bxo 0.0.9 โ 0.0.10-dev.2
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/example/websocket-example.ts +91 -59
- package/package.json +1 -1
- package/src/index.ts +25 -14
- package/test-enhanced-websocket.js +0 -68
|
@@ -127,101 +127,127 @@ async function main() {
|
|
|
127
127
|
`, 200);
|
|
128
128
|
});
|
|
129
129
|
|
|
130
|
-
// WebSocket route with enhanced client identification
|
|
130
|
+
// WebSocket route with enhanced client identification and typed interface
|
|
131
131
|
app.ws("/ws", {
|
|
132
132
|
open(ws) {
|
|
133
|
-
const
|
|
133
|
+
const data = ws.data; // Now fully typed with WebSocketData interface
|
|
134
134
|
console.log("๐ WebSocket connection opened:");
|
|
135
|
-
console.log(` ๐ Client ID: ${
|
|
136
|
-
console.log(` ๐ Connection ID: ${
|
|
137
|
-
console.log(` ๐ Client IP: ${
|
|
138
|
-
console.log(` ๐ฅ๏ธ User Agent: ${
|
|
139
|
-
console.log(` ๐ฏ Origin: ${
|
|
140
|
-
console.log(` ๐ Host: ${
|
|
141
|
-
console.log(` ๐ Path: ${
|
|
142
|
-
console.log(` ๐ช Cookies:`,
|
|
143
|
-
console.log(` ๐ Search Params:`,
|
|
144
|
-
console.log(` ๐ Authorization:`,
|
|
145
|
-
|
|
146
|
-
//
|
|
147
|
-
|
|
135
|
+
console.log(` ๐ Client ID: ${data.id}`);
|
|
136
|
+
console.log(` ๐ Connection ID: ${data.connectionId}`);
|
|
137
|
+
console.log(` ๐ Client IP: ${data.ip}`);
|
|
138
|
+
console.log(` ๐ฅ๏ธ User Agent: ${data.userAgent}`);
|
|
139
|
+
console.log(` ๐ฏ Origin: ${data.origin}`);
|
|
140
|
+
console.log(` ๐ Host: ${data.host}`);
|
|
141
|
+
console.log(` ๐ Path: ${data.path}`);
|
|
142
|
+
console.log(` ๐ช Cookies:`, data.cookies);
|
|
143
|
+
console.log(` ๐ Search Params:`, data.searchParams);
|
|
144
|
+
console.log(` ๐ Authorization:`, data.authorization || 'None');
|
|
145
|
+
|
|
146
|
+
// Use direct property access
|
|
147
|
+
console.log(` ๐ช Session Cookie:`, data.cookies.sessionId);
|
|
148
|
+
console.log(` ๐ Room Param:`, data.searchParams.room);
|
|
149
|
+
console.log(` ๐ค Username:`, data.searchParams.user || data.searchParams.username);
|
|
150
|
+
console.log(` ๐ Room:`, data.searchParams.room);
|
|
151
|
+
console.log(` ๐ Has Auth:`, !!(data.authorization || data.searchParams.token || data.searchParams.auth));
|
|
152
|
+
console.log(` ๐ Auth Type:`, data.authorization ? (data.authorization.toLowerCase().startsWith('bearer ') ? 'bearer' : 'basic') : 'none');
|
|
153
|
+
console.log(` ๐ซ Token:`, data.searchParams.token || data.searchParams.auth);
|
|
154
|
+
|
|
155
|
+
// Check for authentication using direct property access
|
|
156
|
+
if (data.authorization || data.searchParams.token || data.searchParams.auth) {
|
|
148
157
|
console.log(` โ
Authenticated user detected`);
|
|
149
|
-
ws.send(`Welcome authenticated user! Your WebSocket ID is: ${
|
|
150
|
-
} else if (clientInfo.searchParams.token || clientInfo.searchParams.auth) {
|
|
151
|
-
console.log(` ๐ Token-based auth detected`);
|
|
152
|
-
ws.send(`Welcome! Token detected. Your WebSocket ID is: ${clientInfo.id}`);
|
|
158
|
+
ws.send(`Welcome authenticated user! Your WebSocket ID is: ${data.id}`);
|
|
153
159
|
} else {
|
|
154
|
-
ws.send(`Welcome! Your WebSocket ID is: ${
|
|
160
|
+
ws.send(`Welcome! Your WebSocket ID is: ${data.id}`);
|
|
155
161
|
}
|
|
156
162
|
},
|
|
157
163
|
|
|
158
164
|
message(ws, message) {
|
|
159
|
-
const
|
|
160
|
-
console.log(`๐ฌ Message from ${
|
|
161
|
-
console.log(` ๐ช Client cookies:`,
|
|
162
|
-
console.log(` ๐ Search params:`,
|
|
163
|
-
console.log(` ๐ Auth:`,
|
|
165
|
+
const data = ws.data; // Fully typed WebSocketData
|
|
166
|
+
console.log(`๐ฌ Message from ${data.id} (${data.ip}):`, message);
|
|
167
|
+
console.log(` ๐ช Client cookies:`, data.cookies);
|
|
168
|
+
console.log(` ๐ Search params:`, data.searchParams);
|
|
169
|
+
console.log(` ๐ Auth:`, data.authorization || 'None');
|
|
170
|
+
|
|
171
|
+
// Use direct property access
|
|
172
|
+
const username = data.searchParams.user || data.searchParams.username || 'Anonymous';
|
|
173
|
+
const room = data.searchParams.room;
|
|
174
|
+
const sessionId = data.cookies.sessionId;
|
|
175
|
+
|
|
176
|
+
console.log(` ๐ค Username: ${username}`);
|
|
177
|
+
console.log(` ๐ Room: ${room || 'None'}`);
|
|
178
|
+
console.log(` ๐ช Session: ${sessionId || 'None'}`);
|
|
164
179
|
|
|
165
180
|
// Echo the message back with client ID and context
|
|
166
|
-
let response = `[${
|
|
181
|
+
let response = `[${data.id}] Echo: ${message}`;
|
|
167
182
|
|
|
168
|
-
// Add context
|
|
169
|
-
if (
|
|
170
|
-
response += ` (Room: ${
|
|
183
|
+
// Add context using direct property access
|
|
184
|
+
if (room) {
|
|
185
|
+
response += ` (Room: ${room})`;
|
|
171
186
|
}
|
|
172
|
-
if (
|
|
173
|
-
response += ` (User: ${
|
|
187
|
+
if (username && username !== 'Anonymous') {
|
|
188
|
+
response += ` (User: ${username})`;
|
|
174
189
|
}
|
|
175
190
|
|
|
176
191
|
ws.send(response);
|
|
177
192
|
},
|
|
178
193
|
|
|
179
194
|
close(ws, code, reason) {
|
|
180
|
-
const
|
|
181
|
-
console.log(`โ WebSocket connection closed for ${
|
|
195
|
+
const data = ws.data;
|
|
196
|
+
console.log(`โ WebSocket connection closed for ${data.id}: ${code} ${reason}`);
|
|
182
197
|
},
|
|
183
198
|
|
|
184
199
|
ping(ws, data) {
|
|
185
|
-
const
|
|
186
|
-
console.log(`๐ Ping received from ${
|
|
200
|
+
const wsData = ws.data;
|
|
201
|
+
console.log(`๐ Ping received from ${wsData.id}:`, data);
|
|
187
202
|
},
|
|
188
203
|
|
|
189
204
|
pong(ws, data) {
|
|
190
|
-
const
|
|
191
|
-
console.log(`๐ Pong received from ${
|
|
205
|
+
const wsData = ws.data;
|
|
206
|
+
console.log(`๐ Pong received from ${wsData.id}:`, data);
|
|
192
207
|
}
|
|
193
208
|
});
|
|
194
209
|
|
|
195
|
-
// Chat room WebSocket with client identification
|
|
210
|
+
// Chat room WebSocket with typed client identification
|
|
196
211
|
app.ws("/chat/:room", {
|
|
197
212
|
open(ws) {
|
|
198
|
-
const
|
|
199
|
-
const room =
|
|
213
|
+
const data = ws.data; // Fully typed WebSocketData
|
|
214
|
+
const room = data.path.split('/').pop() || 'unknown';
|
|
200
215
|
console.log(`๐ Chat room connection opened for room: ${room}`);
|
|
201
|
-
console.log(` ๐ Client: ${
|
|
202
|
-
console.log(` ๐ช Cookies:`,
|
|
203
|
-
console.log(` ๐ Search Params:`,
|
|
204
|
-
console.log(` ๐ Authorization:`,
|
|
205
|
-
|
|
206
|
-
//
|
|
207
|
-
const username =
|
|
208
|
-
|
|
216
|
+
console.log(` ๐ Client: ${data.id} (${data.ip})`);
|
|
217
|
+
console.log(` ๐ช Cookies:`, data.cookies);
|
|
218
|
+
console.log(` ๐ Search Params:`, data.searchParams);
|
|
219
|
+
console.log(` ๐ Authorization:`, data.authorization || 'None');
|
|
220
|
+
|
|
221
|
+
// Use direct property access
|
|
222
|
+
const username = data.searchParams.user || data.searchParams.username || 'Anonymous';
|
|
223
|
+
const sessionId = data.cookies.sessionId;
|
|
224
|
+
const hasAuth = !!(data.authorization || data.searchParams.token || data.searchParams.auth);
|
|
225
|
+
|
|
226
|
+
console.log(` ๐ค Username: ${username}`);
|
|
227
|
+
console.log(` ๐ช Session: ${sessionId || 'None'}`);
|
|
228
|
+
console.log(` ๐ Authenticated: ${hasAuth}`);
|
|
229
|
+
|
|
230
|
+
ws.send(`Welcome to chat room: ${room}! Your ID is: ${data.id}, Username: ${username}`);
|
|
209
231
|
},
|
|
210
232
|
|
|
211
233
|
message(ws, message) {
|
|
212
|
-
const
|
|
213
|
-
const room =
|
|
214
|
-
const username =
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
console.log(
|
|
218
|
-
|
|
234
|
+
const data = ws.data; // Fully typed WebSocketData
|
|
235
|
+
const room = data.path.split('/').pop() || 'unknown';
|
|
236
|
+
const username = data.searchParams.user || data.searchParams.username || 'Anonymous';
|
|
237
|
+
const sessionId = data.cookies.sessionId;
|
|
238
|
+
|
|
239
|
+
console.log(`๐ฌ Message in room ${room} from ${data.id} (${username}):`, message);
|
|
240
|
+
console.log(` ๐ช Client cookies:`, data.cookies);
|
|
241
|
+
console.log(` ๐ Search params:`, data.searchParams);
|
|
242
|
+
console.log(` ๐ช Session: ${sessionId || 'None'}`);
|
|
243
|
+
|
|
244
|
+
ws.send(`[${room}] [${username}] [${data.id}] Echo: ${message}`);
|
|
219
245
|
},
|
|
220
246
|
|
|
221
247
|
close(ws, code, reason) {
|
|
222
|
-
const
|
|
223
|
-
const room =
|
|
224
|
-
console.log(`โ Chat room connection closed for room ${room} (${
|
|
248
|
+
const data = ws.data;
|
|
249
|
+
const room = data.path.split('/').pop() || 'unknown';
|
|
250
|
+
console.log(`โ Chat room connection closed for room ${room} (${data.id}): ${code} ${reason}`);
|
|
225
251
|
}
|
|
226
252
|
});
|
|
227
253
|
|
|
@@ -230,12 +256,18 @@ async function main() {
|
|
|
230
256
|
console.log(`๐ WebSocket available at ws://localhost:${app.server?.port}/ws`);
|
|
231
257
|
console.log(`๐ฌ Chat WebSocket available at ws://localhost:${app.server?.port}/chat/:room`);
|
|
232
258
|
console.log(`\n๐ Features demonstrated:`);
|
|
233
|
-
console.log(` โข ws.id - Short, unique client identifier`);
|
|
259
|
+
console.log(` โข ws.data.id - Short, unique client identifier`);
|
|
234
260
|
console.log(` โข ws.data.connectionId - Detailed connection ID`);
|
|
235
261
|
console.log(` โข ws.data.cookies - Parsed cookies from handshake`);
|
|
236
262
|
console.log(` โข ws.data.searchParams - Query parameters from URL`);
|
|
237
263
|
console.log(` โข ws.data.authorization - Authorization header`);
|
|
238
264
|
console.log(` โข Client IP, User Agent, Origin tracking`);
|
|
265
|
+
console.log(`\n๐ง Direct Property Access:`);
|
|
266
|
+
console.log(` โข ws.data.cookies.name - Get specific cookie`);
|
|
267
|
+
console.log(` โข ws.data.searchParams.name - Get specific search param`);
|
|
268
|
+
console.log(` โข ws.data.authorization - Check authorization header`);
|
|
269
|
+
console.log(` โข ws.data.id - Short client identifier`);
|
|
270
|
+
console.log(` โข ws.data.connectionId - Detailed connection ID`);
|
|
239
271
|
console.log(`\n๐งช Test URLs:`);
|
|
240
272
|
console.log(` โข Basic: ws://localhost:${app.server?.port}/ws`);
|
|
241
273
|
console.log(` โข With params: ws://localhost:${app.server?.port}/ws?room=test&user=john&theme=dark`);
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -106,8 +106,14 @@ export type WebSocketClientInfo = {
|
|
|
106
106
|
authorization?: string; // Authorization header (Bearer token, Basic auth, etc.)
|
|
107
107
|
};
|
|
108
108
|
|
|
109
|
+
// WebSocket data interface - this is what you get when accessing ws.data
|
|
110
|
+
export interface WebSocketData extends WebSocketClientInfo {
|
|
111
|
+
// Simple interface with just the data properties
|
|
112
|
+
// No convenience methods - use direct property access
|
|
113
|
+
}
|
|
114
|
+
|
|
109
115
|
// WebSocket handler types
|
|
110
|
-
export type WebSocketHandler<T =
|
|
116
|
+
export type WebSocketHandler<T = WebSocketData> = {
|
|
111
117
|
message?(ws: Bun.ServerWebSocket<T>, message: string | Buffer): void | Promise<void>;
|
|
112
118
|
open?(ws: Bun.ServerWebSocket<T>): void | Promise<void>;
|
|
113
119
|
close?(ws: Bun.ServerWebSocket<T>, code: number, reason: string): void | Promise<void>;
|
|
@@ -450,22 +456,22 @@ export default class BXO {
|
|
|
450
456
|
|
|
451
457
|
// Create WebSocket configuration if we have WebSocket routes
|
|
452
458
|
const websocketConfig = hasWebSocketRoutes ? {
|
|
453
|
-
message: (ws: Bun.ServerWebSocket<
|
|
459
|
+
message: (ws: Bun.ServerWebSocket<WebSocketData>, message: string | Buffer) => {
|
|
454
460
|
this.handleWebSocketMessage(ws, message);
|
|
455
461
|
},
|
|
456
|
-
open: (ws: Bun.ServerWebSocket<
|
|
462
|
+
open: (ws: Bun.ServerWebSocket<WebSocketData>) => {
|
|
457
463
|
this.handleWebSocketOpen(ws);
|
|
458
464
|
},
|
|
459
|
-
close: (ws: Bun.ServerWebSocket<
|
|
465
|
+
close: (ws: Bun.ServerWebSocket<WebSocketData>, code: number, reason: string) => {
|
|
460
466
|
this.handleWebSocketClose(ws, code, reason);
|
|
461
467
|
},
|
|
462
|
-
drain: (ws: Bun.ServerWebSocket<
|
|
468
|
+
drain: (ws: Bun.ServerWebSocket<WebSocketData>) => {
|
|
463
469
|
this.handleWebSocketDrain(ws);
|
|
464
470
|
},
|
|
465
|
-
ping: (ws: Bun.ServerWebSocket<
|
|
471
|
+
ping: (ws: Bun.ServerWebSocket<WebSocketData>, data: Buffer) => {
|
|
466
472
|
this.handleWebSocketPing(ws, data);
|
|
467
473
|
},
|
|
468
|
-
pong: (ws: Bun.ServerWebSocket<
|
|
474
|
+
pong: (ws: Bun.ServerWebSocket<WebSocketData>, data: Buffer) => {
|
|
469
475
|
this.handleWebSocketPong(ws, data);
|
|
470
476
|
}
|
|
471
477
|
} : undefined;
|
|
@@ -502,7 +508,7 @@ export default class BXO {
|
|
|
502
508
|
}
|
|
503
509
|
}
|
|
504
510
|
|
|
505
|
-
const
|
|
511
|
+
const baseClientInfo = {
|
|
506
512
|
id: shortId, // Short, easy-to-use ID
|
|
507
513
|
path: url.pathname,
|
|
508
514
|
ip: req.headers.get("x-forwarded-for") ||
|
|
@@ -516,6 +522,11 @@ export default class BXO {
|
|
|
516
522
|
searchParams: searchParams, // Query parameters from URL
|
|
517
523
|
authorization: authHeader || undefined // Authorization header
|
|
518
524
|
};
|
|
525
|
+
|
|
526
|
+
// Create simple WebSocket data object
|
|
527
|
+
const clientInfo: WebSocketData = {
|
|
528
|
+
...baseClientInfo
|
|
529
|
+
};
|
|
519
530
|
|
|
520
531
|
const success = server.upgrade(req, {
|
|
521
532
|
data: clientInfo
|
|
@@ -583,7 +594,7 @@ export default class BXO {
|
|
|
583
594
|
return null;
|
|
584
595
|
}
|
|
585
596
|
|
|
586
|
-
private handleWebSocketMessage(ws: Bun.ServerWebSocket<
|
|
597
|
+
private handleWebSocketMessage(ws: Bun.ServerWebSocket<WebSocketData>, message: string | Buffer): void {
|
|
587
598
|
const route = this.findWebSocketRoute(ws.data?.path || "");
|
|
588
599
|
if (route?.websocketHandler?.message) {
|
|
589
600
|
try {
|
|
@@ -594,7 +605,7 @@ export default class BXO {
|
|
|
594
605
|
}
|
|
595
606
|
}
|
|
596
607
|
|
|
597
|
-
private handleWebSocketOpen(ws: Bun.ServerWebSocket<
|
|
608
|
+
private handleWebSocketOpen(ws: Bun.ServerWebSocket<WebSocketData>): void {
|
|
598
609
|
const route = this.findWebSocketRoute(ws.data?.path || "");
|
|
599
610
|
if (route?.websocketHandler?.open) {
|
|
600
611
|
try {
|
|
@@ -605,7 +616,7 @@ export default class BXO {
|
|
|
605
616
|
}
|
|
606
617
|
}
|
|
607
618
|
|
|
608
|
-
private handleWebSocketClose(ws: Bun.ServerWebSocket<
|
|
619
|
+
private handleWebSocketClose(ws: Bun.ServerWebSocket<WebSocketData>, code: number, reason: string): void {
|
|
609
620
|
const route = this.findWebSocketRoute(ws.data?.path || "");
|
|
610
621
|
if (route?.websocketHandler?.close) {
|
|
611
622
|
try {
|
|
@@ -616,7 +627,7 @@ export default class BXO {
|
|
|
616
627
|
}
|
|
617
628
|
}
|
|
618
629
|
|
|
619
|
-
private handleWebSocketDrain(ws: Bun.ServerWebSocket<
|
|
630
|
+
private handleWebSocketDrain(ws: Bun.ServerWebSocket<WebSocketData>): void {
|
|
620
631
|
const route = this.findWebSocketRoute(ws.data?.path || "");
|
|
621
632
|
if (route?.websocketHandler?.drain) {
|
|
622
633
|
try {
|
|
@@ -627,7 +638,7 @@ export default class BXO {
|
|
|
627
638
|
}
|
|
628
639
|
}
|
|
629
640
|
|
|
630
|
-
private handleWebSocketPing(ws: Bun.ServerWebSocket<
|
|
641
|
+
private handleWebSocketPing(ws: Bun.ServerWebSocket<WebSocketData>, data: Buffer): void {
|
|
631
642
|
const route = this.findWebSocketRoute(ws.data?.path || "");
|
|
632
643
|
if (route?.websocketHandler?.ping) {
|
|
633
644
|
try {
|
|
@@ -638,7 +649,7 @@ export default class BXO {
|
|
|
638
649
|
}
|
|
639
650
|
}
|
|
640
651
|
|
|
641
|
-
private handleWebSocketPong(ws: Bun.ServerWebSocket<
|
|
652
|
+
private handleWebSocketPong(ws: Bun.ServerWebSocket<WebSocketData>, data: Buffer): void {
|
|
642
653
|
const route = this.findWebSocketRoute(ws.data?.path || "");
|
|
643
654
|
if (route?.websocketHandler?.pong) {
|
|
644
655
|
try {
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
// Comprehensive test for enhanced WebSocket client identification
|
|
2
|
-
console.log('๐งช Testing Enhanced WebSocket Client Identification...\n');
|
|
3
|
-
|
|
4
|
-
// Test 1: Basic WebSocket connection
|
|
5
|
-
console.log('1. Testing basic WebSocket connection');
|
|
6
|
-
const ws1 = new WebSocket('ws://localhost:3000/ws');
|
|
7
|
-
|
|
8
|
-
ws1.onopen = function() {
|
|
9
|
-
console.log('โ Connected to basic WebSocket');
|
|
10
|
-
ws1.send('Hello from basic connection!');
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
ws1.onmessage = function(event) {
|
|
14
|
-
console.log('โ Received:', event.data);
|
|
15
|
-
ws1.close();
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
ws1.onclose = function() {
|
|
19
|
-
console.log('โ Basic connection closed\n');
|
|
20
|
-
|
|
21
|
-
// Test 2: WebSocket with search parameters
|
|
22
|
-
console.log('2. Testing WebSocket with search parameters');
|
|
23
|
-
const ws2 = new WebSocket('ws://localhost:3000/ws?room=test&user=john&theme=dark&token=abc123');
|
|
24
|
-
|
|
25
|
-
ws2.onopen = function() {
|
|
26
|
-
console.log('โ Connected with search params');
|
|
27
|
-
ws2.send('Hello from connection with params!');
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
ws2.onmessage = function(event) {
|
|
31
|
-
console.log('โ Received:', event.data);
|
|
32
|
-
ws2.close();
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
ws2.onclose = function() {
|
|
36
|
-
console.log('โ Search params connection closed\n');
|
|
37
|
-
|
|
38
|
-
// Test 3: Chat room with search parameters
|
|
39
|
-
console.log('3. Testing chat room with search parameters');
|
|
40
|
-
const ws3 = new WebSocket('ws://localhost:3000/chat/general?user=alice&theme=light&role=moderator');
|
|
41
|
-
|
|
42
|
-
ws3.onopen = function() {
|
|
43
|
-
console.log('โ Connected to chat room with params');
|
|
44
|
-
ws3.send('Hello from chat room!');
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
ws3.onmessage = function(event) {
|
|
48
|
-
console.log('โ Received:', event.data);
|
|
49
|
-
ws3.close();
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
ws3.onclose = function() {
|
|
53
|
-
console.log('โ Chat room connection closed');
|
|
54
|
-
console.log('\nโ
All tests completed! Check the server logs to see:');
|
|
55
|
-
console.log(' โข ws.id - Short client identifier');
|
|
56
|
-
console.log(' โข ws.data.searchParams - Query parameters');
|
|
57
|
-
console.log(' โข ws.data.cookies - Parsed cookies');
|
|
58
|
-
console.log(' โข ws.data.authorization - Auth header');
|
|
59
|
-
console.log(' โข Client IP and other identification info');
|
|
60
|
-
process.exit(0);
|
|
61
|
-
};
|
|
62
|
-
};
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
ws1.onerror = function(error) {
|
|
66
|
-
console.error('โ WebSocket error:', error);
|
|
67
|
-
process.exit(1);
|
|
68
|
-
};
|