vite-plugin-phpsandbox 0.1.1 → 0.2.0

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
@@ -23,18 +23,6 @@ export default defineConfig({
23
23
 
24
24
  The plugin only applies when `PHPSANDBOX_TYPE` is set.
25
25
 
26
- ## Options
27
-
28
- ```ts
29
- type PhpSandboxOptions = {
30
- allowedHosts?: true | string[];
31
- enabled?: boolean;
32
- hmrPort?: number;
33
- publicHost?: string;
34
- publicClientPort?: number;
35
- };
36
- ```
37
-
38
26
  ## Environment Variables
39
27
 
40
28
  The plugin reads these environment variables by default:
@@ -46,14 +34,16 @@ The plugin reads these environment variables by default:
46
34
  ## Behavior
47
35
 
48
36
  - Does nothing unless `PHPSANDBOX_TYPE` is set.
49
- - Resolves the HMR port from the `hmrPort` option only.
50
- - Resolves the public host from `publicHost`, or derives `${SUBDOMAIN}-${hmrPort}.${NOTEBOOK_HOST}`.
51
- - Resolves the public client port from the `publicClientPort` option only.
37
+ - Uses `5173` as the stable HMR port.
38
+ - Derives the public host as `${SUBDOMAIN}-5173.${NOTEBOOK_HOST}` when both values exist.
39
+ - Uses `443` as the public HMR client port.
52
40
  - Defaults `server.host` to `true` only when the project has not set `server.host`.
53
- - Merges `.${NOTEBOOK_HOST}` and the derived public host into `server.allowedHosts` by default instead of disabling host checks globally.
54
- - Creates a stable local HMR server on `0.0.0.0:${hmrPort}` unless `PHPSANDBOX_TYPE=laravel`.
41
+ - Adds `.${NOTEBOOK_HOST}` and the derived public host to `server.allowedHosts` unless the project has set `server.allowedHosts = true`.
42
+ - Creates a stable local HMR server on `0.0.0.0:5173` unless `PHPSANDBOX_TYPE=laravel`.
43
+ - Fails startup if the local HMR server cannot bind to `0.0.0.0:5173`.
55
44
  - Advertises HMR over `wss://${publicHost}:${publicClientPort}` when a public host is available.
56
45
  - Preserves `server.hmr = false` if the consuming project disables HMR explicitly.
46
+ - Logs the resolved sandbox type, host, HMR endpoint, and allowed hosts after config resolution.
57
47
 
58
48
  ## Laravel Mode
59
49
 
@@ -62,9 +52,5 @@ When `PHPSANDBOX_TYPE=laravel`, the plugin does not create a standalone HMR serv
62
52
  ## API
63
53
 
64
54
  ```ts
65
- import phpSandboxPlugin, {
66
- phpSandbox,
67
- type PhpSandboxEnv,
68
- type PhpSandboxOptions,
69
- } from "vite-plugin-phpsandbox";
55
+ import phpSandboxPlugin, { phpSandbox } from "vite-plugin-phpsandbox";
70
56
  ```
package/dist/index.cjs CHANGED
@@ -36,8 +36,8 @@ __export(index_exports, {
36
36
  });
37
37
  module.exports = __toCommonJS(index_exports);
38
38
  var import_node_http = __toESM(require("http"), 1);
39
- var DEFAULT_HMR_PORT = 5173;
40
- var DEFAULT_PUBLIC_CLIENT_PORT = 443;
39
+ var HMR_PORT = 5173;
40
+ var PUBLIC_CLIENT_PORT = 443;
41
41
  var GLOBAL_KEY = "__phpSandboxViteState__";
42
42
  function getGlobalState() {
43
43
  const g = globalThis;
@@ -52,30 +52,60 @@ function normalizeSandboxType(value) {
52
52
  const normalized = value?.trim().toLowerCase();
53
53
  return normalized ? normalized : void 0;
54
54
  }
55
- function resolveHmrPort(options) {
56
- return options.hmrPort ?? DEFAULT_HMR_PORT;
57
- }
58
- function resolvePublicClientPort(options) {
59
- return options.publicClientPort ?? DEFAULT_PUBLIC_CLIENT_PORT;
60
- }
61
- function resolvePublicHost(options, env, hmrPort) {
62
- return options.publicHost ?? (env.SUBDOMAIN && env.NOTEBOOK_HOST ? `${env.SUBDOMAIN}-${hmrPort}.${env.NOTEBOOK_HOST}` : void 0);
55
+ function resolvePublicHost(env) {
56
+ return env.SUBDOMAIN && env.NOTEBOOK_HOST ? `${env.SUBDOMAIN}-${HMR_PORT}.${env.NOTEBOOK_HOST}` : void 0;
63
57
  }
64
58
  function isRecord(value) {
65
59
  return typeof value === "object" && value !== null;
66
60
  }
67
- function acquireServer(state, port) {
61
+ function toListenError(error, port) {
62
+ const code = isRecord(error) ? error.code : void 0;
63
+ if (code === "EADDRINUSE") {
64
+ return new Error(
65
+ `[vite-plugin-phpsandbox] HMR port ${port} is already in use.`
66
+ );
67
+ }
68
+ const message = error instanceof Error ? error.message : String(error);
69
+ return new Error(
70
+ `[vite-plugin-phpsandbox] Failed to bind HMR server on 0.0.0.0:${port}: ${message}`
71
+ );
72
+ }
73
+ async function listen(server, port) {
74
+ await new Promise((resolve, reject) => {
75
+ const cleanup = () => {
76
+ server.off("error", onError);
77
+ server.off("listening", onListening);
78
+ };
79
+ const onError = (error) => {
80
+ cleanup();
81
+ reject(toListenError(error, port));
82
+ };
83
+ const onListening = () => {
84
+ cleanup();
85
+ resolve();
86
+ };
87
+ server.once("error", onError);
88
+ server.once("listening", onListening);
89
+ try {
90
+ server.listen(port, "0.0.0.0");
91
+ } catch (error) {
92
+ cleanup();
93
+ reject(toListenError(error, port));
94
+ }
95
+ });
96
+ }
97
+ function logServerError(error) {
98
+ console.error("[vite-plugin-phpsandbox] HMR server error:", error);
99
+ }
100
+ async function acquireServer(state, port) {
68
101
  const existing = state.servers.get(port);
69
102
  if (existing) {
70
103
  state.refs.set(port, (state.refs.get(port) ?? 0) + 1);
71
104
  return existing;
72
105
  }
73
106
  const server = import_node_http.default.createServer();
74
- server.on("error", (error) => {
75
- if (error.code === "EADDRINUSE") return;
76
- console.error("[vite-plugin-phpsandbox] HMR server error:", error);
77
- });
78
- server.listen(port, "0.0.0.0");
107
+ await listen(server, port);
108
+ server.on("error", logServerError);
79
109
  state.servers.set(port, server);
80
110
  state.refs.set(port, 1);
81
111
  return server;
@@ -89,83 +119,152 @@ function releaseServer(state, port, server) {
89
119
  state.refs.delete(port);
90
120
  if (state.servers.get(port) !== server) return;
91
121
  state.servers.delete(port);
122
+ server.off("error", logServerError);
92
123
  if (server.listening) {
93
124
  server.close();
94
125
  }
95
126
  }
96
- function resolveAllowedHosts(existingAllowedHosts, optionAllowedHosts, notebookHost, publicHost) {
97
- if (optionAllowedHosts === true || existingAllowedHosts === true) {
98
- return true;
99
- }
100
- const merged = new Set(Array.isArray(existingAllowedHosts) ? existingAllowedHosts : []);
101
- if (Array.isArray(optionAllowedHosts)) {
102
- for (const host of optionAllowedHosts) {
103
- merged.add(host);
104
- }
105
- }
106
- if (notebookHost) {
107
- merged.add(`.${notebookHost}`);
108
- }
109
- if (publicHost) {
110
- merged.add(publicHost);
111
- }
112
- return merged.size > 0 ? Array.from(merged) : existingAllowedHosts;
127
+ function resolveAllowedHosts(existingAllowedHosts, notebookHost, publicHost) {
128
+ if (existingAllowedHosts === true) return true;
129
+ const hosts = [
130
+ ...Array.isArray(existingAllowedHosts) ? existingAllowedHosts : [],
131
+ ...notebookHost ? [`.${notebookHost}`] : [],
132
+ ...publicHost ? [publicHost] : []
133
+ ];
134
+ return hosts.length > 0 ? Array.from(new Set(hosts)) : existingAllowedHosts;
135
+ }
136
+ function resolveExistingHmrOptions(serverOptions) {
137
+ return isRecord(serverOptions.hmr) ? serverOptions.hmr : void 0;
113
138
  }
114
- function phpSandboxPlugin(options = {}, env = process.env) {
115
- let managedHmrPort;
139
+ function resolveHmrOptions(existingServer, publicHost, hmrServer) {
140
+ if (existingServer.hmr === false) return false;
141
+ return {
142
+ ...resolveExistingHmrOptions(existingServer),
143
+ port: HMR_PORT,
144
+ ...hmrServer ? { server: hmrServer } : {},
145
+ ...publicHost ? {
146
+ protocol: "wss",
147
+ host: publicHost,
148
+ clientPort: PUBLIC_CLIENT_PORT
149
+ } : {}
150
+ };
151
+ }
152
+ function shouldCreateHmrServer(existingServer, isLaravel) {
153
+ return !isLaravel && existingServer.hmr !== false;
154
+ }
155
+ function resolveServerConfig(existingServer, env, isLaravel, publicHost, hmrServer) {
156
+ return {
157
+ ...existingServer,
158
+ host: existingServer.host ?? true,
159
+ ...isLaravel ? { port: HMR_PORT } : {},
160
+ hmr: resolveHmrOptions(existingServer, publicHost, hmrServer),
161
+ allowedHosts: resolveAllowedHosts(
162
+ existingServer.allowedHosts,
163
+ env.NOTEBOOK_HOST,
164
+ publicHost
165
+ )
166
+ };
167
+ }
168
+ function formatHost(host) {
169
+ if (host === true) return "0.0.0.0";
170
+ if (host === false || host === void 0) return "vite default";
171
+ return String(host);
172
+ }
173
+ function formatAllowedHosts(allowedHosts) {
174
+ if (allowedHosts === true) return "all";
175
+ if (Array.isArray(allowedHosts)) return allowedHosts.join(", ") || "none";
176
+ return "vite default";
177
+ }
178
+ function formatHmrEndpoint(hmr) {
179
+ if (!hmr || !hmr.host) return "none";
180
+ const protocol = hmr.protocol ?? "ws";
181
+ const port = hmr.clientPort ?? hmr.port;
182
+ return port ? `${protocol}://${hmr.host}:${port}` : `${protocol}://${hmr.host}`;
183
+ }
184
+ function formatHmrSummary(serverOptions, hasManagedServer) {
185
+ if (serverOptions.hmr === false) return "disabled";
186
+ const hmr = resolveExistingHmrOptions(serverOptions);
187
+ const localEndpoint = hasManagedServer ? `0.0.0.0:${HMR_PORT}` : `vite:${serverOptions.port ?? HMR_PORT}`;
188
+ return `${localEndpoint}, public=${formatHmrEndpoint(hmr)}`;
189
+ }
190
+ function formatStartupLog(sandboxType, serverOptions, hasManagedServer) {
191
+ return [
192
+ "[vite-plugin-phpsandbox] enabled",
193
+ `type=${sandboxType}`,
194
+ `host=${formatHost(serverOptions.host)}`,
195
+ `hmr=${formatHmrSummary(serverOptions, hasManagedServer)}`,
196
+ `allowedHosts=${formatAllowedHosts(serverOptions.allowedHosts)}`
197
+ ].join(" | ");
198
+ }
199
+ function phpSandboxPlugin() {
116
200
  let managedHmrServer;
201
+ let releaseManagedHmrServer;
202
+ let sandboxType;
203
+ let startupLog;
204
+ function setManagedHmrServer(server) {
205
+ if (managedHmrServer === server) return;
206
+ releaseManagedHmrServer?.();
207
+ managedHmrServer = server;
208
+ if (!server) {
209
+ releaseManagedHmrServer = void 0;
210
+ return;
211
+ }
212
+ let released = false;
213
+ releaseManagedHmrServer = () => {
214
+ if (released) return;
215
+ released = true;
216
+ if (managedHmrServer === server) {
217
+ managedHmrServer = void 0;
218
+ releaseManagedHmrServer = void 0;
219
+ }
220
+ releaseServer(getGlobalState(), HMR_PORT, server);
221
+ };
222
+ }
117
223
  return {
118
224
  name: "vite-plugin-phpsandbox",
119
225
  apply: "serve",
120
226
  enforce: "post",
121
- config(userConfig) {
122
- if (options.enabled === false) return {};
123
- const sandboxType = normalizeSandboxType(env.PHPSANDBOX_TYPE);
124
- if (!sandboxType) return {};
125
- const hmrPort = resolveHmrPort(options);
126
- const publicClientPort = resolvePublicClientPort(options);
127
- const publicHost = resolvePublicHost(options, env, hmrPort);
227
+ async config(userConfig) {
228
+ const env = process.env;
229
+ sandboxType = normalizeSandboxType(env.PHPSANDBOX_TYPE);
230
+ if (!sandboxType) {
231
+ setManagedHmrServer(void 0);
232
+ startupLog = void 0;
233
+ return {};
234
+ }
128
235
  const isLaravel = sandboxType === "laravel";
236
+ const publicHost = resolvePublicHost(env);
129
237
  const existingServer = userConfig.server ?? {};
130
- const existingHmr = isRecord(existingServer.hmr) ? existingServer.hmr : void 0;
131
- const hmrDisabled = existingServer.hmr === false;
132
- const allowedHosts = resolveAllowedHosts(
133
- existingServer.allowedHosts,
134
- options.allowedHosts,
135
- env.NOTEBOOK_HOST,
136
- publicHost
137
- );
138
- const hmrServer = isLaravel || hmrDisabled ? void 0 : acquireServer(getGlobalState(), hmrPort);
139
- managedHmrPort = hmrServer ? hmrPort : void 0;
140
- managedHmrServer = hmrServer;
238
+ const hmrServer = shouldCreateHmrServer(existingServer, isLaravel) ? managedHmrServer ?? await acquireServer(getGlobalState(), HMR_PORT) : void 0;
239
+ setManagedHmrServer(hmrServer);
141
240
  return {
142
- server: {
143
- ...existingServer,
144
- host: existingServer.host ?? true,
145
- ...isLaravel ? { port: hmrPort } : {},
146
- ...hmrDisabled ? { hmr: false } : {
147
- hmr: {
148
- ...existingHmr,
149
- port: hmrPort,
150
- ...hmrServer ? { server: hmrServer } : {},
151
- ...publicHost ? {
152
- protocol: "wss",
153
- host: publicHost,
154
- clientPort: publicClientPort
155
- } : {}
156
- }
157
- },
158
- allowedHosts
159
- }
241
+ server: resolveServerConfig(
242
+ existingServer,
243
+ env,
244
+ isLaravel,
245
+ publicHost,
246
+ hmrServer
247
+ )
160
248
  };
161
249
  },
250
+ configResolved(config) {
251
+ if (!sandboxType) return;
252
+ const nextStartupLog = formatStartupLog(
253
+ sandboxType,
254
+ config.server,
255
+ Boolean(managedHmrServer)
256
+ );
257
+ if (nextStartupLog === startupLog) return;
258
+ startupLog = nextStartupLog;
259
+ console.info(nextStartupLog);
260
+ },
162
261
  configureServer(server) {
163
- if (!managedHmrServer || managedHmrPort === void 0) return;
164
- const hmrPort = managedHmrPort;
165
- const hmrServer = managedHmrServer;
166
- server.httpServer?.once("close", () => {
167
- releaseServer(getGlobalState(), hmrPort, hmrServer);
168
- });
262
+ const release = releaseManagedHmrServer;
263
+ if (!release) return;
264
+ server.httpServer?.once("close", release);
265
+ },
266
+ closeBundle() {
267
+ releaseManagedHmrServer?.();
169
268
  }
170
269
  };
171
270
  }
package/dist/index.d.cts CHANGED
@@ -1,36 +1,6 @@
1
1
  import { Plugin } from 'vite';
2
2
 
3
- type PhpSandboxEnv = {
4
- SUBDOMAIN?: string;
5
- NOTEBOOK_HOST?: string;
6
- PHPSANDBOX_TYPE?: string;
7
- };
8
- type PhpSandboxOptions = {
9
- /**
10
- * Defaults to merging `.${NOTEBOOK_HOST}` and the derived public host into
11
- * `server.allowedHosts`.
12
- * - true: disable host checks entirely
13
- * - array: merge with existing allowedHosts
14
- */
15
- allowedHosts?: true | string[];
16
- /**
17
- * Explicitly disable the plugin.
18
- */
19
- enabled?: boolean;
20
- /**
21
- * Defaults to 5173.
22
- */
23
- hmrPort?: number;
24
- /**
25
- * Defaults to `${SUBDOMAIN}-${port}.${NOTEBOOK_HOST}` when env values exist.
26
- */
27
- publicHost?: string;
28
- /**
29
- * Defaults to 443.
30
- */
31
- publicClientPort?: number;
32
- };
33
- declare function phpSandboxPlugin(options?: PhpSandboxOptions, env?: PhpSandboxEnv): Plugin;
3
+ declare function phpSandboxPlugin(): Plugin;
34
4
  declare const phpSandbox: typeof phpSandboxPlugin;
35
5
 
36
- export { type PhpSandboxEnv, type PhpSandboxOptions, phpSandboxPlugin as default, phpSandbox, phpSandboxPlugin };
6
+ export { phpSandboxPlugin as default, phpSandbox, phpSandboxPlugin };
package/dist/index.d.ts CHANGED
@@ -1,36 +1,6 @@
1
1
  import { Plugin } from 'vite';
2
2
 
3
- type PhpSandboxEnv = {
4
- SUBDOMAIN?: string;
5
- NOTEBOOK_HOST?: string;
6
- PHPSANDBOX_TYPE?: string;
7
- };
8
- type PhpSandboxOptions = {
9
- /**
10
- * Defaults to merging `.${NOTEBOOK_HOST}` and the derived public host into
11
- * `server.allowedHosts`.
12
- * - true: disable host checks entirely
13
- * - array: merge with existing allowedHosts
14
- */
15
- allowedHosts?: true | string[];
16
- /**
17
- * Explicitly disable the plugin.
18
- */
19
- enabled?: boolean;
20
- /**
21
- * Defaults to 5173.
22
- */
23
- hmrPort?: number;
24
- /**
25
- * Defaults to `${SUBDOMAIN}-${port}.${NOTEBOOK_HOST}` when env values exist.
26
- */
27
- publicHost?: string;
28
- /**
29
- * Defaults to 443.
30
- */
31
- publicClientPort?: number;
32
- };
33
- declare function phpSandboxPlugin(options?: PhpSandboxOptions, env?: PhpSandboxEnv): Plugin;
3
+ declare function phpSandboxPlugin(): Plugin;
34
4
  declare const phpSandbox: typeof phpSandboxPlugin;
35
5
 
36
- export { type PhpSandboxEnv, type PhpSandboxOptions, phpSandboxPlugin as default, phpSandbox, phpSandboxPlugin };
6
+ export { phpSandboxPlugin as default, phpSandbox, phpSandboxPlugin };
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  // src/index.ts
2
2
  import http from "http";
3
- var DEFAULT_HMR_PORT = 5173;
4
- var DEFAULT_PUBLIC_CLIENT_PORT = 443;
3
+ var HMR_PORT = 5173;
4
+ var PUBLIC_CLIENT_PORT = 443;
5
5
  var GLOBAL_KEY = "__phpSandboxViteState__";
6
6
  function getGlobalState() {
7
7
  const g = globalThis;
@@ -16,30 +16,60 @@ function normalizeSandboxType(value) {
16
16
  const normalized = value?.trim().toLowerCase();
17
17
  return normalized ? normalized : void 0;
18
18
  }
19
- function resolveHmrPort(options) {
20
- return options.hmrPort ?? DEFAULT_HMR_PORT;
21
- }
22
- function resolvePublicClientPort(options) {
23
- return options.publicClientPort ?? DEFAULT_PUBLIC_CLIENT_PORT;
24
- }
25
- function resolvePublicHost(options, env, hmrPort) {
26
- return options.publicHost ?? (env.SUBDOMAIN && env.NOTEBOOK_HOST ? `${env.SUBDOMAIN}-${hmrPort}.${env.NOTEBOOK_HOST}` : void 0);
19
+ function resolvePublicHost(env) {
20
+ return env.SUBDOMAIN && env.NOTEBOOK_HOST ? `${env.SUBDOMAIN}-${HMR_PORT}.${env.NOTEBOOK_HOST}` : void 0;
27
21
  }
28
22
  function isRecord(value) {
29
23
  return typeof value === "object" && value !== null;
30
24
  }
31
- function acquireServer(state, port) {
25
+ function toListenError(error, port) {
26
+ const code = isRecord(error) ? error.code : void 0;
27
+ if (code === "EADDRINUSE") {
28
+ return new Error(
29
+ `[vite-plugin-phpsandbox] HMR port ${port} is already in use.`
30
+ );
31
+ }
32
+ const message = error instanceof Error ? error.message : String(error);
33
+ return new Error(
34
+ `[vite-plugin-phpsandbox] Failed to bind HMR server on 0.0.0.0:${port}: ${message}`
35
+ );
36
+ }
37
+ async function listen(server, port) {
38
+ await new Promise((resolve, reject) => {
39
+ const cleanup = () => {
40
+ server.off("error", onError);
41
+ server.off("listening", onListening);
42
+ };
43
+ const onError = (error) => {
44
+ cleanup();
45
+ reject(toListenError(error, port));
46
+ };
47
+ const onListening = () => {
48
+ cleanup();
49
+ resolve();
50
+ };
51
+ server.once("error", onError);
52
+ server.once("listening", onListening);
53
+ try {
54
+ server.listen(port, "0.0.0.0");
55
+ } catch (error) {
56
+ cleanup();
57
+ reject(toListenError(error, port));
58
+ }
59
+ });
60
+ }
61
+ function logServerError(error) {
62
+ console.error("[vite-plugin-phpsandbox] HMR server error:", error);
63
+ }
64
+ async function acquireServer(state, port) {
32
65
  const existing = state.servers.get(port);
33
66
  if (existing) {
34
67
  state.refs.set(port, (state.refs.get(port) ?? 0) + 1);
35
68
  return existing;
36
69
  }
37
70
  const server = http.createServer();
38
- server.on("error", (error) => {
39
- if (error.code === "EADDRINUSE") return;
40
- console.error("[vite-plugin-phpsandbox] HMR server error:", error);
41
- });
42
- server.listen(port, "0.0.0.0");
71
+ await listen(server, port);
72
+ server.on("error", logServerError);
43
73
  state.servers.set(port, server);
44
74
  state.refs.set(port, 1);
45
75
  return server;
@@ -53,83 +83,152 @@ function releaseServer(state, port, server) {
53
83
  state.refs.delete(port);
54
84
  if (state.servers.get(port) !== server) return;
55
85
  state.servers.delete(port);
86
+ server.off("error", logServerError);
56
87
  if (server.listening) {
57
88
  server.close();
58
89
  }
59
90
  }
60
- function resolveAllowedHosts(existingAllowedHosts, optionAllowedHosts, notebookHost, publicHost) {
61
- if (optionAllowedHosts === true || existingAllowedHosts === true) {
62
- return true;
63
- }
64
- const merged = new Set(Array.isArray(existingAllowedHosts) ? existingAllowedHosts : []);
65
- if (Array.isArray(optionAllowedHosts)) {
66
- for (const host of optionAllowedHosts) {
67
- merged.add(host);
68
- }
69
- }
70
- if (notebookHost) {
71
- merged.add(`.${notebookHost}`);
72
- }
73
- if (publicHost) {
74
- merged.add(publicHost);
75
- }
76
- return merged.size > 0 ? Array.from(merged) : existingAllowedHosts;
91
+ function resolveAllowedHosts(existingAllowedHosts, notebookHost, publicHost) {
92
+ if (existingAllowedHosts === true) return true;
93
+ const hosts = [
94
+ ...Array.isArray(existingAllowedHosts) ? existingAllowedHosts : [],
95
+ ...notebookHost ? [`.${notebookHost}`] : [],
96
+ ...publicHost ? [publicHost] : []
97
+ ];
98
+ return hosts.length > 0 ? Array.from(new Set(hosts)) : existingAllowedHosts;
99
+ }
100
+ function resolveExistingHmrOptions(serverOptions) {
101
+ return isRecord(serverOptions.hmr) ? serverOptions.hmr : void 0;
77
102
  }
78
- function phpSandboxPlugin(options = {}, env = process.env) {
79
- let managedHmrPort;
103
+ function resolveHmrOptions(existingServer, publicHost, hmrServer) {
104
+ if (existingServer.hmr === false) return false;
105
+ return {
106
+ ...resolveExistingHmrOptions(existingServer),
107
+ port: HMR_PORT,
108
+ ...hmrServer ? { server: hmrServer } : {},
109
+ ...publicHost ? {
110
+ protocol: "wss",
111
+ host: publicHost,
112
+ clientPort: PUBLIC_CLIENT_PORT
113
+ } : {}
114
+ };
115
+ }
116
+ function shouldCreateHmrServer(existingServer, isLaravel) {
117
+ return !isLaravel && existingServer.hmr !== false;
118
+ }
119
+ function resolveServerConfig(existingServer, env, isLaravel, publicHost, hmrServer) {
120
+ return {
121
+ ...existingServer,
122
+ host: existingServer.host ?? true,
123
+ ...isLaravel ? { port: HMR_PORT } : {},
124
+ hmr: resolveHmrOptions(existingServer, publicHost, hmrServer),
125
+ allowedHosts: resolveAllowedHosts(
126
+ existingServer.allowedHosts,
127
+ env.NOTEBOOK_HOST,
128
+ publicHost
129
+ )
130
+ };
131
+ }
132
+ function formatHost(host) {
133
+ if (host === true) return "0.0.0.0";
134
+ if (host === false || host === void 0) return "vite default";
135
+ return String(host);
136
+ }
137
+ function formatAllowedHosts(allowedHosts) {
138
+ if (allowedHosts === true) return "all";
139
+ if (Array.isArray(allowedHosts)) return allowedHosts.join(", ") || "none";
140
+ return "vite default";
141
+ }
142
+ function formatHmrEndpoint(hmr) {
143
+ if (!hmr || !hmr.host) return "none";
144
+ const protocol = hmr.protocol ?? "ws";
145
+ const port = hmr.clientPort ?? hmr.port;
146
+ return port ? `${protocol}://${hmr.host}:${port}` : `${protocol}://${hmr.host}`;
147
+ }
148
+ function formatHmrSummary(serverOptions, hasManagedServer) {
149
+ if (serverOptions.hmr === false) return "disabled";
150
+ const hmr = resolveExistingHmrOptions(serverOptions);
151
+ const localEndpoint = hasManagedServer ? `0.0.0.0:${HMR_PORT}` : `vite:${serverOptions.port ?? HMR_PORT}`;
152
+ return `${localEndpoint}, public=${formatHmrEndpoint(hmr)}`;
153
+ }
154
+ function formatStartupLog(sandboxType, serverOptions, hasManagedServer) {
155
+ return [
156
+ "[vite-plugin-phpsandbox] enabled",
157
+ `type=${sandboxType}`,
158
+ `host=${formatHost(serverOptions.host)}`,
159
+ `hmr=${formatHmrSummary(serverOptions, hasManagedServer)}`,
160
+ `allowedHosts=${formatAllowedHosts(serverOptions.allowedHosts)}`
161
+ ].join(" | ");
162
+ }
163
+ function phpSandboxPlugin() {
80
164
  let managedHmrServer;
165
+ let releaseManagedHmrServer;
166
+ let sandboxType;
167
+ let startupLog;
168
+ function setManagedHmrServer(server) {
169
+ if (managedHmrServer === server) return;
170
+ releaseManagedHmrServer?.();
171
+ managedHmrServer = server;
172
+ if (!server) {
173
+ releaseManagedHmrServer = void 0;
174
+ return;
175
+ }
176
+ let released = false;
177
+ releaseManagedHmrServer = () => {
178
+ if (released) return;
179
+ released = true;
180
+ if (managedHmrServer === server) {
181
+ managedHmrServer = void 0;
182
+ releaseManagedHmrServer = void 0;
183
+ }
184
+ releaseServer(getGlobalState(), HMR_PORT, server);
185
+ };
186
+ }
81
187
  return {
82
188
  name: "vite-plugin-phpsandbox",
83
189
  apply: "serve",
84
190
  enforce: "post",
85
- config(userConfig) {
86
- if (options.enabled === false) return {};
87
- const sandboxType = normalizeSandboxType(env.PHPSANDBOX_TYPE);
88
- if (!sandboxType) return {};
89
- const hmrPort = resolveHmrPort(options);
90
- const publicClientPort = resolvePublicClientPort(options);
91
- const publicHost = resolvePublicHost(options, env, hmrPort);
191
+ async config(userConfig) {
192
+ const env = process.env;
193
+ sandboxType = normalizeSandboxType(env.PHPSANDBOX_TYPE);
194
+ if (!sandboxType) {
195
+ setManagedHmrServer(void 0);
196
+ startupLog = void 0;
197
+ return {};
198
+ }
92
199
  const isLaravel = sandboxType === "laravel";
200
+ const publicHost = resolvePublicHost(env);
93
201
  const existingServer = userConfig.server ?? {};
94
- const existingHmr = isRecord(existingServer.hmr) ? existingServer.hmr : void 0;
95
- const hmrDisabled = existingServer.hmr === false;
96
- const allowedHosts = resolveAllowedHosts(
97
- existingServer.allowedHosts,
98
- options.allowedHosts,
99
- env.NOTEBOOK_HOST,
100
- publicHost
101
- );
102
- const hmrServer = isLaravel || hmrDisabled ? void 0 : acquireServer(getGlobalState(), hmrPort);
103
- managedHmrPort = hmrServer ? hmrPort : void 0;
104
- managedHmrServer = hmrServer;
202
+ const hmrServer = shouldCreateHmrServer(existingServer, isLaravel) ? managedHmrServer ?? await acquireServer(getGlobalState(), HMR_PORT) : void 0;
203
+ setManagedHmrServer(hmrServer);
105
204
  return {
106
- server: {
107
- ...existingServer,
108
- host: existingServer.host ?? true,
109
- ...isLaravel ? { port: hmrPort } : {},
110
- ...hmrDisabled ? { hmr: false } : {
111
- hmr: {
112
- ...existingHmr,
113
- port: hmrPort,
114
- ...hmrServer ? { server: hmrServer } : {},
115
- ...publicHost ? {
116
- protocol: "wss",
117
- host: publicHost,
118
- clientPort: publicClientPort
119
- } : {}
120
- }
121
- },
122
- allowedHosts
123
- }
205
+ server: resolveServerConfig(
206
+ existingServer,
207
+ env,
208
+ isLaravel,
209
+ publicHost,
210
+ hmrServer
211
+ )
124
212
  };
125
213
  },
214
+ configResolved(config) {
215
+ if (!sandboxType) return;
216
+ const nextStartupLog = formatStartupLog(
217
+ sandboxType,
218
+ config.server,
219
+ Boolean(managedHmrServer)
220
+ );
221
+ if (nextStartupLog === startupLog) return;
222
+ startupLog = nextStartupLog;
223
+ console.info(nextStartupLog);
224
+ },
126
225
  configureServer(server) {
127
- if (!managedHmrServer || managedHmrPort === void 0) return;
128
- const hmrPort = managedHmrPort;
129
- const hmrServer = managedHmrServer;
130
- server.httpServer?.once("close", () => {
131
- releaseServer(getGlobalState(), hmrPort, hmrServer);
132
- });
226
+ const release = releaseManagedHmrServer;
227
+ if (!release) return;
228
+ server.httpServer?.once("close", release);
229
+ },
230
+ closeBundle() {
231
+ releaseManagedHmrServer?.();
133
232
  }
134
233
  };
135
234
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vite-plugin-phpsandbox",
3
- "version": "0.1.1",
3
+ "version": "0.2.0",
4
4
  "description": "Vite plugin for PHP sandbox environments that need stable HMR over public proxy hosts.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -37,7 +37,7 @@
37
37
  "build": "tsup src/index.ts --format esm,cjs --dts",
38
38
  "check": "tsc --noEmit",
39
39
  "release:check": "npm run check && npm run build && npm pack --dry-run",
40
- "release": "npm version patch && npm run release:check && npm publish",
40
+ "release": "npm version minor && npm run release:check && npm publish",
41
41
  "prepublishOnly": "npm run build && npm run check"
42
42
  },
43
43
  "devDependencies": {