next-ws 2.2.18 → 2.2.19

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 CHANGED
@@ -25,6 +25,7 @@
25
25
  - [📦 Installation](#-installation)
26
26
  - [🚀 Usage](#-usage)
27
27
  - [🌀 Examples](#-examples)
28
+ - [🔒 HTTPS and `wss://`](#-https-and-wss)
28
29
 
29
30
  ## 📦 Installation
30
31
 
@@ -97,3 +98,27 @@ You can now connect to your WebSocket server, send it a message and receive the
97
98
  ### Chat Room
98
99
 
99
100
  See the [chat room example](https://github.com/k0d13/next-ws/tree/main/examples/chat-room).
101
+
102
+ ### WebSocket Proxy
103
+
104
+ Forward connections to another WebSocket server, using a catch-all route to keep the rest of the path. See the [websocket proxy example](https://github.com/k0d13/next-ws/tree/main/examples/websocket-proxy).
105
+
106
+ ## 🔒 HTTPS and `wss://`
107
+
108
+ Next WS doesn't handle TLS itself. It listens for upgrade requests on the same HTTP server that Next.js uses, so `wss://` works whenever that server is reachable over HTTPS.
109
+
110
+ **Reverse proxy (recommended):** terminate TLS in nginx, Caddy or your load balancer and forward to `next start` over plain HTTP. Make sure the proxy forwards the `Upgrade` and `Connection` headers.
111
+
112
+ **Custom server:** create an HTTPS server with your certificate and hand it to Next WS. See the [custom server example](https://github.com/k0d13/next-ws/tree/main/examples/custom-server) for the full setup.
113
+
114
+ ```ts
115
+ import { readFileSync } from 'node:fs';
116
+ import { createServer } from 'node:https';
117
+ import { setHttpServer } from 'next-ws/server';
118
+
119
+ const httpsServer = createServer({
120
+ key: readFileSync('key.pem'),
121
+ cert: readFileSync('cert.pem'),
122
+ });
123
+ setHttpServer(httpsServer);
124
+ ```
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 = "2.2.18";
30
+ var version = "2.2.19";
31
31
 
32
32
  // src/commands/helpers/define.ts
33
33
  function defineCommandGroup(definition) {
@@ -80,8 +80,37 @@ Options:
80
80
  }
81
81
 
82
82
  // src/patches/helpers/next.ts
83
- var import_promises = require("fs/promises");
83
+ var import_promises3 = require("fs/promises");
84
84
  var import_node_path = require("path");
85
+
86
+ // src/patches/helpers/fs.ts
87
+ var import_node_crypto = require("crypto");
88
+ var import_promises = require("fs/promises");
89
+ var import_promises2 = require("timers/promises");
90
+ async function writeFileAtomic(path, data) {
91
+ const temporary = `${path}.${process.pid}.${(0, import_node_crypto.randomBytes)(4).toString("hex")}.tmp`;
92
+ try {
93
+ await (0, import_promises.writeFile)(temporary, data);
94
+ await renameWithRetry(temporary, path);
95
+ } catch (error2) {
96
+ await (0, import_promises.rm)(temporary, { force: true });
97
+ throw error2;
98
+ }
99
+ }
100
+ async function renameWithRetry(from, to) {
101
+ for (let attempt = 1; ; attempt++) {
102
+ try {
103
+ return await (0, import_promises.rename)(from, to);
104
+ } catch (error2) {
105
+ const code = error2.code;
106
+ const busy = code === "EPERM" || code === "EACCES" || code === "EBUSY";
107
+ if (!busy || attempt >= 20) throw error2;
108
+ await (0, import_promises2.setTimeout)(attempt * 25);
109
+ }
110
+ }
111
+ }
112
+
113
+ // src/patches/helpers/next.ts
85
114
  function resolveNextWsDirectory() {
86
115
  const id = (
87
116
  //
@@ -98,16 +127,16 @@ function resolveNextDirectory() {
98
127
  }
99
128
  async function getInstalledNextVersion() {
100
129
  const id = (0, import_node_path.join)(resolveNextDirectory(), "package.json");
101
- const pkg = await (0, import_promises.readFile)(id, "utf8").then(JSON.parse);
130
+ const pkg = await (0, import_promises3.readFile)(id, "utf8").then(JSON.parse);
102
131
  return String(pkg.version.split("-")[0]);
103
132
  }
104
133
  async function readTrace() {
105
134
  const id = (0, import_node_path.join)(resolveNextDirectory(), ".next-ws-trace.json");
106
- return (0, import_promises.readFile)(id, "utf-8").then(JSON.parse).catch(() => null);
135
+ return (0, import_promises3.readFile)(id, "utf-8").then(JSON.parse).catch(() => null);
107
136
  }
108
137
  async function writeTrace(trace) {
109
138
  const id = (0, import_node_path.join)(resolveNextDirectory(), ".next-ws-trace.json");
110
- await (0, import_promises.writeFile)(id, JSON.stringify(trace, null, 2));
139
+ await writeFileAtomic(id, JSON.stringify(trace, null, 2));
111
140
  }
112
141
 
113
142
  // src/patches/patch-1.ts
@@ -115,7 +144,7 @@ var import_node_path3 = require("path");
115
144
  var import_jscodeshift = __toESM(require("jscodeshift"));
116
145
 
117
146
  // src/patches/helpers/define.ts
118
- var import_promises2 = require("fs/promises");
147
+ var import_promises4 = require("fs/promises");
119
148
  var import_node_path2 = require("path");
120
149
 
121
150
  // src/commands/helpers/console.ts
@@ -697,8 +726,8 @@ function definePatchStep(definition) {
697
726
  },
698
727
  async execute() {
699
728
  debug(`Applying '${this.title}' to '${this.path}'`);
700
- const code = await (0, import_promises2.readFile)(this.path, "utf8").then((code2) => this.transform(code2));
701
- await (0, import_promises2.writeFile)(this.path, code);
729
+ const code = await (0, import_promises4.readFile)(this.path, "utf8").then((code2) => this.transform(code2));
730
+ await writeFileAtomic(this.path, code);
702
731
  }
703
732
  };
704
733
  }
@@ -843,7 +872,7 @@ var patchCookies2 = definePatchStep({
843
872
  });
844
873
  var patch_2_default = definePatch({
845
874
  name: "patch-2",
846
- versions: ">=15.0.0 <=16.4.1",
875
+ versions: ">=15.0.0 <=16.4.2",
847
876
  steps: [
848
877
  patchNextNodeServer,
849
878
  patchRouterServer,
@@ -43,22 +43,21 @@ var WebSocketContext = (0, import_react.createContext)(null);
43
43
  WebSocketContext.displayName = "WebSocketContext";
44
44
  var WebSocketConsumer = WebSocketContext.Consumer;
45
45
  function WebSocketProvider(p) {
46
- const clientRef = (0, import_react.useRef)(null);
46
+ const [client, setClient] = (0, import_react.useState)(null);
47
+ const protocols = Array.isArray(p.protocols) ? p.protocols.join(",") : p.protocols;
47
48
  (0, import_react.useEffect)(() => {
48
- if (typeof window === "undefined") return;
49
- if (clientRef.current) {
50
- clientRef.current.close();
51
- clientRef.current = null;
52
- }
53
- const client = new WebSocket(p.url, p.protocols);
54
- if (p.binaryType) client.binaryType = p.binaryType;
55
- clientRef.current = client;
49
+ const client2 = new WebSocket(
50
+ p.url,
51
+ protocols ? protocols.split(",") : void 0
52
+ );
53
+ if (p.binaryType) client2.binaryType = p.binaryType;
54
+ setClient(client2);
56
55
  return () => {
57
- client.close();
58
- clientRef.current = null;
56
+ client2.close();
57
+ setClient(null);
59
58
  };
60
- }, [p.url, p.protocols, p.binaryType]);
61
- return /* @__PURE__ */ import_react.default.createElement(WebSocketContext.Provider, { value: clientRef.current }, p.children);
59
+ }, [p.url, protocols, p.binaryType]);
60
+ return /* @__PURE__ */ import_react.default.createElement(WebSocketContext.Provider, { value: client }, p.children);
62
61
  }
63
62
  function useWebSocket() {
64
63
  const context = (0, import_react.useContext)(WebSocketContext);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "next-ws",
3
- "version": "2.2.18",
3
+ "version": "2.2.19",
4
4
  "description": "Add support for WebSockets in the Next.js app directory",
5
5
  "license": "MIT",
6
6
  "keywords": [
@@ -60,7 +60,7 @@
60
60
  "chalk": "^5.6.2",
61
61
  "husky": "^9.1.7",
62
62
  "ioredis": "^5.10.0",
63
- "next": "16.4.1",
63
+ "next": "16.4.2",
64
64
  "pinst": "^3.0.0",
65
65
  "react": "19.1.1",
66
66
  "react-dom": "19.1.1",