unplugin-https-reverse-proxy 4.0.0 → 4.0.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/dist/{chunk-K7HSLE6X.js → chunk-JA3D5AWS.js} +40 -4
- package/dist/chunk-RSBXFJ3Z.js +232 -0
- package/dist/esbuild.cjs +264 -4
- package/dist/esbuild.js +2 -1
- package/dist/hmr-sse-bridge.cjs +258 -0
- package/dist/hmr-sse-bridge.d.cts +10 -0
- package/dist/hmr-sse-bridge.d.ts +10 -0
- package/dist/hmr-sse-bridge.js +8 -0
- package/dist/index.cjs +264 -4
- package/dist/index.js +2 -1
- package/dist/nuxt.cjs +152 -4
- package/dist/nuxt.js +2 -1
- package/dist/rollup.cjs +264 -4
- package/dist/rollup.js +2 -1
- package/dist/rspack.cjs +264 -4
- package/dist/rspack.js +2 -1
- package/dist/vite.cjs +264 -4
- package/dist/vite.js +2 -1
- package/dist/webpack.cjs +264 -4
- package/dist/webpack.js +2 -1
- package/package.json +1 -1
- package/src/caddy/index.ts +24 -5
- package/src/hmr-sse-bridge.ts +266 -0
- package/src/index.ts +20 -0
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/hmr-sse-bridge.ts
|
|
21
|
+
var hmr_sse_bridge_exports = {};
|
|
22
|
+
__export(hmr_sse_bridge_exports, {
|
|
23
|
+
hmrSseBridgeClientScript: () => hmrSseBridgeClientScript,
|
|
24
|
+
setupHmrSseBridge: () => setupHmrSseBridge
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(hmr_sse_bridge_exports);
|
|
27
|
+
var SSE_PATH = "/__hmr_sse";
|
|
28
|
+
var SEND_PATH = "/__hmr_send";
|
|
29
|
+
var MAX_POST_BODY = 64 * 1024;
|
|
30
|
+
function setupHmrSseBridge(server) {
|
|
31
|
+
const sseClients = /* @__PURE__ */ new Set();
|
|
32
|
+
const originalSend = server.ws.send.bind(server.ws);
|
|
33
|
+
server.ws.send = (...args) => {
|
|
34
|
+
;
|
|
35
|
+
originalSend(...args);
|
|
36
|
+
let payload;
|
|
37
|
+
if (typeof args[0] === "string") {
|
|
38
|
+
payload = JSON.stringify({ type: "custom", event: args[0], data: args[1] });
|
|
39
|
+
} else {
|
|
40
|
+
payload = JSON.stringify(args[0]);
|
|
41
|
+
}
|
|
42
|
+
for (const res of sseClients) {
|
|
43
|
+
try {
|
|
44
|
+
res.write(`data: ${payload}
|
|
45
|
+
|
|
46
|
+
`);
|
|
47
|
+
} catch {
|
|
48
|
+
sseClients.delete(res);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
server.middlewares.use((req, res, next) => {
|
|
53
|
+
var _a;
|
|
54
|
+
const url = (_a = req.url) == null ? void 0 : _a.split("?")[0];
|
|
55
|
+
if (url === SSE_PATH && req.method === "GET") {
|
|
56
|
+
handleSseConnection(req, res, sseClients);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
if (url === SEND_PATH && req.method === "POST") {
|
|
60
|
+
handleClientMessage(req, res, server);
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
next();
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
function handleSseConnection(_req, res, sseClients) {
|
|
67
|
+
res.writeHead(200, {
|
|
68
|
+
"Content-Type": "text/event-stream",
|
|
69
|
+
"Cache-Control": "no-cache",
|
|
70
|
+
"Connection": "keep-alive"
|
|
71
|
+
});
|
|
72
|
+
res.write(`data: ${JSON.stringify({ type: "connected" })}
|
|
73
|
+
|
|
74
|
+
`);
|
|
75
|
+
sseClients.add(res);
|
|
76
|
+
const keepAlive = setInterval(() => {
|
|
77
|
+
try {
|
|
78
|
+
res.write(": ping\n\n");
|
|
79
|
+
} catch {
|
|
80
|
+
cleanup();
|
|
81
|
+
}
|
|
82
|
+
}, 3e4);
|
|
83
|
+
function cleanup() {
|
|
84
|
+
clearInterval(keepAlive);
|
|
85
|
+
sseClients.delete(res);
|
|
86
|
+
}
|
|
87
|
+
res.on("close", cleanup);
|
|
88
|
+
res.on("error", cleanup);
|
|
89
|
+
}
|
|
90
|
+
function handleClientMessage(req, res, server) {
|
|
91
|
+
let body = "";
|
|
92
|
+
let overflow = false;
|
|
93
|
+
req.on("data", (chunk) => {
|
|
94
|
+
body += chunk.toString();
|
|
95
|
+
if (body.length > MAX_POST_BODY) {
|
|
96
|
+
overflow = true;
|
|
97
|
+
req.destroy();
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
req.on("end", () => {
|
|
101
|
+
var _a, _b, _c, _d, _e;
|
|
102
|
+
if (overflow) {
|
|
103
|
+
res.writeHead(413);
|
|
104
|
+
res.end('{"ok":false}');
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
try {
|
|
108
|
+
const data = JSON.parse(body);
|
|
109
|
+
if (data.type === "custom" && data.event) {
|
|
110
|
+
const dummyClient = {
|
|
111
|
+
send: (...args) => {
|
|
112
|
+
server.ws.send(...args);
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
(_e = (_d = (_c = (_b = (_a = server.environments) == null ? void 0 : _a.client) == null ? void 0 : _b.hot) == null ? void 0 : _c.api) == null ? void 0 : _d.emit) == null ? void 0 : _e.call(_d, data.event, data.data, dummyClient);
|
|
116
|
+
}
|
|
117
|
+
res.writeHead(200, {
|
|
118
|
+
"Content-Type": "application/json"
|
|
119
|
+
});
|
|
120
|
+
res.end('{"ok":true}');
|
|
121
|
+
} catch {
|
|
122
|
+
res.writeHead(400);
|
|
123
|
+
res.end('{"ok":false}');
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
var hmrSseBridgeClientScript = `
|
|
128
|
+
(function() {
|
|
129
|
+
// Activate when served over HTTPS to bypass WSS self-signed cert issues
|
|
130
|
+
if (location.protocol !== 'https:') return;
|
|
131
|
+
|
|
132
|
+
var OriginalWebSocket = window.WebSocket;
|
|
133
|
+
|
|
134
|
+
function SseWebSocket(originalUrl) {
|
|
135
|
+
var self = this;
|
|
136
|
+
// WebSocket readyState constants on instance
|
|
137
|
+
self.CONNECTING = 0;
|
|
138
|
+
self.OPEN = 1;
|
|
139
|
+
self.CLOSING = 2;
|
|
140
|
+
self.CLOSED = 3;
|
|
141
|
+
self.readyState = 0;
|
|
142
|
+
self.onopen = null;
|
|
143
|
+
self.onmessage = null;
|
|
144
|
+
self.onclose = null;
|
|
145
|
+
self.onerror = null;
|
|
146
|
+
self.bufferedAmount = 0;
|
|
147
|
+
self.extensions = '';
|
|
148
|
+
self.binaryType = 'blob';
|
|
149
|
+
self.protocol = 'vite-hmr';
|
|
150
|
+
self.url = originalUrl;
|
|
151
|
+
self._listeners = {};
|
|
152
|
+
self._opened = false;
|
|
153
|
+
|
|
154
|
+
var sseUrl = location.origin + '${SSE_PATH}';
|
|
155
|
+
var sendUrl = location.origin + '${SEND_PATH}';
|
|
156
|
+
self._sendUrl = sendUrl;
|
|
157
|
+
|
|
158
|
+
var es = new EventSource(sseUrl);
|
|
159
|
+
self._es = es;
|
|
160
|
+
|
|
161
|
+
es.onopen = function() {
|
|
162
|
+
if (self._opened) return;
|
|
163
|
+
self._opened = true;
|
|
164
|
+
self.readyState = 1;
|
|
165
|
+
var evt = new Event('open');
|
|
166
|
+
if (self.onopen) self.onopen(evt);
|
|
167
|
+
self._emit('open', evt);
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
es.onmessage = function(e) {
|
|
171
|
+
var evt = new MessageEvent('message', { data: e.data });
|
|
172
|
+
if (self.onmessage) self.onmessage(evt);
|
|
173
|
+
self._emit('message', evt);
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
es.onerror = function() {
|
|
177
|
+
// EventSource auto-reconnects on error; don't treat as fatal close
|
|
178
|
+
// Only emit error event, never close event (SSE handles reconnect internally)
|
|
179
|
+
if (self.readyState >= 2) return;
|
|
180
|
+
// EventSource auto-reconnects; no action needed
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
SseWebSocket.prototype.send = function(data) {
|
|
185
|
+
if (this.readyState !== 1) return;
|
|
186
|
+
fetch(this._sendUrl, {
|
|
187
|
+
method: 'POST',
|
|
188
|
+
headers: { 'Content-Type': 'application/json' },
|
|
189
|
+
body: data
|
|
190
|
+
}).catch(function() {});
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
SseWebSocket.prototype.close = function() {
|
|
194
|
+
if (this.readyState >= 2) return;
|
|
195
|
+
this.readyState = 3;
|
|
196
|
+
if (this._es) this._es.close();
|
|
197
|
+
var evt = new CloseEvent('close', { code: 1000, reason: '', wasClean: true });
|
|
198
|
+
if (this.onclose) this.onclose(evt);
|
|
199
|
+
this._emit('close', evt);
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
SseWebSocket.prototype.addEventListener = function(type, fn, options) {
|
|
203
|
+
if (!this._listeners[type]) this._listeners[type] = [];
|
|
204
|
+
var entry = { fn: fn, once: !!(options && options.once) };
|
|
205
|
+
this._listeners[type].push(entry);
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
SseWebSocket.prototype.removeEventListener = function(type, fn) {
|
|
209
|
+
var list = this._listeners[type];
|
|
210
|
+
if (!list) return;
|
|
211
|
+
this._listeners[type] = list.filter(function(e) { return e.fn !== fn; });
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
SseWebSocket.prototype.dispatchEvent = function(evt) {
|
|
215
|
+
this._emit(evt.type, evt);
|
|
216
|
+
return true;
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
SseWebSocket.prototype._emit = function(type, evt) {
|
|
220
|
+
var list = this._listeners[type];
|
|
221
|
+
if (!list) return;
|
|
222
|
+
var remaining = [];
|
|
223
|
+
list.forEach(function(entry) {
|
|
224
|
+
entry.fn(evt);
|
|
225
|
+
if (!entry.once) remaining.push(entry);
|
|
226
|
+
});
|
|
227
|
+
this._listeners[type] = remaining;
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
function PatchedWebSocket(url, protocols) {
|
|
231
|
+
// Only intercept Vite HMR connections (protocol 'vite-hmr')
|
|
232
|
+
var isViteHmr = protocols === 'vite-hmr'
|
|
233
|
+
|| (Array.isArray(protocols) && protocols.indexOf('vite-hmr') !== -1);
|
|
234
|
+
if (!isViteHmr) {
|
|
235
|
+
if (protocols !== undefined) {
|
|
236
|
+
return new OriginalWebSocket(url, protocols);
|
|
237
|
+
}
|
|
238
|
+
return new OriginalWebSocket(url);
|
|
239
|
+
}
|
|
240
|
+
return new SseWebSocket(url);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
PatchedWebSocket.CONNECTING = 0;
|
|
244
|
+
PatchedWebSocket.OPEN = 1;
|
|
245
|
+
PatchedWebSocket.CLOSING = 2;
|
|
246
|
+
PatchedWebSocket.CLOSED = 3;
|
|
247
|
+
PatchedWebSocket.prototype = Object.create(OriginalWebSocket.prototype);
|
|
248
|
+
PatchedWebSocket.prototype.constructor = PatchedWebSocket;
|
|
249
|
+
|
|
250
|
+
window.WebSocket = PatchedWebSocket;
|
|
251
|
+
})();
|
|
252
|
+
`;
|
|
253
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
254
|
+
0 && (module.exports = {
|
|
255
|
+
hmrSseBridgeClientScript,
|
|
256
|
+
setupHmrSseBridge
|
|
257
|
+
});
|
|
258
|
+
exports.default = module.exports;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { ViteDevServer } from 'vite';
|
|
2
|
+
|
|
3
|
+
declare function setupHmrSseBridge(server: ViteDevServer): void;
|
|
4
|
+
/**
|
|
5
|
+
* Client-side script that patches WebSocket to use SSE+fetch on iOS Safari.
|
|
6
|
+
* This script is injected via Vite's transformIndexHtml hook.
|
|
7
|
+
*/
|
|
8
|
+
declare const hmrSseBridgeClientScript = "\n(function() {\n // Activate when served over HTTPS to bypass WSS self-signed cert issues\n if (location.protocol !== 'https:') return;\n\n var OriginalWebSocket = window.WebSocket;\n\n function SseWebSocket(originalUrl) {\n var self = this;\n // WebSocket readyState constants on instance\n self.CONNECTING = 0;\n self.OPEN = 1;\n self.CLOSING = 2;\n self.CLOSED = 3;\n self.readyState = 0;\n self.onopen = null;\n self.onmessage = null;\n self.onclose = null;\n self.onerror = null;\n self.bufferedAmount = 0;\n self.extensions = '';\n self.binaryType = 'blob';\n self.protocol = 'vite-hmr';\n self.url = originalUrl;\n self._listeners = {};\n self._opened = false;\n\n var sseUrl = location.origin + '/__hmr_sse';\n var sendUrl = location.origin + '/__hmr_send';\n self._sendUrl = sendUrl;\n\n var es = new EventSource(sseUrl);\n self._es = es;\n\n es.onopen = function() {\n if (self._opened) return;\n self._opened = true;\n self.readyState = 1;\n var evt = new Event('open');\n if (self.onopen) self.onopen(evt);\n self._emit('open', evt);\n };\n\n es.onmessage = function(e) {\n var evt = new MessageEvent('message', { data: e.data });\n if (self.onmessage) self.onmessage(evt);\n self._emit('message', evt);\n };\n\n es.onerror = function() {\n // EventSource auto-reconnects on error; don't treat as fatal close\n // Only emit error event, never close event (SSE handles reconnect internally)\n if (self.readyState >= 2) return;\n // EventSource auto-reconnects; no action needed\n };\n }\n\n SseWebSocket.prototype.send = function(data) {\n if (this.readyState !== 1) return;\n fetch(this._sendUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: data\n }).catch(function() {});\n };\n\n SseWebSocket.prototype.close = function() {\n if (this.readyState >= 2) return;\n this.readyState = 3;\n if (this._es) this._es.close();\n var evt = new CloseEvent('close', { code: 1000, reason: '', wasClean: true });\n if (this.onclose) this.onclose(evt);\n this._emit('close', evt);\n };\n\n SseWebSocket.prototype.addEventListener = function(type, fn, options) {\n if (!this._listeners[type]) this._listeners[type] = [];\n var entry = { fn: fn, once: !!(options && options.once) };\n this._listeners[type].push(entry);\n };\n\n SseWebSocket.prototype.removeEventListener = function(type, fn) {\n var list = this._listeners[type];\n if (!list) return;\n this._listeners[type] = list.filter(function(e) { return e.fn !== fn; });\n };\n\n SseWebSocket.prototype.dispatchEvent = function(evt) {\n this._emit(evt.type, evt);\n return true;\n };\n\n SseWebSocket.prototype._emit = function(type, evt) {\n var list = this._listeners[type];\n if (!list) return;\n var remaining = [];\n list.forEach(function(entry) {\n entry.fn(evt);\n if (!entry.once) remaining.push(entry);\n });\n this._listeners[type] = remaining;\n };\n\n function PatchedWebSocket(url, protocols) {\n // Only intercept Vite HMR connections (protocol 'vite-hmr')\n var isViteHmr = protocols === 'vite-hmr'\n || (Array.isArray(protocols) && protocols.indexOf('vite-hmr') !== -1);\n if (!isViteHmr) {\n if (protocols !== undefined) {\n return new OriginalWebSocket(url, protocols);\n }\n return new OriginalWebSocket(url);\n }\n return new SseWebSocket(url);\n }\n\n PatchedWebSocket.CONNECTING = 0;\n PatchedWebSocket.OPEN = 1;\n PatchedWebSocket.CLOSING = 2;\n PatchedWebSocket.CLOSED = 3;\n PatchedWebSocket.prototype = Object.create(OriginalWebSocket.prototype);\n PatchedWebSocket.prototype.constructor = PatchedWebSocket;\n\n window.WebSocket = PatchedWebSocket;\n})();\n";
|
|
9
|
+
|
|
10
|
+
export { hmrSseBridgeClientScript, setupHmrSseBridge };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { ViteDevServer } from 'vite';
|
|
2
|
+
|
|
3
|
+
declare function setupHmrSseBridge(server: ViteDevServer): void;
|
|
4
|
+
/**
|
|
5
|
+
* Client-side script that patches WebSocket to use SSE+fetch on iOS Safari.
|
|
6
|
+
* This script is injected via Vite's transformIndexHtml hook.
|
|
7
|
+
*/
|
|
8
|
+
declare const hmrSseBridgeClientScript = "\n(function() {\n // Activate when served over HTTPS to bypass WSS self-signed cert issues\n if (location.protocol !== 'https:') return;\n\n var OriginalWebSocket = window.WebSocket;\n\n function SseWebSocket(originalUrl) {\n var self = this;\n // WebSocket readyState constants on instance\n self.CONNECTING = 0;\n self.OPEN = 1;\n self.CLOSING = 2;\n self.CLOSED = 3;\n self.readyState = 0;\n self.onopen = null;\n self.onmessage = null;\n self.onclose = null;\n self.onerror = null;\n self.bufferedAmount = 0;\n self.extensions = '';\n self.binaryType = 'blob';\n self.protocol = 'vite-hmr';\n self.url = originalUrl;\n self._listeners = {};\n self._opened = false;\n\n var sseUrl = location.origin + '/__hmr_sse';\n var sendUrl = location.origin + '/__hmr_send';\n self._sendUrl = sendUrl;\n\n var es = new EventSource(sseUrl);\n self._es = es;\n\n es.onopen = function() {\n if (self._opened) return;\n self._opened = true;\n self.readyState = 1;\n var evt = new Event('open');\n if (self.onopen) self.onopen(evt);\n self._emit('open', evt);\n };\n\n es.onmessage = function(e) {\n var evt = new MessageEvent('message', { data: e.data });\n if (self.onmessage) self.onmessage(evt);\n self._emit('message', evt);\n };\n\n es.onerror = function() {\n // EventSource auto-reconnects on error; don't treat as fatal close\n // Only emit error event, never close event (SSE handles reconnect internally)\n if (self.readyState >= 2) return;\n // EventSource auto-reconnects; no action needed\n };\n }\n\n SseWebSocket.prototype.send = function(data) {\n if (this.readyState !== 1) return;\n fetch(this._sendUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: data\n }).catch(function() {});\n };\n\n SseWebSocket.prototype.close = function() {\n if (this.readyState >= 2) return;\n this.readyState = 3;\n if (this._es) this._es.close();\n var evt = new CloseEvent('close', { code: 1000, reason: '', wasClean: true });\n if (this.onclose) this.onclose(evt);\n this._emit('close', evt);\n };\n\n SseWebSocket.prototype.addEventListener = function(type, fn, options) {\n if (!this._listeners[type]) this._listeners[type] = [];\n var entry = { fn: fn, once: !!(options && options.once) };\n this._listeners[type].push(entry);\n };\n\n SseWebSocket.prototype.removeEventListener = function(type, fn) {\n var list = this._listeners[type];\n if (!list) return;\n this._listeners[type] = list.filter(function(e) { return e.fn !== fn; });\n };\n\n SseWebSocket.prototype.dispatchEvent = function(evt) {\n this._emit(evt.type, evt);\n return true;\n };\n\n SseWebSocket.prototype._emit = function(type, evt) {\n var list = this._listeners[type];\n if (!list) return;\n var remaining = [];\n list.forEach(function(entry) {\n entry.fn(evt);\n if (!entry.once) remaining.push(entry);\n });\n this._listeners[type] = remaining;\n };\n\n function PatchedWebSocket(url, protocols) {\n // Only intercept Vite HMR connections (protocol 'vite-hmr')\n var isViteHmr = protocols === 'vite-hmr'\n || (Array.isArray(protocols) && protocols.indexOf('vite-hmr') !== -1);\n if (!isViteHmr) {\n if (protocols !== undefined) {\n return new OriginalWebSocket(url, protocols);\n }\n return new OriginalWebSocket(url);\n }\n return new SseWebSocket(url);\n }\n\n PatchedWebSocket.CONNECTING = 0;\n PatchedWebSocket.OPEN = 1;\n PatchedWebSocket.CLOSING = 2;\n PatchedWebSocket.CLOSED = 3;\n PatchedWebSocket.prototype = Object.create(OriginalWebSocket.prototype);\n PatchedWebSocket.prototype.constructor = PatchedWebSocket;\n\n window.WebSocket = PatchedWebSocket;\n})();\n";
|
|
9
|
+
|
|
10
|
+
export { hmrSseBridgeClientScript, setupHmrSseBridge };
|
package/dist/index.cjs
CHANGED
|
@@ -13859,6 +13859,17 @@ function getCaddyConfig() {
|
|
|
13859
13859
|
}
|
|
13860
13860
|
return caddyConfig;
|
|
13861
13861
|
}
|
|
13862
|
+
function splitHostPort(addr) {
|
|
13863
|
+
const lastColon = addr.lastIndexOf(":");
|
|
13864
|
+
if (lastColon === -1)
|
|
13865
|
+
return { host: addr, port: "" };
|
|
13866
|
+
if (addr.startsWith("[")) {
|
|
13867
|
+
const end = addr.indexOf("]");
|
|
13868
|
+
if (end !== -1 && addr[end + 1] === ":")
|
|
13869
|
+
return { host: addr.slice(1, end), port: addr.slice(end + 2) };
|
|
13870
|
+
}
|
|
13871
|
+
return { host: addr.slice(0, lastColon), port: addr.slice(lastColon + 1) };
|
|
13872
|
+
}
|
|
13862
13873
|
var CaddyInstant = class {
|
|
13863
13874
|
constructor() {
|
|
13864
13875
|
this.inited = false;
|
|
@@ -13906,6 +13917,7 @@ var CaddyInstant = class {
|
|
|
13906
13917
|
*/
|
|
13907
13918
|
async run(source, target, options) {
|
|
13908
13919
|
source = source.replace("0.0.0.0", "127.0.0.1");
|
|
13920
|
+
source = source.replace(/^localhost(?=:)/i, "127.0.0.1");
|
|
13909
13921
|
const {
|
|
13910
13922
|
restore = true,
|
|
13911
13923
|
base = "/",
|
|
@@ -13917,10 +13929,11 @@ var CaddyInstant = class {
|
|
|
13917
13929
|
this._target = target;
|
|
13918
13930
|
if (!this.inited)
|
|
13919
13931
|
await this.init();
|
|
13920
|
-
|
|
13932
|
+
const sourceHost = splitHostPort(source).host;
|
|
13933
|
+
const targetHost = splitHostPort(target).host;
|
|
13934
|
+
if (!await addHost(sourceHost, targetHost))
|
|
13921
13935
|
throw new Error("update host failed");
|
|
13922
13936
|
consola.success("update host success\n");
|
|
13923
|
-
const targetHost = target.split(":")[0];
|
|
13924
13937
|
const normalizeBase = (b) => {
|
|
13925
13938
|
let out = b || "/";
|
|
13926
13939
|
if (!out.startsWith("/"))
|
|
@@ -13980,7 +13993,7 @@ var CaddyInstant = class {
|
|
|
13980
13993
|
});
|
|
13981
13994
|
const originalExit = import_node_process4.default.exit.bind(import_node_process4.default);
|
|
13982
13995
|
import_node_process4.default.exit = async (code) => {
|
|
13983
|
-
const port = Number(source.
|
|
13996
|
+
const port = Number(splitHostPort(source).port);
|
|
13984
13997
|
if (!Number.isNaN(port) && await tryPort(port))
|
|
13985
13998
|
await kill(port);
|
|
13986
13999
|
const pwd = import_node_process4.default.cwd();
|
|
@@ -13988,6 +14001,10 @@ var CaddyInstant = class {
|
|
|
13988
14001
|
if ((0, import_node_fs3.existsSync)(viteCacheDir))
|
|
13989
14002
|
await chmodRecursive(viteCacheDir, 511).catch(() => {
|
|
13990
14003
|
});
|
|
14004
|
+
const viteTempCacheDir = `${pwd}/node_modules/.vite-temp`;
|
|
14005
|
+
if ((0, import_node_fs3.existsSync)(viteTempCacheDir))
|
|
14006
|
+
await chmodRecursive(viteTempCacheDir, 511).catch(() => {
|
|
14007
|
+
});
|
|
13991
14008
|
const nuxtCacheDir = `${pwd}/.nuxt`;
|
|
13992
14009
|
if ((0, import_node_fs3.existsSync)(nuxtCacheDir))
|
|
13993
14010
|
await chmodRecursive(nuxtCacheDir, 511).catch(() => {
|
|
@@ -14059,7 +14076,7 @@ ${line}
|
|
|
14059
14076
|
this._stopEffects.forEach((fn) => fn());
|
|
14060
14077
|
try {
|
|
14061
14078
|
if (restore && this._source && this._target) {
|
|
14062
|
-
if (await removeHost(this._source.
|
|
14079
|
+
if (await removeHost(splitHostPort(this._source).host, splitHostPort(this._target).host))
|
|
14063
14080
|
consola.success("Restore host success.\n");
|
|
14064
14081
|
else
|
|
14065
14082
|
consola.fail("Restore host failed.\n");
|
|
@@ -14087,9 +14104,238 @@ ${line}
|
|
|
14087
14104
|
}
|
|
14088
14105
|
};
|
|
14089
14106
|
|
|
14107
|
+
// src/hmr-sse-bridge.ts
|
|
14108
|
+
var SSE_PATH = "/__hmr_sse";
|
|
14109
|
+
var SEND_PATH = "/__hmr_send";
|
|
14110
|
+
var MAX_POST_BODY = 64 * 1024;
|
|
14111
|
+
function setupHmrSseBridge(server) {
|
|
14112
|
+
const sseClients = /* @__PURE__ */ new Set();
|
|
14113
|
+
const originalSend = server.ws.send.bind(server.ws);
|
|
14114
|
+
server.ws.send = (...args2) => {
|
|
14115
|
+
;
|
|
14116
|
+
originalSend(...args2);
|
|
14117
|
+
let payload;
|
|
14118
|
+
if (typeof args2[0] === "string") {
|
|
14119
|
+
payload = JSON.stringify({ type: "custom", event: args2[0], data: args2[1] });
|
|
14120
|
+
} else {
|
|
14121
|
+
payload = JSON.stringify(args2[0]);
|
|
14122
|
+
}
|
|
14123
|
+
for (const res of sseClients) {
|
|
14124
|
+
try {
|
|
14125
|
+
res.write(`data: ${payload}
|
|
14126
|
+
|
|
14127
|
+
`);
|
|
14128
|
+
} catch {
|
|
14129
|
+
sseClients.delete(res);
|
|
14130
|
+
}
|
|
14131
|
+
}
|
|
14132
|
+
};
|
|
14133
|
+
server.middlewares.use((req, res, next2) => {
|
|
14134
|
+
var _a4;
|
|
14135
|
+
const url2 = (_a4 = req.url) == null ? void 0 : _a4.split("?")[0];
|
|
14136
|
+
if (url2 === SSE_PATH && req.method === "GET") {
|
|
14137
|
+
handleSseConnection(req, res, sseClients);
|
|
14138
|
+
return;
|
|
14139
|
+
}
|
|
14140
|
+
if (url2 === SEND_PATH && req.method === "POST") {
|
|
14141
|
+
handleClientMessage(req, res, server);
|
|
14142
|
+
return;
|
|
14143
|
+
}
|
|
14144
|
+
next2();
|
|
14145
|
+
});
|
|
14146
|
+
}
|
|
14147
|
+
function handleSseConnection(_req, res, sseClients) {
|
|
14148
|
+
res.writeHead(200, {
|
|
14149
|
+
"Content-Type": "text/event-stream",
|
|
14150
|
+
"Cache-Control": "no-cache",
|
|
14151
|
+
"Connection": "keep-alive"
|
|
14152
|
+
});
|
|
14153
|
+
res.write(`data: ${JSON.stringify({ type: "connected" })}
|
|
14154
|
+
|
|
14155
|
+
`);
|
|
14156
|
+
sseClients.add(res);
|
|
14157
|
+
const keepAlive = setInterval(() => {
|
|
14158
|
+
try {
|
|
14159
|
+
res.write(": ping\n\n");
|
|
14160
|
+
} catch {
|
|
14161
|
+
cleanup();
|
|
14162
|
+
}
|
|
14163
|
+
}, 3e4);
|
|
14164
|
+
function cleanup() {
|
|
14165
|
+
clearInterval(keepAlive);
|
|
14166
|
+
sseClients.delete(res);
|
|
14167
|
+
}
|
|
14168
|
+
res.on("close", cleanup);
|
|
14169
|
+
res.on("error", cleanup);
|
|
14170
|
+
}
|
|
14171
|
+
function handleClientMessage(req, res, server) {
|
|
14172
|
+
let body = "";
|
|
14173
|
+
let overflow = false;
|
|
14174
|
+
req.on("data", (chunk) => {
|
|
14175
|
+
body += chunk.toString();
|
|
14176
|
+
if (body.length > MAX_POST_BODY) {
|
|
14177
|
+
overflow = true;
|
|
14178
|
+
req.destroy();
|
|
14179
|
+
}
|
|
14180
|
+
});
|
|
14181
|
+
req.on("end", () => {
|
|
14182
|
+
var _a4, _b3, _c2, _d2, _e;
|
|
14183
|
+
if (overflow) {
|
|
14184
|
+
res.writeHead(413);
|
|
14185
|
+
res.end('{"ok":false}');
|
|
14186
|
+
return;
|
|
14187
|
+
}
|
|
14188
|
+
try {
|
|
14189
|
+
const data = JSON.parse(body);
|
|
14190
|
+
if (data.type === "custom" && data.event) {
|
|
14191
|
+
const dummyClient = {
|
|
14192
|
+
send: (...args2) => {
|
|
14193
|
+
server.ws.send(...args2);
|
|
14194
|
+
}
|
|
14195
|
+
};
|
|
14196
|
+
(_e = (_d2 = (_c2 = (_b3 = (_a4 = server.environments) == null ? void 0 : _a4.client) == null ? void 0 : _b3.hot) == null ? void 0 : _c2.api) == null ? void 0 : _d2.emit) == null ? void 0 : _e.call(_d2, data.event, data.data, dummyClient);
|
|
14197
|
+
}
|
|
14198
|
+
res.writeHead(200, {
|
|
14199
|
+
"Content-Type": "application/json"
|
|
14200
|
+
});
|
|
14201
|
+
res.end('{"ok":true}');
|
|
14202
|
+
} catch {
|
|
14203
|
+
res.writeHead(400);
|
|
14204
|
+
res.end('{"ok":false}');
|
|
14205
|
+
}
|
|
14206
|
+
});
|
|
14207
|
+
}
|
|
14208
|
+
var hmrSseBridgeClientScript = `
|
|
14209
|
+
(function() {
|
|
14210
|
+
// Activate when served over HTTPS to bypass WSS self-signed cert issues
|
|
14211
|
+
if (location.protocol !== 'https:') return;
|
|
14212
|
+
|
|
14213
|
+
var OriginalWebSocket = window.WebSocket;
|
|
14214
|
+
|
|
14215
|
+
function SseWebSocket(originalUrl) {
|
|
14216
|
+
var self = this;
|
|
14217
|
+
// WebSocket readyState constants on instance
|
|
14218
|
+
self.CONNECTING = 0;
|
|
14219
|
+
self.OPEN = 1;
|
|
14220
|
+
self.CLOSING = 2;
|
|
14221
|
+
self.CLOSED = 3;
|
|
14222
|
+
self.readyState = 0;
|
|
14223
|
+
self.onopen = null;
|
|
14224
|
+
self.onmessage = null;
|
|
14225
|
+
self.onclose = null;
|
|
14226
|
+
self.onerror = null;
|
|
14227
|
+
self.bufferedAmount = 0;
|
|
14228
|
+
self.extensions = '';
|
|
14229
|
+
self.binaryType = 'blob';
|
|
14230
|
+
self.protocol = 'vite-hmr';
|
|
14231
|
+
self.url = originalUrl;
|
|
14232
|
+
self._listeners = {};
|
|
14233
|
+
self._opened = false;
|
|
14234
|
+
|
|
14235
|
+
var sseUrl = location.origin + '${SSE_PATH}';
|
|
14236
|
+
var sendUrl = location.origin + '${SEND_PATH}';
|
|
14237
|
+
self._sendUrl = sendUrl;
|
|
14238
|
+
|
|
14239
|
+
var es = new EventSource(sseUrl);
|
|
14240
|
+
self._es = es;
|
|
14241
|
+
|
|
14242
|
+
es.onopen = function() {
|
|
14243
|
+
if (self._opened) return;
|
|
14244
|
+
self._opened = true;
|
|
14245
|
+
self.readyState = 1;
|
|
14246
|
+
var evt = new Event('open');
|
|
14247
|
+
if (self.onopen) self.onopen(evt);
|
|
14248
|
+
self._emit('open', evt);
|
|
14249
|
+
};
|
|
14250
|
+
|
|
14251
|
+
es.onmessage = function(e) {
|
|
14252
|
+
var evt = new MessageEvent('message', { data: e.data });
|
|
14253
|
+
if (self.onmessage) self.onmessage(evt);
|
|
14254
|
+
self._emit('message', evt);
|
|
14255
|
+
};
|
|
14256
|
+
|
|
14257
|
+
es.onerror = function() {
|
|
14258
|
+
// EventSource auto-reconnects on error; don't treat as fatal close
|
|
14259
|
+
// Only emit error event, never close event (SSE handles reconnect internally)
|
|
14260
|
+
if (self.readyState >= 2) return;
|
|
14261
|
+
// EventSource auto-reconnects; no action needed
|
|
14262
|
+
};
|
|
14263
|
+
}
|
|
14264
|
+
|
|
14265
|
+
SseWebSocket.prototype.send = function(data) {
|
|
14266
|
+
if (this.readyState !== 1) return;
|
|
14267
|
+
fetch(this._sendUrl, {
|
|
14268
|
+
method: 'POST',
|
|
14269
|
+
headers: { 'Content-Type': 'application/json' },
|
|
14270
|
+
body: data
|
|
14271
|
+
}).catch(function() {});
|
|
14272
|
+
};
|
|
14273
|
+
|
|
14274
|
+
SseWebSocket.prototype.close = function() {
|
|
14275
|
+
if (this.readyState >= 2) return;
|
|
14276
|
+
this.readyState = 3;
|
|
14277
|
+
if (this._es) this._es.close();
|
|
14278
|
+
var evt = new CloseEvent('close', { code: 1000, reason: '', wasClean: true });
|
|
14279
|
+
if (this.onclose) this.onclose(evt);
|
|
14280
|
+
this._emit('close', evt);
|
|
14281
|
+
};
|
|
14282
|
+
|
|
14283
|
+
SseWebSocket.prototype.addEventListener = function(type, fn, options) {
|
|
14284
|
+
if (!this._listeners[type]) this._listeners[type] = [];
|
|
14285
|
+
var entry = { fn: fn, once: !!(options && options.once) };
|
|
14286
|
+
this._listeners[type].push(entry);
|
|
14287
|
+
};
|
|
14288
|
+
|
|
14289
|
+
SseWebSocket.prototype.removeEventListener = function(type, fn) {
|
|
14290
|
+
var list = this._listeners[type];
|
|
14291
|
+
if (!list) return;
|
|
14292
|
+
this._listeners[type] = list.filter(function(e) { return e.fn !== fn; });
|
|
14293
|
+
};
|
|
14294
|
+
|
|
14295
|
+
SseWebSocket.prototype.dispatchEvent = function(evt) {
|
|
14296
|
+
this._emit(evt.type, evt);
|
|
14297
|
+
return true;
|
|
14298
|
+
};
|
|
14299
|
+
|
|
14300
|
+
SseWebSocket.prototype._emit = function(type, evt) {
|
|
14301
|
+
var list = this._listeners[type];
|
|
14302
|
+
if (!list) return;
|
|
14303
|
+
var remaining = [];
|
|
14304
|
+
list.forEach(function(entry) {
|
|
14305
|
+
entry.fn(evt);
|
|
14306
|
+
if (!entry.once) remaining.push(entry);
|
|
14307
|
+
});
|
|
14308
|
+
this._listeners[type] = remaining;
|
|
14309
|
+
};
|
|
14310
|
+
|
|
14311
|
+
function PatchedWebSocket(url, protocols) {
|
|
14312
|
+
// Only intercept Vite HMR connections (protocol 'vite-hmr')
|
|
14313
|
+
var isViteHmr = protocols === 'vite-hmr'
|
|
14314
|
+
|| (Array.isArray(protocols) && protocols.indexOf('vite-hmr') !== -1);
|
|
14315
|
+
if (!isViteHmr) {
|
|
14316
|
+
if (protocols !== undefined) {
|
|
14317
|
+
return new OriginalWebSocket(url, protocols);
|
|
14318
|
+
}
|
|
14319
|
+
return new OriginalWebSocket(url);
|
|
14320
|
+
}
|
|
14321
|
+
return new SseWebSocket(url);
|
|
14322
|
+
}
|
|
14323
|
+
|
|
14324
|
+
PatchedWebSocket.CONNECTING = 0;
|
|
14325
|
+
PatchedWebSocket.OPEN = 1;
|
|
14326
|
+
PatchedWebSocket.CLOSING = 2;
|
|
14327
|
+
PatchedWebSocket.CLOSED = 3;
|
|
14328
|
+
PatchedWebSocket.prototype = Object.create(OriginalWebSocket.prototype);
|
|
14329
|
+
PatchedWebSocket.prototype.constructor = PatchedWebSocket;
|
|
14330
|
+
|
|
14331
|
+
window.WebSocket = PatchedWebSocket;
|
|
14332
|
+
})();
|
|
14333
|
+
`;
|
|
14334
|
+
|
|
14090
14335
|
// src/index.ts
|
|
14091
14336
|
var config;
|
|
14092
14337
|
var caddy;
|
|
14338
|
+
var hmrSseBridgeActive = false;
|
|
14093
14339
|
var cwd = import_node_process5.default.cwd();
|
|
14094
14340
|
function colorUrl(url2) {
|
|
14095
14341
|
return import_picocolors2.default.green(url2.replace(/:(\d+)\//, (_, port) => `:${import_picocolors2.default.bold(port)}/`));
|
|
@@ -14176,6 +14422,20 @@ var unpluginFactory = (options) => ({
|
|
|
14176
14422
|
}
|
|
14177
14423
|
const base = server.config.base || "/";
|
|
14178
14424
|
server.printUrls = () => vitePrintUrls(options, source, target, base, _printUrls);
|
|
14425
|
+
if (options.https) {
|
|
14426
|
+
setupHmrSseBridge(server);
|
|
14427
|
+
hmrSseBridgeActive = true;
|
|
14428
|
+
consola.info("HMR SSE bridge enabled for iOS Safari WSS workaround");
|
|
14429
|
+
}
|
|
14430
|
+
},
|
|
14431
|
+
transformIndexHtml() {
|
|
14432
|
+
if (!hmrSseBridgeActive)
|
|
14433
|
+
return [];
|
|
14434
|
+
return [{
|
|
14435
|
+
tag: "script",
|
|
14436
|
+
children: hmrSseBridgeClientScript,
|
|
14437
|
+
injectTo: "head-prepend"
|
|
14438
|
+
}];
|
|
14179
14439
|
}
|
|
14180
14440
|
},
|
|
14181
14441
|
webpack(compiler) {
|