next-ws 0.0.0-beta-20250823112013 → 0.0.0-beta-20250824084203
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/dist/cli.cjs +68 -4
- package/dist/server/index.cjs +84 -74
- package/dist/server/index.d.ts +4 -6
- package/package.json +1 -1
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-20250824084203";
|
|
31
31
|
|
|
32
32
|
// src/commands/helpers/define.ts
|
|
33
33
|
function defineCommandGroup(definition) {
|
|
@@ -757,14 +757,78 @@ var patchRouterServer = definePatchStep({
|
|
|
757
757
|
}).toSource();
|
|
758
758
|
}
|
|
759
759
|
});
|
|
760
|
+
var patchHeaders = definePatchStep({
|
|
761
|
+
title: "Add WebSocket contextual headers resolution to request headers",
|
|
762
|
+
path: "next:dist/client/components/headers.js",
|
|
763
|
+
async transform(code) {
|
|
764
|
+
const marker = "@patch headers";
|
|
765
|
+
const snippet = (0, import_jscodeshift.default)(`
|
|
766
|
+
// ${marker}
|
|
767
|
+
const kRequestStorage = Symbol.for('next-ws.request-store');
|
|
768
|
+
const requestStorage = Reflect.get(globalThis, kRequestStorage);
|
|
769
|
+
const contextualHeaders = requestStorage?.getStore()?.headers;
|
|
770
|
+
if (contextualHeaders) return contextualHeaders;
|
|
771
|
+
`);
|
|
772
|
+
const block = import_jscodeshift.default.blockStatement(snippet.nodes()[0].program.body);
|
|
773
|
+
return (0, import_jscodeshift.default)(code).find(import_jscodeshift.default.FunctionDeclaration, { id: { name: "headers" } }).forEach(({ node }) => {
|
|
774
|
+
const body = node.body.body;
|
|
775
|
+
const existing = (0, import_jscodeshift.default)(body).find(CommentLine, { value: ` ${marker}` }).paths()[0];
|
|
776
|
+
const idx = body.indexOf(existing?.parent.node);
|
|
777
|
+
if (existing && idx > -1) body[idx] = block;
|
|
778
|
+
else body.unshift(block);
|
|
779
|
+
}).toSource();
|
|
780
|
+
}
|
|
781
|
+
});
|
|
782
|
+
var patchCookies = definePatchStep({
|
|
783
|
+
title: "Add WebSocket contextual cookies resolution to request cookies",
|
|
784
|
+
path: "next:dist/client/components/headers.js",
|
|
785
|
+
async transform(code) {
|
|
786
|
+
const marker = "@patch cookies";
|
|
787
|
+
const snippet = (0, import_jscodeshift.default)(`
|
|
788
|
+
// ${marker}
|
|
789
|
+
const kRequestStorage = Symbol.for('next-ws.request-store');
|
|
790
|
+
const requestStorage = Reflect.get(globalThis, kRequestStorage);
|
|
791
|
+
const contextualCookies = requestStorage?.getStore()?.cookies;
|
|
792
|
+
if (contextualCookies) return contextualCookies;
|
|
793
|
+
`);
|
|
794
|
+
const block = import_jscodeshift.default.blockStatement(snippet.nodes()[0].program.body);
|
|
795
|
+
return (0, import_jscodeshift.default)(code).find(import_jscodeshift.default.FunctionDeclaration, { id: { name: "cookies" } }).forEach(({ node }) => {
|
|
796
|
+
const body = node.body.body;
|
|
797
|
+
const existing = (0, import_jscodeshift.default)(body).find(CommentLine, { value: ` ${marker}` }).paths()[0];
|
|
798
|
+
const idx = body.indexOf(existing?.parent.node);
|
|
799
|
+
if (existing && idx > -1) body[idx] = block;
|
|
800
|
+
else body.unshift(block);
|
|
801
|
+
}).toSource();
|
|
802
|
+
}
|
|
803
|
+
});
|
|
760
804
|
var patch_1_default = definePatch({
|
|
761
805
|
name: "patch-1",
|
|
762
|
-
versions: ">=13.5.1 <=
|
|
763
|
-
steps: [patchNextNodeServer, patchRouterServer]
|
|
806
|
+
versions: ">=13.5.1 <=14.2.32",
|
|
807
|
+
steps: [patchNextNodeServer, patchRouterServer, patchHeaders, patchCookies]
|
|
808
|
+
});
|
|
809
|
+
|
|
810
|
+
// src/patches/patch-2.ts
|
|
811
|
+
var patchHeaders2 = definePatchStep({
|
|
812
|
+
...patchHeaders,
|
|
813
|
+
path: "next:dist/server/request/headers.js"
|
|
814
|
+
});
|
|
815
|
+
var patchCookies2 = definePatchStep({
|
|
816
|
+
...patchCookies,
|
|
817
|
+
path: "next:dist/server/request/cookies.js"
|
|
818
|
+
});
|
|
819
|
+
var patch_2_default = definePatch({
|
|
820
|
+
name: "patch-2",
|
|
821
|
+
versions: ">=15.0.0 <=15.5.0",
|
|
822
|
+
steps: [
|
|
823
|
+
patchNextNodeServer,
|
|
824
|
+
patchRouterServer,
|
|
825
|
+
patchHeaders2,
|
|
826
|
+
patchCookies2
|
|
827
|
+
]
|
|
764
828
|
});
|
|
765
829
|
|
|
766
830
|
// src/patches/index.ts
|
|
767
|
-
var patches_default = [patch_1_default];
|
|
831
|
+
var patches_default = [patch_1_default, patch_2_default];
|
|
768
832
|
|
|
769
833
|
// src/commands/helpers/semver.ts
|
|
770
834
|
var import_range = __toESM(require("semver/classes/range.js"));
|
package/dist/server/index.cjs
CHANGED
|
@@ -39,66 +39,43 @@ __export(server_exports, {
|
|
|
39
39
|
module.exports = __toCommonJS(server_exports);
|
|
40
40
|
|
|
41
41
|
// src/server/persistent.ts
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
);
|
|
58
|
-
} else if (!meta.isCustomServer) {
|
|
59
|
-
logger.warnOnce(
|
|
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 an UPGRADE handler.
|
|
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
|
-
You can resolve this by using a custom server.`
|
|
64
|
-
);
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
var kHttpServer = Symbol.for("kHttpServer");
|
|
68
|
-
function getHttpServer() {
|
|
69
|
-
mainProcessOnly("getHttpServer");
|
|
70
|
-
return Reflect.get(globalThis, kHttpServer);
|
|
71
|
-
}
|
|
72
|
-
function setHttpServer(server) {
|
|
73
|
-
mainProcessOnly("setHttpServer");
|
|
74
|
-
Reflect.set(globalThis, kHttpServer, server);
|
|
75
|
-
return getHttpServer();
|
|
76
|
-
}
|
|
77
|
-
function useHttpServer(server) {
|
|
78
|
-
mainProcessOnly("useHttpServer");
|
|
79
|
-
const existing = getHttpServer();
|
|
80
|
-
if (existing) return existing;
|
|
81
|
-
return setHttpServer(server());
|
|
82
|
-
}
|
|
83
|
-
var kWebSocketServer = Symbol.for("kWebSocketServer");
|
|
84
|
-
function getWebSocketServer() {
|
|
85
|
-
mainProcessOnly("getWebSocketServer");
|
|
86
|
-
return Reflect.get(globalThis, kWebSocketServer);
|
|
87
|
-
}
|
|
88
|
-
function setWebSocketServer(server) {
|
|
89
|
-
mainProcessOnly("setWebSocketServer");
|
|
90
|
-
Reflect.set(globalThis, kWebSocketServer, server);
|
|
91
|
-
return getWebSocketServer();
|
|
92
|
-
}
|
|
93
|
-
function useWebSocketServer(server) {
|
|
94
|
-
mainProcessOnly("useWebSocketServer");
|
|
95
|
-
const existing = getWebSocketServer();
|
|
96
|
-
if (existing) return existing;
|
|
97
|
-
return setWebSocketServer(server());
|
|
42
|
+
function useGlobal(key) {
|
|
43
|
+
return [
|
|
44
|
+
function get() {
|
|
45
|
+
return Reflect.get(globalThis, key);
|
|
46
|
+
},
|
|
47
|
+
function set(value) {
|
|
48
|
+
return Reflect.set(globalThis, key, value);
|
|
49
|
+
},
|
|
50
|
+
function use(getter) {
|
|
51
|
+
const existing = Reflect.get(globalThis, key);
|
|
52
|
+
if (existing) return existing;
|
|
53
|
+
Reflect.set(globalThis, key, getter());
|
|
54
|
+
return Reflect.get(globalThis, key);
|
|
55
|
+
}
|
|
56
|
+
];
|
|
98
57
|
}
|
|
58
|
+
var [getHttpServer, setHttpServer, useHttpServer] = (
|
|
59
|
+
//
|
|
60
|
+
useGlobal(
|
|
61
|
+
Symbol.for("next-ws.http-server")
|
|
62
|
+
//
|
|
63
|
+
)
|
|
64
|
+
);
|
|
65
|
+
var [getWebSocketServer, setWebSocketServer, useWebSocketServer] = useGlobal(
|
|
66
|
+
Symbol.for("next-ws.websocket-server")
|
|
67
|
+
);
|
|
68
|
+
var [getRequestStorage, setRequestStorage, useRequestStorage] = (
|
|
69
|
+
//
|
|
70
|
+
useGlobal(
|
|
71
|
+
Symbol.for("next-ws.request-store")
|
|
72
|
+
//
|
|
73
|
+
)
|
|
74
|
+
);
|
|
99
75
|
|
|
100
76
|
// src/server/setup.ts
|
|
101
|
-
var
|
|
77
|
+
var import_node_async_hooks2 = require("async_hooks");
|
|
78
|
+
var logger2 = __toESM(require("next/dist/build/output/log.js"));
|
|
102
79
|
var import_ws = require("ws");
|
|
103
80
|
|
|
104
81
|
// src/server/helpers/match.ts
|
|
@@ -142,7 +119,7 @@ function findMatchingRoute(nextServer, requestPathname) {
|
|
|
142
119
|
}
|
|
143
120
|
|
|
144
121
|
// src/server/helpers/module.ts
|
|
145
|
-
var
|
|
122
|
+
var logger = __toESM(require("next/dist/build/output/log.js"));
|
|
146
123
|
async function importRouteModule(nextServer, filePath) {
|
|
147
124
|
try {
|
|
148
125
|
if ("hotReloader" in nextServer) {
|
|
@@ -153,7 +130,7 @@ async function importRouteModule(nextServer, filePath) {
|
|
|
153
130
|
} else if ("ensurePage" in nextServer) {
|
|
154
131
|
await nextServer.ensurePage({ page: filePath, clientOnly: false });
|
|
155
132
|
} else {
|
|
156
|
-
|
|
133
|
+
logger.warnOnce(
|
|
157
134
|
"[next-ws] unable to ensure page, you may need to open the route in your browser first so Next.js compiles it"
|
|
158
135
|
);
|
|
159
136
|
}
|
|
@@ -185,26 +162,55 @@ function toNextRequest(message) {
|
|
|
185
162
|
});
|
|
186
163
|
}
|
|
187
164
|
|
|
165
|
+
// src/server/helpers/store.ts
|
|
166
|
+
var import_node_async_hooks = require("async_hooks");
|
|
167
|
+
var import_cookies = require("next/dist/compiled/@edge-runtime/cookies");
|
|
168
|
+
var ReadonlyHeaders = class extends Headers {
|
|
169
|
+
append() {
|
|
170
|
+
throw new Error("Headers are read-only");
|
|
171
|
+
}
|
|
172
|
+
set() {
|
|
173
|
+
throw new Error("Headers are read-only");
|
|
174
|
+
}
|
|
175
|
+
delete() {
|
|
176
|
+
throw new Error("Headers are read-only");
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
var ReadonlyRequestsCookies = class extends import_cookies.RequestCookies {
|
|
180
|
+
set() {
|
|
181
|
+
throw new Error("Cookies are read-only");
|
|
182
|
+
}
|
|
183
|
+
delete() {
|
|
184
|
+
throw new Error("Cookies are read-only");
|
|
185
|
+
}
|
|
186
|
+
};
|
|
187
|
+
function createRequestStore(request) {
|
|
188
|
+
return {
|
|
189
|
+
headers: new ReadonlyHeaders(request.headers),
|
|
190
|
+
cookies: new ReadonlyRequestsCookies(request.headers)
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
var requestStorage = new import_node_async_hooks.AsyncLocalStorage();
|
|
194
|
+
|
|
188
195
|
// src/server/setup.ts
|
|
189
196
|
function setupWebSocketServer(nextServer) {
|
|
190
|
-
process.env.NEXT_WS_MAIN_PROCESS = String(1);
|
|
191
|
-
process.env.NEXT_WS_SKIP_ENVIRONMENT_CHECK = String(1);
|
|
192
197
|
const httpServer = (
|
|
193
198
|
//
|
|
194
199
|
// @ts-expect-error - serverOptions is protected
|
|
195
200
|
useHttpServer(() => nextServer.serverOptions?.httpServer)
|
|
196
201
|
);
|
|
197
202
|
if (!httpServer)
|
|
198
|
-
return
|
|
203
|
+
return logger2.error("[next-ws] was not able to find the HTTP server");
|
|
199
204
|
const wsServer = (
|
|
200
205
|
//
|
|
201
206
|
useWebSocketServer(() => new import_ws.WebSocketServer({ noServer: true }))
|
|
202
207
|
);
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
+
const requestStorage2 = (
|
|
209
|
+
//
|
|
210
|
+
useRequestStorage(() => new import_node_async_hooks2.AsyncLocalStorage())
|
|
211
|
+
);
|
|
212
|
+
logger2.ready("[next-ws] has started the WebSocket server");
|
|
213
|
+
const kInstalled = Symbol.for("next-ws.http-server.attached");
|
|
208
214
|
if (Reflect.has(httpServer, kInstalled)) return;
|
|
209
215
|
Reflect.set(httpServer, kInstalled, true);
|
|
210
216
|
httpServer.on("upgrade", async (message, socket, head) => {
|
|
@@ -213,30 +219,34 @@ function setupWebSocketServer(nextServer) {
|
|
|
213
219
|
if (pathname.includes("/_next")) return;
|
|
214
220
|
const route = findMatchingRoute(nextServer, pathname);
|
|
215
221
|
if (!route) {
|
|
216
|
-
|
|
222
|
+
logger2.error(`[next-ws] could not find route for page ${pathname}`);
|
|
217
223
|
return socket.end();
|
|
218
224
|
}
|
|
219
225
|
const module2 = await importRouteModule(nextServer, route.filename);
|
|
220
226
|
if (!module2) {
|
|
221
|
-
|
|
227
|
+
logger2.error(`[next-ws] could not import module for page ${pathname}`);
|
|
222
228
|
return socket.end();
|
|
223
229
|
}
|
|
224
230
|
const handleUpgrade = module2.userland.UPGRADE;
|
|
225
231
|
const handleSocket = module2.userland.SOCKET;
|
|
226
232
|
if ((!handleUpgrade || typeof handleUpgrade !== "function") && (!handleSocket || typeof handleSocket !== "function")) {
|
|
227
|
-
|
|
233
|
+
logger2.error(`[next-ws] route '${pathname}' does not export a handler`);
|
|
228
234
|
return socket.end();
|
|
229
235
|
}
|
|
230
236
|
if (handleSocket)
|
|
231
|
-
|
|
232
|
-
"DeprecationWarning: [next-ws] SOCKET is deprecated,
|
|
237
|
+
logger2.warnOnce(
|
|
238
|
+
"DeprecationWarning: [next-ws] SOCKET is deprecated, prefer UPGRADE instead, see https://github.com/apteryxxyz/next-ws#-usage"
|
|
233
239
|
);
|
|
234
240
|
wsServer.handleUpgrade(message, socket, head, async (client) => {
|
|
235
241
|
wsServer.emit("connection", client, message);
|
|
236
242
|
try {
|
|
237
243
|
const context = { params: route.params };
|
|
238
244
|
if (handleUpgrade) {
|
|
239
|
-
await
|
|
245
|
+
await requestStorage2.run(
|
|
246
|
+
createRequestStore(request),
|
|
247
|
+
//
|
|
248
|
+
() => handleUpgrade(client, wsServer, request, context)
|
|
249
|
+
);
|
|
240
250
|
} else if (handleSocket) {
|
|
241
251
|
const handleClose = (
|
|
242
252
|
//
|
|
@@ -246,7 +256,7 @@ function setupWebSocketServer(nextServer) {
|
|
|
246
256
|
client.once("close", () => handleClose());
|
|
247
257
|
}
|
|
248
258
|
} catch (cause) {
|
|
249
|
-
|
|
259
|
+
logger2.error(
|
|
250
260
|
`[next-ws] error in socket handler for '${pathname}'`,
|
|
251
261
|
cause
|
|
252
262
|
);
|
package/dist/server/index.d.ts
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import * as next_server from 'next/server';
|
|
2
2
|
import * as http from 'http';
|
|
3
3
|
import * as ws from 'ws';
|
|
4
|
-
import { WebSocketServer } from 'ws';
|
|
5
|
-
import { Server } from 'node:http';
|
|
6
4
|
import NextNodeServer from 'next/dist/server/next-server.js';
|
|
7
5
|
|
|
8
6
|
/** @deprecated Prefer UPGRADE and {@link UpgradeHandler} */
|
|
@@ -22,10 +20,10 @@ type RouteContext<Path extends string> = {
|
|
|
22
20
|
params: Record<string, string | string[] | undefined> & RouteParams<Path> & RouteParams<Path>;
|
|
23
21
|
};
|
|
24
22
|
|
|
25
|
-
declare
|
|
26
|
-
declare
|
|
27
|
-
declare
|
|
28
|
-
declare
|
|
23
|
+
declare const getHttpServer: () => http.Server<typeof http.IncomingMessage, typeof http.ServerResponse> | undefined;
|
|
24
|
+
declare const setHttpServer: (value: http.Server<typeof http.IncomingMessage, typeof http.ServerResponse>) => boolean;
|
|
25
|
+
declare const getWebSocketServer: () => ws.WebSocketServer | undefined;
|
|
26
|
+
declare const setWebSocketServer: (value: ws.WebSocketServer) => boolean;
|
|
29
27
|
|
|
30
28
|
declare function setupWebSocketServer(nextServer: NextNodeServer): void;
|
|
31
29
|
|