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/rspack.cjs CHANGED
@@ -13858,6 +13858,17 @@ function getCaddyConfig() {
13858
13858
  }
13859
13859
  return caddyConfig;
13860
13860
  }
13861
+ function splitHostPort(addr) {
13862
+ const lastColon = addr.lastIndexOf(":");
13863
+ if (lastColon === -1)
13864
+ return { host: addr, port: "" };
13865
+ if (addr.startsWith("[")) {
13866
+ const end = addr.indexOf("]");
13867
+ if (end !== -1 && addr[end + 1] === ":")
13868
+ return { host: addr.slice(1, end), port: addr.slice(end + 2) };
13869
+ }
13870
+ return { host: addr.slice(0, lastColon), port: addr.slice(lastColon + 1) };
13871
+ }
13861
13872
  var CaddyInstant = class {
13862
13873
  constructor() {
13863
13874
  this.inited = false;
@@ -13905,6 +13916,7 @@ var CaddyInstant = class {
13905
13916
  */
13906
13917
  async run(source, target, options) {
13907
13918
  source = source.replace("0.0.0.0", "127.0.0.1");
13919
+ source = source.replace(/^localhost(?=:)/i, "127.0.0.1");
13908
13920
  const {
13909
13921
  restore = true,
13910
13922
  base = "/",
@@ -13916,10 +13928,11 @@ var CaddyInstant = class {
13916
13928
  this._target = target;
13917
13929
  if (!this.inited)
13918
13930
  await this.init();
13919
- if (!await addHost(source.split(":")[0], target.split(":")[0]))
13931
+ const sourceHost = splitHostPort(source).host;
13932
+ const targetHost = splitHostPort(target).host;
13933
+ if (!await addHost(sourceHost, targetHost))
13920
13934
  throw new Error("update host failed");
13921
13935
  consola.success("update host success\n");
13922
- const targetHost = target.split(":")[0];
13923
13936
  const normalizeBase = (b) => {
13924
13937
  let out = b || "/";
13925
13938
  if (!out.startsWith("/"))
@@ -13979,7 +13992,7 @@ var CaddyInstant = class {
13979
13992
  });
13980
13993
  const originalExit = import_node_process4.default.exit.bind(import_node_process4.default);
13981
13994
  import_node_process4.default.exit = async (code) => {
13982
- const port = Number(source.split(":")[1]);
13995
+ const port = Number(splitHostPort(source).port);
13983
13996
  if (!Number.isNaN(port) && await tryPort(port))
13984
13997
  await kill(port);
13985
13998
  const pwd = import_node_process4.default.cwd();
@@ -13987,6 +14000,10 @@ var CaddyInstant = class {
13987
14000
  if ((0, import_node_fs3.existsSync)(viteCacheDir))
13988
14001
  await chmodRecursive(viteCacheDir, 511).catch(() => {
13989
14002
  });
14003
+ const viteTempCacheDir = `${pwd}/node_modules/.vite-temp`;
14004
+ if ((0, import_node_fs3.existsSync)(viteTempCacheDir))
14005
+ await chmodRecursive(viteTempCacheDir, 511).catch(() => {
14006
+ });
13990
14007
  const nuxtCacheDir = `${pwd}/.nuxt`;
13991
14008
  if ((0, import_node_fs3.existsSync)(nuxtCacheDir))
13992
14009
  await chmodRecursive(nuxtCacheDir, 511).catch(() => {
@@ -14058,7 +14075,7 @@ ${line}
14058
14075
  this._stopEffects.forEach((fn) => fn());
14059
14076
  try {
14060
14077
  if (restore && this._source && this._target) {
14061
- if (await removeHost(this._source.split(":")[0], this._target.split(":")[0]))
14078
+ if (await removeHost(splitHostPort(this._source).host, splitHostPort(this._target).host))
14062
14079
  consola.success("Restore host success.\n");
14063
14080
  else
14064
14081
  consola.fail("Restore host failed.\n");
@@ -14086,9 +14103,238 @@ ${line}
14086
14103
  }
14087
14104
  };
14088
14105
 
14106
+ // src/hmr-sse-bridge.ts
14107
+ var SSE_PATH = "/__hmr_sse";
14108
+ var SEND_PATH = "/__hmr_send";
14109
+ var MAX_POST_BODY = 64 * 1024;
14110
+ function setupHmrSseBridge(server) {
14111
+ const sseClients = /* @__PURE__ */ new Set();
14112
+ const originalSend = server.ws.send.bind(server.ws);
14113
+ server.ws.send = (...args2) => {
14114
+ ;
14115
+ originalSend(...args2);
14116
+ let payload;
14117
+ if (typeof args2[0] === "string") {
14118
+ payload = JSON.stringify({ type: "custom", event: args2[0], data: args2[1] });
14119
+ } else {
14120
+ payload = JSON.stringify(args2[0]);
14121
+ }
14122
+ for (const res of sseClients) {
14123
+ try {
14124
+ res.write(`data: ${payload}
14125
+
14126
+ `);
14127
+ } catch {
14128
+ sseClients.delete(res);
14129
+ }
14130
+ }
14131
+ };
14132
+ server.middlewares.use((req, res, next2) => {
14133
+ var _a4;
14134
+ const url2 = (_a4 = req.url) == null ? void 0 : _a4.split("?")[0];
14135
+ if (url2 === SSE_PATH && req.method === "GET") {
14136
+ handleSseConnection(req, res, sseClients);
14137
+ return;
14138
+ }
14139
+ if (url2 === SEND_PATH && req.method === "POST") {
14140
+ handleClientMessage(req, res, server);
14141
+ return;
14142
+ }
14143
+ next2();
14144
+ });
14145
+ }
14146
+ function handleSseConnection(_req, res, sseClients) {
14147
+ res.writeHead(200, {
14148
+ "Content-Type": "text/event-stream",
14149
+ "Cache-Control": "no-cache",
14150
+ "Connection": "keep-alive"
14151
+ });
14152
+ res.write(`data: ${JSON.stringify({ type: "connected" })}
14153
+
14154
+ `);
14155
+ sseClients.add(res);
14156
+ const keepAlive = setInterval(() => {
14157
+ try {
14158
+ res.write(": ping\n\n");
14159
+ } catch {
14160
+ cleanup();
14161
+ }
14162
+ }, 3e4);
14163
+ function cleanup() {
14164
+ clearInterval(keepAlive);
14165
+ sseClients.delete(res);
14166
+ }
14167
+ res.on("close", cleanup);
14168
+ res.on("error", cleanup);
14169
+ }
14170
+ function handleClientMessage(req, res, server) {
14171
+ let body = "";
14172
+ let overflow = false;
14173
+ req.on("data", (chunk) => {
14174
+ body += chunk.toString();
14175
+ if (body.length > MAX_POST_BODY) {
14176
+ overflow = true;
14177
+ req.destroy();
14178
+ }
14179
+ });
14180
+ req.on("end", () => {
14181
+ var _a4, _b3, _c2, _d2, _e;
14182
+ if (overflow) {
14183
+ res.writeHead(413);
14184
+ res.end('{"ok":false}');
14185
+ return;
14186
+ }
14187
+ try {
14188
+ const data = JSON.parse(body);
14189
+ if (data.type === "custom" && data.event) {
14190
+ const dummyClient = {
14191
+ send: (...args2) => {
14192
+ server.ws.send(...args2);
14193
+ }
14194
+ };
14195
+ (_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);
14196
+ }
14197
+ res.writeHead(200, {
14198
+ "Content-Type": "application/json"
14199
+ });
14200
+ res.end('{"ok":true}');
14201
+ } catch {
14202
+ res.writeHead(400);
14203
+ res.end('{"ok":false}');
14204
+ }
14205
+ });
14206
+ }
14207
+ var hmrSseBridgeClientScript = `
14208
+ (function() {
14209
+ // Activate when served over HTTPS to bypass WSS self-signed cert issues
14210
+ if (location.protocol !== 'https:') return;
14211
+
14212
+ var OriginalWebSocket = window.WebSocket;
14213
+
14214
+ function SseWebSocket(originalUrl) {
14215
+ var self = this;
14216
+ // WebSocket readyState constants on instance
14217
+ self.CONNECTING = 0;
14218
+ self.OPEN = 1;
14219
+ self.CLOSING = 2;
14220
+ self.CLOSED = 3;
14221
+ self.readyState = 0;
14222
+ self.onopen = null;
14223
+ self.onmessage = null;
14224
+ self.onclose = null;
14225
+ self.onerror = null;
14226
+ self.bufferedAmount = 0;
14227
+ self.extensions = '';
14228
+ self.binaryType = 'blob';
14229
+ self.protocol = 'vite-hmr';
14230
+ self.url = originalUrl;
14231
+ self._listeners = {};
14232
+ self._opened = false;
14233
+
14234
+ var sseUrl = location.origin + '${SSE_PATH}';
14235
+ var sendUrl = location.origin + '${SEND_PATH}';
14236
+ self._sendUrl = sendUrl;
14237
+
14238
+ var es = new EventSource(sseUrl);
14239
+ self._es = es;
14240
+
14241
+ es.onopen = function() {
14242
+ if (self._opened) return;
14243
+ self._opened = true;
14244
+ self.readyState = 1;
14245
+ var evt = new Event('open');
14246
+ if (self.onopen) self.onopen(evt);
14247
+ self._emit('open', evt);
14248
+ };
14249
+
14250
+ es.onmessage = function(e) {
14251
+ var evt = new MessageEvent('message', { data: e.data });
14252
+ if (self.onmessage) self.onmessage(evt);
14253
+ self._emit('message', evt);
14254
+ };
14255
+
14256
+ es.onerror = function() {
14257
+ // EventSource auto-reconnects on error; don't treat as fatal close
14258
+ // Only emit error event, never close event (SSE handles reconnect internally)
14259
+ if (self.readyState >= 2) return;
14260
+ // EventSource auto-reconnects; no action needed
14261
+ };
14262
+ }
14263
+
14264
+ SseWebSocket.prototype.send = function(data) {
14265
+ if (this.readyState !== 1) return;
14266
+ fetch(this._sendUrl, {
14267
+ method: 'POST',
14268
+ headers: { 'Content-Type': 'application/json' },
14269
+ body: data
14270
+ }).catch(function() {});
14271
+ };
14272
+
14273
+ SseWebSocket.prototype.close = function() {
14274
+ if (this.readyState >= 2) return;
14275
+ this.readyState = 3;
14276
+ if (this._es) this._es.close();
14277
+ var evt = new CloseEvent('close', { code: 1000, reason: '', wasClean: true });
14278
+ if (this.onclose) this.onclose(evt);
14279
+ this._emit('close', evt);
14280
+ };
14281
+
14282
+ SseWebSocket.prototype.addEventListener = function(type, fn, options) {
14283
+ if (!this._listeners[type]) this._listeners[type] = [];
14284
+ var entry = { fn: fn, once: !!(options && options.once) };
14285
+ this._listeners[type].push(entry);
14286
+ };
14287
+
14288
+ SseWebSocket.prototype.removeEventListener = function(type, fn) {
14289
+ var list = this._listeners[type];
14290
+ if (!list) return;
14291
+ this._listeners[type] = list.filter(function(e) { return e.fn !== fn; });
14292
+ };
14293
+
14294
+ SseWebSocket.prototype.dispatchEvent = function(evt) {
14295
+ this._emit(evt.type, evt);
14296
+ return true;
14297
+ };
14298
+
14299
+ SseWebSocket.prototype._emit = function(type, evt) {
14300
+ var list = this._listeners[type];
14301
+ if (!list) return;
14302
+ var remaining = [];
14303
+ list.forEach(function(entry) {
14304
+ entry.fn(evt);
14305
+ if (!entry.once) remaining.push(entry);
14306
+ });
14307
+ this._listeners[type] = remaining;
14308
+ };
14309
+
14310
+ function PatchedWebSocket(url, protocols) {
14311
+ // Only intercept Vite HMR connections (protocol 'vite-hmr')
14312
+ var isViteHmr = protocols === 'vite-hmr'
14313
+ || (Array.isArray(protocols) && protocols.indexOf('vite-hmr') !== -1);
14314
+ if (!isViteHmr) {
14315
+ if (protocols !== undefined) {
14316
+ return new OriginalWebSocket(url, protocols);
14317
+ }
14318
+ return new OriginalWebSocket(url);
14319
+ }
14320
+ return new SseWebSocket(url);
14321
+ }
14322
+
14323
+ PatchedWebSocket.CONNECTING = 0;
14324
+ PatchedWebSocket.OPEN = 1;
14325
+ PatchedWebSocket.CLOSING = 2;
14326
+ PatchedWebSocket.CLOSED = 3;
14327
+ PatchedWebSocket.prototype = Object.create(OriginalWebSocket.prototype);
14328
+ PatchedWebSocket.prototype.constructor = PatchedWebSocket;
14329
+
14330
+ window.WebSocket = PatchedWebSocket;
14331
+ })();
14332
+ `;
14333
+
14089
14334
  // src/index.ts
14090
14335
  var config;
14091
14336
  var caddy;
14337
+ var hmrSseBridgeActive = false;
14092
14338
  var cwd = import_node_process5.default.cwd();
14093
14339
  function colorUrl(url2) {
14094
14340
  return import_picocolors2.default.green(url2.replace(/:(\d+)\//, (_, port) => `:${import_picocolors2.default.bold(port)}/`));
@@ -14175,6 +14421,20 @@ var unpluginFactory = (options) => ({
14175
14421
  }
14176
14422
  const base = server.config.base || "/";
14177
14423
  server.printUrls = () => vitePrintUrls(options, source, target, base, _printUrls);
14424
+ if (options.https) {
14425
+ setupHmrSseBridge(server);
14426
+ hmrSseBridgeActive = true;
14427
+ consola.info("HMR SSE bridge enabled for iOS Safari WSS workaround");
14428
+ }
14429
+ },
14430
+ transformIndexHtml() {
14431
+ if (!hmrSseBridgeActive)
14432
+ return [];
14433
+ return [{
14434
+ tag: "script",
14435
+ children: hmrSseBridgeClientScript,
14436
+ injectTo: "head-prepend"
14437
+ }];
14178
14438
  }
14179
14439
  },
14180
14440
  webpack(compiler) {
package/dist/rspack.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import {
2
2
  src_default
3
- } from "./chunk-K7HSLE6X.js";
3
+ } from "./chunk-JA3D5AWS.js";
4
+ import "./chunk-RSBXFJ3Z.js";
4
5
  import "./chunk-2P7SUCQ3.js";
5
6
 
6
7
  // src/rspack.ts
package/dist/vite.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
- if (!await addHost(source.split(":")[0], target.split(":")[0]))
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.split(":")[1]);
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.split(":")[0], this._target.split(":")[0]))
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) {
package/dist/vite.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import {
2
2
  unpluginFactory
3
- } from "./chunk-K7HSLE6X.js";
3
+ } from "./chunk-JA3D5AWS.js";
4
+ import "./chunk-RSBXFJ3Z.js";
4
5
  import "./chunk-2P7SUCQ3.js";
5
6
 
6
7
  // src/vite.ts