bxo 0.0.5-dev.76 → 0.0.5-dev.77
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 +72 -0
- package/example/websocket-example.ts +132 -0
- package/package.json +1 -1
- package/src/index.ts +170 -7
package/README.md
CHANGED
|
@@ -5,6 +5,7 @@ A fast, lightweight web framework for Bun with built-in Zod validation and lifec
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
7
7
|
- **Type-safe routing** with Zod schema validation
|
|
8
|
+
- **WebSocket support** with clean API
|
|
8
9
|
- **Lifecycle hooks** for middleware and plugins
|
|
9
10
|
- **Plugin system** for extending functionality
|
|
10
11
|
- **Built-in CORS support** via plugin
|
|
@@ -33,6 +34,76 @@ app.get("/", (ctx) => ctx.json({ message: "Hello World!" }));
|
|
|
33
34
|
app.start();
|
|
34
35
|
```
|
|
35
36
|
|
|
37
|
+
## WebSocket Support
|
|
38
|
+
|
|
39
|
+
BXO provides built-in WebSocket support with a clean, intuitive API:
|
|
40
|
+
|
|
41
|
+
```typescript
|
|
42
|
+
import BXO from "./src";
|
|
43
|
+
|
|
44
|
+
const app = new BXO();
|
|
45
|
+
|
|
46
|
+
// WebSocket route
|
|
47
|
+
app.ws("/ws", {
|
|
48
|
+
open(ws) {
|
|
49
|
+
console.log("WebSocket connection opened");
|
|
50
|
+
ws.send("Welcome to BXO WebSocket!");
|
|
51
|
+
},
|
|
52
|
+
|
|
53
|
+
message(ws, message) {
|
|
54
|
+
console.log("Received message:", message);
|
|
55
|
+
// Echo the message back
|
|
56
|
+
ws.send(`Echo: ${message}`);
|
|
57
|
+
},
|
|
58
|
+
|
|
59
|
+
close(ws, code, reason) {
|
|
60
|
+
console.log(`WebSocket connection closed: ${code} ${reason}`);
|
|
61
|
+
},
|
|
62
|
+
|
|
63
|
+
ping(ws, data) {
|
|
64
|
+
console.log("Ping received:", data);
|
|
65
|
+
},
|
|
66
|
+
|
|
67
|
+
pong(ws, data) {
|
|
68
|
+
console.log("Pong received:", data);
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
// WebSocket with path parameters
|
|
73
|
+
app.ws("/chat/:room", {
|
|
74
|
+
open(ws) {
|
|
75
|
+
const room = ws.data?.room || 'unknown';
|
|
76
|
+
console.log(`WebSocket connection opened for room: ${room}`);
|
|
77
|
+
ws.send(`Welcome to chat room: ${room}`);
|
|
78
|
+
},
|
|
79
|
+
|
|
80
|
+
message(ws, message) {
|
|
81
|
+
const room = ws.data?.room || 'unknown';
|
|
82
|
+
console.log(`Message in room ${room}:`, message);
|
|
83
|
+
ws.send(`[${room}] Echo: ${message}`);
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
app.start();
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### WebSocket Handler Events
|
|
91
|
+
|
|
92
|
+
- `open(ws)` - Called when a WebSocket connection is established
|
|
93
|
+
- `message(ws, message)` - Called when a message is received
|
|
94
|
+
- `close(ws, code, reason)` - Called when the connection is closed
|
|
95
|
+
- `drain(ws)` - Called when the WebSocket is ready for more data
|
|
96
|
+
- `ping(ws, data)` - Called when a ping is received
|
|
97
|
+
- `pong(ws, data)` - Called when a pong is received
|
|
98
|
+
|
|
99
|
+
### WebSocket Features
|
|
100
|
+
|
|
101
|
+
- **Path parameters** - Support for dynamic routes like `/chat/:room`
|
|
102
|
+
- **Automatic upgrade** - HTTP requests to WebSocket routes are automatically upgraded
|
|
103
|
+
- **Type safety** - Full TypeScript support with proper typing
|
|
104
|
+
- **Error handling** - Built-in error handling for WebSocket events
|
|
105
|
+
- **Data attachment** - Access to path information via `ws.data`
|
|
106
|
+
|
|
36
107
|
## Lifecycle Hooks
|
|
37
108
|
|
|
38
109
|
BXO provides powerful lifecycle hooks that allow you to intercept and modify requests and responses at different stages:
|
|
@@ -220,6 +291,7 @@ Check out the `example/` directory for more usage examples:
|
|
|
220
291
|
|
|
221
292
|
- `cors-example.ts` - Demonstrates CORS plugin and lifecycle hooks
|
|
222
293
|
- `openapi-example.ts` - Demonstrates OpenAPI plugin with tags and security
|
|
294
|
+
- `websocket-example.ts` - Demonstrates WebSocket functionality with interactive HTML client
|
|
223
295
|
- `index.ts` - Basic routing example
|
|
224
296
|
|
|
225
297
|
This project was created using `bun init` in bun v1.2.3. [Bun](https://bun.sh) is a fast all-in-one JavaScript runtime.
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import BXO from "../src";
|
|
2
|
+
|
|
3
|
+
async function main() {
|
|
4
|
+
const app = new BXO({ serve: { port: 3000 } });
|
|
5
|
+
|
|
6
|
+
// HTTP routes
|
|
7
|
+
app.get("/", (ctx) => {
|
|
8
|
+
return ctx.text(`
|
|
9
|
+
<!DOCTYPE html>
|
|
10
|
+
<html>
|
|
11
|
+
<head>
|
|
12
|
+
<title>BXO WebSocket Example</title>
|
|
13
|
+
</head>
|
|
14
|
+
<body>
|
|
15
|
+
<h1>BXO WebSocket Example</h1>
|
|
16
|
+
<div id="messages"></div>
|
|
17
|
+
<input type="text" id="messageInput" placeholder="Type a message...">
|
|
18
|
+
<button onclick="sendMessage()">Send</button>
|
|
19
|
+
<button onclick="connect()">Connect</button>
|
|
20
|
+
<button onclick="disconnect()">Disconnect</button>
|
|
21
|
+
|
|
22
|
+
<script>
|
|
23
|
+
let ws = null;
|
|
24
|
+
|
|
25
|
+
function connect() {
|
|
26
|
+
ws = new WebSocket('ws://localhost:3000/ws');
|
|
27
|
+
|
|
28
|
+
ws.onopen = function() {
|
|
29
|
+
addMessage('Connected to WebSocket');
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
ws.onmessage = function(event) {
|
|
33
|
+
addMessage('Received: ' + event.data);
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
ws.onclose = function() {
|
|
37
|
+
addMessage('Disconnected from WebSocket');
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
ws.onerror = function(error) {
|
|
41
|
+
addMessage('Error: ' + error);
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function disconnect() {
|
|
46
|
+
if (ws) {
|
|
47
|
+
ws.close();
|
|
48
|
+
ws = null;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function sendMessage() {
|
|
53
|
+
const input = document.getElementById('messageInput');
|
|
54
|
+
if (ws && input.value) {
|
|
55
|
+
ws.send(input.value);
|
|
56
|
+
addMessage('Sent: ' + input.value);
|
|
57
|
+
input.value = '';
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function addMessage(message) {
|
|
62
|
+
const messages = document.getElementById('messages');
|
|
63
|
+
const div = document.createElement('div');
|
|
64
|
+
div.textContent = new Date().toLocaleTimeString() + ': ' + message;
|
|
65
|
+
messages.appendChild(div);
|
|
66
|
+
messages.scrollTop = messages.scrollHeight;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Allow Enter key to send message
|
|
70
|
+
document.getElementById('messageInput').addEventListener('keypress', function(e) {
|
|
71
|
+
if (e.key === 'Enter') {
|
|
72
|
+
sendMessage();
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
</script>
|
|
76
|
+
`, 200, {
|
|
77
|
+
"Content-Type": "text/html"
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
// WebSocket route
|
|
82
|
+
app.ws("/ws", {
|
|
83
|
+
open(ws) {
|
|
84
|
+
console.log("WebSocket connection opened");
|
|
85
|
+
ws.send("Welcome to BXO WebSocket!");
|
|
86
|
+
},
|
|
87
|
+
|
|
88
|
+
message(ws, message) {
|
|
89
|
+
console.log("Received message:", message);
|
|
90
|
+
// Echo the message back
|
|
91
|
+
ws.send(`Echo: ${message}`);
|
|
92
|
+
},
|
|
93
|
+
|
|
94
|
+
close(ws, code, reason) {
|
|
95
|
+
console.log(`WebSocket connection closed: ${code} ${reason}`);
|
|
96
|
+
},
|
|
97
|
+
|
|
98
|
+
ping(ws, data) {
|
|
99
|
+
console.log("Ping received:", data);
|
|
100
|
+
},
|
|
101
|
+
|
|
102
|
+
pong(ws, data) {
|
|
103
|
+
console.log("Pong received:", data);
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
// Another WebSocket route with parameters
|
|
108
|
+
app.ws("/chat/:room", {
|
|
109
|
+
open(ws) {
|
|
110
|
+
console.log(`WebSocket connection opened for room: ${ws.data?.room || 'unknown'}`);
|
|
111
|
+
ws.send(`Welcome to chat room: ${ws.data?.room || 'unknown'}`);
|
|
112
|
+
},
|
|
113
|
+
|
|
114
|
+
message(ws, message) {
|
|
115
|
+
const room = ws.data?.room || 'unknown';
|
|
116
|
+
console.log(`Message in room ${room}:`, message);
|
|
117
|
+
ws.send(`[${room}] Echo: ${message}`);
|
|
118
|
+
},
|
|
119
|
+
|
|
120
|
+
close(ws, code, reason) {
|
|
121
|
+
const room = ws.data?.room || 'unknown';
|
|
122
|
+
console.log(`WebSocket connection closed for room ${room}: ${code} ${reason}`);
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
app.start();
|
|
127
|
+
console.log(`Server is running on http://localhost:${app.server?.port}`);
|
|
128
|
+
console.log(`WebSocket available at ws://localhost:${app.server?.port}/ws`);
|
|
129
|
+
console.log(`Chat WebSocket available at ws://localhost:${app.server?.port}/chat/:room`);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
main().catch(console.error);
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -7,7 +7,8 @@ type Method =
|
|
|
7
7
|
| "PATCH"
|
|
8
8
|
| "DELETE"
|
|
9
9
|
| "OPTIONS"
|
|
10
|
-
| "HEAD"
|
|
10
|
+
| "HEAD"
|
|
11
|
+
| "WS";
|
|
11
12
|
|
|
12
13
|
type PickWildcardName<S extends string> = S extends "" ? "wildcard" : S;
|
|
13
14
|
|
|
@@ -89,6 +90,16 @@ type Handler<P extends string, S extends RouteSchema | undefined = undefined> =
|
|
|
89
90
|
app: BXO
|
|
90
91
|
) => Response | string | Promise<Response | string>;
|
|
91
92
|
|
|
93
|
+
// WebSocket handler types
|
|
94
|
+
export type WebSocketHandler<T = any> = {
|
|
95
|
+
message?(ws: Bun.ServerWebSocket<T>, message: string | Buffer): void | Promise<void>;
|
|
96
|
+
open?(ws: Bun.ServerWebSocket<T>): void | Promise<void>;
|
|
97
|
+
close?(ws: Bun.ServerWebSocket<T>, code: number, reason: string): void | Promise<void>;
|
|
98
|
+
drain?(ws: Bun.ServerWebSocket<T>): void | Promise<void>;
|
|
99
|
+
ping?(ws: Bun.ServerWebSocket<T>, data: Buffer): void | Promise<void>;
|
|
100
|
+
pong?(ws: Bun.ServerWebSocket<T>, data: Buffer): void | Promise<void>;
|
|
101
|
+
};
|
|
102
|
+
|
|
92
103
|
type InternalRoute = {
|
|
93
104
|
method: Method | "DEFAULT";
|
|
94
105
|
path: string;
|
|
@@ -96,6 +107,7 @@ type InternalRoute = {
|
|
|
96
107
|
paramNames: string[];
|
|
97
108
|
schema?: RouteSchema;
|
|
98
109
|
handler: AnyHandler;
|
|
110
|
+
websocketHandler?: WebSocketHandler;
|
|
99
111
|
};
|
|
100
112
|
|
|
101
113
|
type ServeOptions = Partial<Parameters<typeof Bun.serve>[0]>;
|
|
@@ -305,6 +317,10 @@ export default class BXO {
|
|
|
305
317
|
return this.add("DELETE", path, handler as AnyHandler, schema as RouteSchema | undefined);
|
|
306
318
|
}
|
|
307
319
|
|
|
320
|
+
ws<P extends string>(path: P, handler: WebSocketHandler): this {
|
|
321
|
+
return this.addWebSocket("WS", path, handler);
|
|
322
|
+
}
|
|
323
|
+
|
|
308
324
|
// default can accept a handler OR static content (including Bun HTML bundle)
|
|
309
325
|
default<P extends string>(path: P, handler: Handler<P, undefined>): this;
|
|
310
326
|
default<P extends string, S extends RouteSchema>(path: P, handler: (req: Request) => Response, schema: S): this;
|
|
@@ -314,6 +330,9 @@ export default class BXO {
|
|
|
314
330
|
}
|
|
315
331
|
|
|
316
332
|
start(): void {
|
|
333
|
+
// Check if we have any WebSocket routes
|
|
334
|
+
const hasWebSocketRoutes = this.routes.some(r => r.method === "WS");
|
|
335
|
+
|
|
317
336
|
// Build a basic routes map for Bun's native routes (exact paths only)
|
|
318
337
|
const nativeRoutes: Record<string, Record<string, (req: Request) => Promise<Response> | Response>> = {};
|
|
319
338
|
|
|
@@ -322,6 +341,9 @@ export default class BXO {
|
|
|
322
341
|
case "DEFAULT":
|
|
323
342
|
nativeRoutes[r.path] = r.handler as any;
|
|
324
343
|
break;
|
|
344
|
+
case "WS":
|
|
345
|
+
// Skip WebSocket routes in native routes - they'll be handled in websocket config
|
|
346
|
+
break;
|
|
325
347
|
default:
|
|
326
348
|
nativeRoutes[r.path] ||= {} as Record<string, (req: Request) => Promise<Response> | Response>;
|
|
327
349
|
nativeRoutes[r.path][r.method] = (req: Request) => this.dispatch(r, req);
|
|
@@ -331,13 +353,61 @@ export default class BXO {
|
|
|
331
353
|
|
|
332
354
|
this.serveOptions.port = this.serveOptions.port === undefined ? 3000 : this.serveOptions.port;
|
|
333
355
|
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
356
|
+
// Create WebSocket configuration if we have WebSocket routes
|
|
357
|
+
const websocketConfig = hasWebSocketRoutes ? {
|
|
358
|
+
message: (ws: Bun.ServerWebSocket<{ path: string }>, message: string | Buffer) => {
|
|
359
|
+
this.handleWebSocketMessage(ws, message);
|
|
360
|
+
},
|
|
361
|
+
open: (ws: Bun.ServerWebSocket<{ path: string }>) => {
|
|
362
|
+
this.handleWebSocketOpen(ws);
|
|
363
|
+
},
|
|
364
|
+
close: (ws: Bun.ServerWebSocket<{ path: string }>, code: number, reason: string) => {
|
|
365
|
+
this.handleWebSocketClose(ws, code, reason);
|
|
366
|
+
},
|
|
367
|
+
drain: (ws: Bun.ServerWebSocket<{ path: string }>) => {
|
|
368
|
+
this.handleWebSocketDrain(ws);
|
|
369
|
+
},
|
|
370
|
+
ping: (ws: Bun.ServerWebSocket<{ path: string }>, data: Buffer) => {
|
|
371
|
+
this.handleWebSocketPing(ws, data);
|
|
372
|
+
},
|
|
373
|
+
pong: (ws: Bun.ServerWebSocket<{ path: string }>, data: Buffer) => {
|
|
374
|
+
this.handleWebSocketPong(ws, data);
|
|
339
375
|
}
|
|
340
|
-
}
|
|
376
|
+
} : undefined;
|
|
377
|
+
|
|
378
|
+
if (hasWebSocketRoutes) {
|
|
379
|
+
this.server = Bun.serve({
|
|
380
|
+
...this.serveOptions,
|
|
381
|
+
routes: nativeRoutes as any,
|
|
382
|
+
websocket: websocketConfig as any,
|
|
383
|
+
fetch: (req: Request, server: Bun.Server) => {
|
|
384
|
+
// Handle WebSocket upgrade requests
|
|
385
|
+
if (req.headers.get("upgrade") === "websocket") {
|
|
386
|
+
const url = new URL(req.url);
|
|
387
|
+
const wsRoute = this.findWebSocketRoute(url.pathname);
|
|
388
|
+
if (wsRoute) {
|
|
389
|
+
const success = server.upgrade(req, {
|
|
390
|
+
data: { path: url.pathname }
|
|
391
|
+
});
|
|
392
|
+
if (success) {
|
|
393
|
+
return; // WebSocket upgrade successful
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
// Handle regular HTTP requests
|
|
399
|
+
return this.dispatchAny(req, nativeRoutes);
|
|
400
|
+
}
|
|
401
|
+
} as any);
|
|
402
|
+
} else {
|
|
403
|
+
this.server = Bun.serve({
|
|
404
|
+
...this.serveOptions,
|
|
405
|
+
routes: nativeRoutes as any,
|
|
406
|
+
fetch: (req: Request) => {
|
|
407
|
+
return this.dispatchAny(req, nativeRoutes);
|
|
408
|
+
}
|
|
409
|
+
});
|
|
410
|
+
}
|
|
341
411
|
}
|
|
342
412
|
|
|
343
413
|
// Lifecycle hook methods
|
|
@@ -361,6 +431,93 @@ export default class BXO {
|
|
|
361
431
|
return this;
|
|
362
432
|
}
|
|
363
433
|
|
|
434
|
+
// WebSocket handler methods
|
|
435
|
+
private findWebSocketRoute(pathname: string): InternalRoute | null {
|
|
436
|
+
for (const route of this.routes) {
|
|
437
|
+
if (route.method === "WS") {
|
|
438
|
+
if (route.matcher === null) {
|
|
439
|
+
// Exact match
|
|
440
|
+
if (route.path === pathname) {
|
|
441
|
+
return route;
|
|
442
|
+
}
|
|
443
|
+
} else {
|
|
444
|
+
// Pattern match
|
|
445
|
+
const match = pathname.match(route.matcher);
|
|
446
|
+
if (match) {
|
|
447
|
+
return route;
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
return null;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
private handleWebSocketMessage(ws: Bun.ServerWebSocket<{ path: string }>, message: string | Buffer): void {
|
|
456
|
+
const route = this.findWebSocketRoute(ws.data?.path || "");
|
|
457
|
+
if (route?.websocketHandler?.message) {
|
|
458
|
+
try {
|
|
459
|
+
(route.websocketHandler as any).message(ws, message);
|
|
460
|
+
} catch (error) {
|
|
461
|
+
console.error("WebSocket message handler error:", error);
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
private handleWebSocketOpen(ws: Bun.ServerWebSocket<{ path: string }>): void {
|
|
467
|
+
const route = this.findWebSocketRoute(ws.data?.path || "");
|
|
468
|
+
if (route?.websocketHandler?.open) {
|
|
469
|
+
try {
|
|
470
|
+
(route.websocketHandler as any).open(ws);
|
|
471
|
+
} catch (error) {
|
|
472
|
+
console.error("WebSocket open handler error:", error);
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
private handleWebSocketClose(ws: Bun.ServerWebSocket<{ path: string }>, code: number, reason: string): void {
|
|
478
|
+
const route = this.findWebSocketRoute(ws.data?.path || "");
|
|
479
|
+
if (route?.websocketHandler?.close) {
|
|
480
|
+
try {
|
|
481
|
+
(route.websocketHandler as any).close(ws, code, reason);
|
|
482
|
+
} catch (error) {
|
|
483
|
+
console.error("WebSocket close handler error:", error);
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
private handleWebSocketDrain(ws: Bun.ServerWebSocket<{ path: string }>): void {
|
|
489
|
+
const route = this.findWebSocketRoute(ws.data?.path || "");
|
|
490
|
+
if (route?.websocketHandler?.drain) {
|
|
491
|
+
try {
|
|
492
|
+
(route.websocketHandler as any).drain(ws);
|
|
493
|
+
} catch (error) {
|
|
494
|
+
console.error("WebSocket drain handler error:", error);
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
private handleWebSocketPing(ws: Bun.ServerWebSocket<{ path: string }>, data: Buffer): void {
|
|
500
|
+
const route = this.findWebSocketRoute(ws.data?.path || "");
|
|
501
|
+
if (route?.websocketHandler?.ping) {
|
|
502
|
+
try {
|
|
503
|
+
(route.websocketHandler as any).ping(ws, data);
|
|
504
|
+
} catch (error) {
|
|
505
|
+
console.error("WebSocket ping handler error:", error);
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
private handleWebSocketPong(ws: Bun.ServerWebSocket<{ path: string }>, data: Buffer): void {
|
|
511
|
+
const route = this.findWebSocketRoute(ws.data?.path || "");
|
|
512
|
+
if (route?.websocketHandler?.pong) {
|
|
513
|
+
try {
|
|
514
|
+
(route.websocketHandler as any).pong(ws, data);
|
|
515
|
+
} catch (error) {
|
|
516
|
+
console.error("WebSocket pong handler error:", error);
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
|
|
364
521
|
// Internal
|
|
365
522
|
private add(method: Method | "DEFAULT", path: string, handler: AnyHandler, schema?: RouteSchema): this {
|
|
366
523
|
const { regex, names } = buildMatcher(path);
|
|
@@ -368,6 +525,12 @@ export default class BXO {
|
|
|
368
525
|
return this;
|
|
369
526
|
}
|
|
370
527
|
|
|
528
|
+
private addWebSocket(method: "WS", path: string, handler: WebSocketHandler): this {
|
|
529
|
+
const { regex, names } = buildMatcher(path);
|
|
530
|
+
this.routes.push({ method, path, handler: () => new Response("WebSocket route", { status: 400 }), matcher: regex, paramNames: names, websocketHandler: handler });
|
|
531
|
+
return this;
|
|
532
|
+
}
|
|
533
|
+
|
|
371
534
|
private async dispatch(route: InternalRoute, req: Request): Promise<Response> {
|
|
372
535
|
// Run beforeRequest hooks
|
|
373
536
|
for (const hook of this.beforeRequestHooks) {
|