next-ws 0.0.0-beta-20250822123253 → 0.0.0-beta-20250823112013
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 +13 -14
- package/dist/cli.cjs +1 -1
- package/dist/server/index.cjs +38 -14
- package/dist/server/index.d.ts +22 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -50,14 +50,14 @@ To set up a WebSocket server with `next-ws`, you need to patch your local Next.j
|
|
|
50
50
|
|
|
51
51
|
## 🚀 Usage
|
|
52
52
|
|
|
53
|
-
Using WebSocket connections in your Next.js app directory is simple with `next-ws`. You can handle WebSocket connections directly in your API routes via exported `
|
|
53
|
+
Using WebSocket connections in your Next.js app directory is simple with `next-ws`. You can handle WebSocket connections directly in your API routes via exported `UPGRADE` functions.
|
|
54
54
|
|
|
55
55
|
```js
|
|
56
|
-
export function
|
|
56
|
+
export function UPGRADE(
|
|
57
57
|
client: import('ws').WebSocket,
|
|
58
|
-
request: import('http').IncomingMessage,
|
|
59
58
|
server: import('ws').WebSocketServer,
|
|
60
|
-
|
|
59
|
+
request: import('next/server').NextRequest,
|
|
60
|
+
context: import('next-ws/server').RouteContext<'/api/ws'>,
|
|
61
61
|
) {
|
|
62
62
|
// ...
|
|
63
63
|
}
|
|
@@ -70,25 +70,24 @@ export function SOCKET(
|
|
|
70
70
|
|
|
71
71
|
### Echo Server
|
|
72
72
|
|
|
73
|
-
This example demonstrates a simple WebSocket echo server that sends back any message it receives. Create a new API route file anywhere in your app directory and export a `
|
|
73
|
+
This example demonstrates a simple WebSocket echo server that sends back any message it receives. Create a new API route file anywhere in your app directory and export a `UPGRADE` function to handle WebSocket connections:
|
|
74
74
|
|
|
75
75
|
```ts
|
|
76
76
|
// app/api/ws/route.ts (can be any route file in the app directory)
|
|
77
77
|
|
|
78
|
-
export function
|
|
79
|
-
client: import(
|
|
80
|
-
|
|
81
|
-
server: import("ws").WebSocketServer
|
|
78
|
+
export function UPGRADE(
|
|
79
|
+
client: import('ws').WebSocket,
|
|
80
|
+
server: import('ws').WebSocketServer
|
|
82
81
|
) {
|
|
83
|
-
console.log(
|
|
82
|
+
console.log('A client connected');
|
|
84
83
|
|
|
85
|
-
client.on(
|
|
86
|
-
console.log(
|
|
84
|
+
client.on('message', (message) => {
|
|
85
|
+
console.log('Received message:', message);
|
|
87
86
|
client.send(message);
|
|
88
87
|
});
|
|
89
88
|
|
|
90
|
-
client.
|
|
91
|
-
console.log(
|
|
89
|
+
client.once('close', () => {
|
|
90
|
+
console.log('A client disconnected');
|
|
92
91
|
});
|
|
93
92
|
}
|
|
94
93
|
```
|
package/dist/cli.cjs
CHANGED
|
@@ -27,7 +27,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
27
27
|
var import_minimist = __toESM(require("minimist"));
|
|
28
28
|
|
|
29
29
|
// package.json
|
|
30
|
-
var version = "0.0.0-beta-
|
|
30
|
+
var version = "0.0.0-beta-20250823112013";
|
|
31
31
|
|
|
32
32
|
// src/commands/helpers/define.ts
|
|
33
33
|
function defineCommandGroup(definition) {
|
package/dist/server/index.cjs
CHANGED
|
@@ -52,13 +52,13 @@ function mainProcessOnly(callerName) {
|
|
|
52
52
|
if (!meta.isCustomServer && !meta.isMainProcess) {
|
|
53
53
|
throw new Error(
|
|
54
54
|
`[next-ws] Attempt to call '${callerName}' outside the main process.
|
|
55
|
-
You may be attempting to interact with the WebSocket server outside of
|
|
55
|
+
You may be attempting to interact with the WebSocket server outside of an UPGRADE handler. This will fail in production, as Next.js employs a worker process for routing, which do not have access to the WebSocket server on the main process.
|
|
56
56
|
You can resolve this by using a custom server.`
|
|
57
57
|
);
|
|
58
58
|
} else if (!meta.isCustomServer) {
|
|
59
59
|
logger.warnOnce(
|
|
60
60
|
`[next-ws] The function '${callerName}' was called without a custom server.
|
|
61
|
-
This could lead to unintended behaviour, especially if you're attempting to interact with the WebSocket server outside of
|
|
61
|
+
This could lead to unintended behaviour, especially if you're attempting to interact with the WebSocket server outside of an UPGRADE handler.
|
|
62
62
|
Please note, while such configurations might function during development, they will fail in production. This is because Next.js employs a worker process for routing in production, which do not have access to the WebSocket server on the main process.
|
|
63
63
|
You can resolve this by using a custom server.`
|
|
64
64
|
);
|
|
@@ -168,6 +168,23 @@ async function importRouteModule(nextServer, filePath) {
|
|
|
168
168
|
}
|
|
169
169
|
}
|
|
170
170
|
|
|
171
|
+
// src/server/helpers/request.ts
|
|
172
|
+
var import_server = require("next/server");
|
|
173
|
+
function toNextRequest(message) {
|
|
174
|
+
const controller = new AbortController();
|
|
175
|
+
const headers = new Headers(message.headers);
|
|
176
|
+
const protocol = "encrypted" in message.socket ? "https" : "http";
|
|
177
|
+
const url = `${protocol}://${headers.get("host")}${message.url}`;
|
|
178
|
+
message.once("aborted", () => controller.abort());
|
|
179
|
+
return new import_server.NextRequest(url, {
|
|
180
|
+
method: message.method,
|
|
181
|
+
headers,
|
|
182
|
+
body: message.method === "GET" || message.method === "HEAD" ? void 0 : message,
|
|
183
|
+
signal: controller.signal,
|
|
184
|
+
referrer: headers.get("referer") || void 0
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
|
|
171
188
|
// src/server/setup.ts
|
|
172
189
|
function setupWebSocketServer(nextServer) {
|
|
173
190
|
process.env.NEXT_WS_MAIN_PROCESS = String(1);
|
|
@@ -191,8 +208,8 @@ function setupWebSocketServer(nextServer) {
|
|
|
191
208
|
if (Reflect.has(httpServer, kInstalled)) return;
|
|
192
209
|
Reflect.set(httpServer, kInstalled, true);
|
|
193
210
|
httpServer.on("upgrade", async (message, socket, head) => {
|
|
194
|
-
const
|
|
195
|
-
const pathname =
|
|
211
|
+
const request = toNextRequest(message);
|
|
212
|
+
const pathname = request.nextUrl.pathname;
|
|
196
213
|
if (pathname.includes("/_next")) return;
|
|
197
214
|
const route = findMatchingRoute(nextServer, pathname);
|
|
198
215
|
if (!route) {
|
|
@@ -204,23 +221,30 @@ function setupWebSocketServer(nextServer) {
|
|
|
204
221
|
logger3.error(`[next-ws] could not import module for page ${pathname}`);
|
|
205
222
|
return socket.end();
|
|
206
223
|
}
|
|
224
|
+
const handleUpgrade = module2.userland.UPGRADE;
|
|
207
225
|
const handleSocket = module2.userland.SOCKET;
|
|
208
|
-
if (!handleSocket || typeof handleSocket !== "function") {
|
|
209
|
-
logger3.error(
|
|
210
|
-
`[next-ws] route '${pathname}' does not export a valid 'SOCKET' handler`
|
|
211
|
-
);
|
|
226
|
+
if ((!handleUpgrade || typeof handleUpgrade !== "function") && (!handleSocket || typeof handleSocket !== "function")) {
|
|
227
|
+
logger3.error(`[next-ws] route '${pathname}' does not export a handler`);
|
|
212
228
|
return socket.end();
|
|
213
229
|
}
|
|
230
|
+
if (handleSocket)
|
|
231
|
+
logger3.warnOnce(
|
|
232
|
+
"DeprecationWarning: [next-ws] SOCKET is deprecated, use UPGRADE instead, see https://github.com/apteryxxyz/next-ws#-usage"
|
|
233
|
+
);
|
|
214
234
|
wsServer.handleUpgrade(message, socket, head, async (client) => {
|
|
215
235
|
wsServer.emit("connection", client, message);
|
|
216
236
|
try {
|
|
217
237
|
const context = { params: route.params };
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
238
|
+
if (handleUpgrade) {
|
|
239
|
+
await handleUpgrade(client, wsServer, request, context);
|
|
240
|
+
} else if (handleSocket) {
|
|
241
|
+
const handleClose = (
|
|
242
|
+
//
|
|
243
|
+
await handleSocket(client, message, wsServer, context)
|
|
244
|
+
);
|
|
245
|
+
if (typeof handleClose === "function")
|
|
246
|
+
client.once("close", () => handleClose());
|
|
247
|
+
}
|
|
224
248
|
} catch (cause) {
|
|
225
249
|
logger3.error(
|
|
226
250
|
`[next-ws] error in socket handler for '${pathname}'`,
|
package/dist/server/index.d.ts
CHANGED
|
@@ -1,7 +1,27 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as next_server from 'next/server';
|
|
2
|
+
import * as http from 'http';
|
|
3
|
+
import * as ws from 'ws';
|
|
2
4
|
import { WebSocketServer } from 'ws';
|
|
5
|
+
import { Server } from 'node:http';
|
|
3
6
|
import NextNodeServer from 'next/dist/server/next-server.js';
|
|
4
7
|
|
|
8
|
+
/** @deprecated Prefer UPGRADE and {@link UpgradeHandler} */
|
|
9
|
+
type SocketHandler = (client: ws.WebSocket, request: http.IncomingMessage, server: ws.WebSocketServer, context: {
|
|
10
|
+
params: Record<string, string | string[]>;
|
|
11
|
+
}) => unknown;
|
|
12
|
+
type UpgradeHandler = (client: ws.WebSocket, server: ws.WebSocketServer, request: next_server.NextRequest, context: RouteContext<string>) => unknown;
|
|
13
|
+
|
|
14
|
+
type RouteParams<Path extends string> = Path extends `${infer Before}[[...${infer Param}]]${infer After}` ? RouteParams<Before> & {
|
|
15
|
+
[K in Param]?: string[];
|
|
16
|
+
} & RouteParams<After> : Path extends `${infer Before}[...${infer Param}]${infer After}` ? RouteParams<Before> & {
|
|
17
|
+
[K in Param]: string[];
|
|
18
|
+
} & RouteParams<After> : Path extends `${infer Before}[${infer Param}]${infer After}` ? RouteParams<Before> & {
|
|
19
|
+
[K in Param]: string;
|
|
20
|
+
} & RouteParams<After> : {};
|
|
21
|
+
type RouteContext<Path extends string> = {
|
|
22
|
+
params: Record<string, string | string[] | undefined> & RouteParams<Path> & RouteParams<Path>;
|
|
23
|
+
};
|
|
24
|
+
|
|
5
25
|
declare function getHttpServer(): Server | undefined;
|
|
6
26
|
declare function setHttpServer<T extends Server | undefined>(server: T): T;
|
|
7
27
|
declare function getWebSocketServer(): WebSocketServer | undefined;
|
|
@@ -9,4 +29,4 @@ declare function setWebSocketServer<T extends WebSocketServer | undefined>(serve
|
|
|
9
29
|
|
|
10
30
|
declare function setupWebSocketServer(nextServer: NextNodeServer): void;
|
|
11
31
|
|
|
12
|
-
export { getHttpServer, getWebSocketServer, setHttpServer, setWebSocketServer, setupWebSocketServer };
|
|
32
|
+
export { type RouteContext, type SocketHandler, type UpgradeHandler, getHttpServer, getWebSocketServer, setHttpServer, setWebSocketServer, setupWebSocketServer };
|