unplugin-https-reverse-proxy 4.1.0-beta.7 → 4.1.0-beta.9
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-FNF6HQJB.js → chunk-3NHJSYFO.js} +38 -23
- package/dist/esbuild.cjs +38 -23
- package/dist/esbuild.js +1 -1
- package/dist/index.cjs +38 -23
- package/dist/index.js +1 -1
- package/dist/nuxt.cjs +38 -23
- package/dist/nuxt.js +1 -1
- package/dist/privileged-helper.cjs +19 -8
- package/dist/privileged-helper.js +19 -8
- package/dist/rollup.cjs +38 -23
- package/dist/rollup.js +1 -1
- package/dist/rspack.cjs +38 -23
- package/dist/rspack.js +1 -1
- package/dist/vite.cjs +38 -23
- package/dist/vite.js +1 -1
- package/dist/webpack.cjs +38 -23
- package/dist/webpack.js +1 -1
- package/package.json +1 -1
- package/src/caddy/config.ts +34 -19
- package/src/caddy/index.ts +26 -7
- package/src/privileged/launch.ts +24 -11
- package/src/privileged/server.ts +24 -0
- package/src/privileged-helper.ts +17 -9
package/dist/rollup.js
CHANGED
package/dist/rspack.cjs
CHANGED
|
@@ -13196,29 +13196,31 @@ function writeConfig(proxies) {
|
|
|
13196
13196
|
(0, import_node_fs.writeFileSync)(temp, content);
|
|
13197
13197
|
(0, import_node_fs.renameSync)(temp, caddyConfigPath);
|
|
13198
13198
|
}
|
|
13199
|
-
async function mutateConfig(lock3, mutate) {
|
|
13200
|
-
const release = await lock3.acquire();
|
|
13201
|
-
try {
|
|
13202
|
-
const proxies = readConfig();
|
|
13203
|
-
mutate(proxies);
|
|
13204
|
-
writeConfig(proxies);
|
|
13205
|
-
return proxies;
|
|
13206
|
-
} finally {
|
|
13207
|
-
release();
|
|
13208
|
-
}
|
|
13209
|
-
}
|
|
13210
13199
|
function useCaddyConfig(options = {}) {
|
|
13211
13200
|
const lock3 = options.lock ?? createFileLock();
|
|
13201
|
+
async function mutate(apply) {
|
|
13202
|
+
var _a4;
|
|
13203
|
+
const release = await lock3.acquire();
|
|
13204
|
+
try {
|
|
13205
|
+
const proxies = readConfig();
|
|
13206
|
+
apply(proxies);
|
|
13207
|
+
writeConfig(proxies);
|
|
13208
|
+
await ((_a4 = options.renderCaddyfile) == null ? void 0 : _a4.call(options, proxies));
|
|
13209
|
+
return proxies;
|
|
13210
|
+
} finally {
|
|
13211
|
+
release();
|
|
13212
|
+
}
|
|
13213
|
+
}
|
|
13212
13214
|
return {
|
|
13213
13215
|
configJsonRef: () => (0, import_node_fs.existsSync)(caddyConfigPath) ? readConfig() : void 0,
|
|
13214
13216
|
async writeCaddyConfig(_proxies, key) {
|
|
13215
|
-
await
|
|
13217
|
+
await mutate((proxies) => {
|
|
13216
13218
|
for (const p of _proxies)
|
|
13217
13219
|
proxies[routeKey(p, key)] = { ...p, base: normalizeBase(p.base), ownerPid: import_node_process2.default.pid };
|
|
13218
13220
|
});
|
|
13219
13221
|
},
|
|
13220
13222
|
async removeProxy(key) {
|
|
13221
|
-
const proxies = await
|
|
13223
|
+
const proxies = await mutate((current) => {
|
|
13222
13224
|
for (const route of Object.keys(current)) {
|
|
13223
13225
|
if (route.endsWith(`#${key}`))
|
|
13224
13226
|
delete current[route];
|
|
@@ -13673,19 +13675,22 @@ function takeBackTerminal() {
|
|
|
13673
13675
|
return () => {
|
|
13674
13676
|
};
|
|
13675
13677
|
const wasRaw = stdin.isRaw === true;
|
|
13678
|
+
stdin.pause();
|
|
13676
13679
|
try {
|
|
13677
13680
|
stdin.setRawMode(false);
|
|
13678
13681
|
} catch {
|
|
13682
|
+
stdin.resume();
|
|
13679
13683
|
return () => {
|
|
13680
13684
|
};
|
|
13681
13685
|
}
|
|
13682
13686
|
return () => {
|
|
13683
|
-
if (
|
|
13684
|
-
|
|
13685
|
-
|
|
13686
|
-
|
|
13687
|
-
|
|
13687
|
+
if (wasRaw) {
|
|
13688
|
+
try {
|
|
13689
|
+
stdin.setRawMode(true);
|
|
13690
|
+
} catch {
|
|
13691
|
+
}
|
|
13688
13692
|
}
|
|
13693
|
+
stdin.resume();
|
|
13689
13694
|
};
|
|
13690
13695
|
}
|
|
13691
13696
|
var PrivilegeDeniedError = class extends Error {
|
|
@@ -14116,10 +14121,23 @@ function testCaddy() {
|
|
|
14116
14121
|
});
|
|
14117
14122
|
});
|
|
14118
14123
|
}
|
|
14124
|
+
function caddyRootPath() {
|
|
14125
|
+
return (0, import_node_path5.join)(
|
|
14126
|
+
import_node_process8.default.platform === "win32" ? `${import_node_process8.default.env.AppData}/Caddy` : `${import_node_process8.default.env.HOME}/Library/Application Support/Caddy`,
|
|
14127
|
+
"./pki/authorities/local"
|
|
14128
|
+
);
|
|
14129
|
+
}
|
|
14130
|
+
async function renderCaddyfile(proxies) {
|
|
14131
|
+
const ctx = validateTemplateContext({
|
|
14132
|
+
caddy_root: caddyRootPath(),
|
|
14133
|
+
proxies: Object.values(proxies)
|
|
14134
|
+
});
|
|
14135
|
+
await (0, import_promises2.writeFile)(caddyFilePath, await genCaddyfile(ctx));
|
|
14136
|
+
}
|
|
14119
14137
|
var caddyConfig;
|
|
14120
14138
|
function getCaddyConfig() {
|
|
14121
14139
|
if (!caddyConfig) {
|
|
14122
|
-
caddyConfig = useCaddyConfig();
|
|
14140
|
+
caddyConfig = useCaddyConfig({ renderCaddyfile });
|
|
14123
14141
|
}
|
|
14124
14142
|
return caddyConfig;
|
|
14125
14143
|
}
|
|
@@ -14175,10 +14193,7 @@ var CaddyInstant = class {
|
|
|
14175
14193
|
return this.caddyfile;
|
|
14176
14194
|
}
|
|
14177
14195
|
get caddyRoot() {
|
|
14178
|
-
return (
|
|
14179
|
-
import_node_process8.default.platform === "win32" ? `${import_node_process8.default.env.AppData}/Caddy` : `${import_node_process8.default.env.HOME}/Library/Application Support/Caddy`,
|
|
14180
|
-
"./pki/authorities/local"
|
|
14181
|
-
);
|
|
14196
|
+
return caddyRootPath();
|
|
14182
14197
|
}
|
|
14183
14198
|
async writeCaddyfile() {
|
|
14184
14199
|
return await (0, import_promises2.writeFile)(caddyFilePath, this.caddyfile || "");
|
package/dist/rspack.js
CHANGED
package/dist/vite.cjs
CHANGED
|
@@ -13197,29 +13197,31 @@ function writeConfig(proxies) {
|
|
|
13197
13197
|
(0, import_node_fs.writeFileSync)(temp, content);
|
|
13198
13198
|
(0, import_node_fs.renameSync)(temp, caddyConfigPath);
|
|
13199
13199
|
}
|
|
13200
|
-
async function mutateConfig(lock3, mutate) {
|
|
13201
|
-
const release = await lock3.acquire();
|
|
13202
|
-
try {
|
|
13203
|
-
const proxies = readConfig();
|
|
13204
|
-
mutate(proxies);
|
|
13205
|
-
writeConfig(proxies);
|
|
13206
|
-
return proxies;
|
|
13207
|
-
} finally {
|
|
13208
|
-
release();
|
|
13209
|
-
}
|
|
13210
|
-
}
|
|
13211
13200
|
function useCaddyConfig(options = {}) {
|
|
13212
13201
|
const lock3 = options.lock ?? createFileLock();
|
|
13202
|
+
async function mutate(apply) {
|
|
13203
|
+
var _a4;
|
|
13204
|
+
const release = await lock3.acquire();
|
|
13205
|
+
try {
|
|
13206
|
+
const proxies = readConfig();
|
|
13207
|
+
apply(proxies);
|
|
13208
|
+
writeConfig(proxies);
|
|
13209
|
+
await ((_a4 = options.renderCaddyfile) == null ? void 0 : _a4.call(options, proxies));
|
|
13210
|
+
return proxies;
|
|
13211
|
+
} finally {
|
|
13212
|
+
release();
|
|
13213
|
+
}
|
|
13214
|
+
}
|
|
13213
13215
|
return {
|
|
13214
13216
|
configJsonRef: () => (0, import_node_fs.existsSync)(caddyConfigPath) ? readConfig() : void 0,
|
|
13215
13217
|
async writeCaddyConfig(_proxies, key) {
|
|
13216
|
-
await
|
|
13218
|
+
await mutate((proxies) => {
|
|
13217
13219
|
for (const p of _proxies)
|
|
13218
13220
|
proxies[routeKey(p, key)] = { ...p, base: normalizeBase(p.base), ownerPid: import_node_process2.default.pid };
|
|
13219
13221
|
});
|
|
13220
13222
|
},
|
|
13221
13223
|
async removeProxy(key) {
|
|
13222
|
-
const proxies = await
|
|
13224
|
+
const proxies = await mutate((current) => {
|
|
13223
13225
|
for (const route of Object.keys(current)) {
|
|
13224
13226
|
if (route.endsWith(`#${key}`))
|
|
13225
13227
|
delete current[route];
|
|
@@ -13674,19 +13676,22 @@ function takeBackTerminal() {
|
|
|
13674
13676
|
return () => {
|
|
13675
13677
|
};
|
|
13676
13678
|
const wasRaw = stdin.isRaw === true;
|
|
13679
|
+
stdin.pause();
|
|
13677
13680
|
try {
|
|
13678
13681
|
stdin.setRawMode(false);
|
|
13679
13682
|
} catch {
|
|
13683
|
+
stdin.resume();
|
|
13680
13684
|
return () => {
|
|
13681
13685
|
};
|
|
13682
13686
|
}
|
|
13683
13687
|
return () => {
|
|
13684
|
-
if (
|
|
13685
|
-
|
|
13686
|
-
|
|
13687
|
-
|
|
13688
|
-
|
|
13688
|
+
if (wasRaw) {
|
|
13689
|
+
try {
|
|
13690
|
+
stdin.setRawMode(true);
|
|
13691
|
+
} catch {
|
|
13692
|
+
}
|
|
13689
13693
|
}
|
|
13694
|
+
stdin.resume();
|
|
13690
13695
|
};
|
|
13691
13696
|
}
|
|
13692
13697
|
var PrivilegeDeniedError = class extends Error {
|
|
@@ -14117,10 +14122,23 @@ function testCaddy() {
|
|
|
14117
14122
|
});
|
|
14118
14123
|
});
|
|
14119
14124
|
}
|
|
14125
|
+
function caddyRootPath() {
|
|
14126
|
+
return (0, import_node_path5.join)(
|
|
14127
|
+
import_node_process8.default.platform === "win32" ? `${import_node_process8.default.env.AppData}/Caddy` : `${import_node_process8.default.env.HOME}/Library/Application Support/Caddy`,
|
|
14128
|
+
"./pki/authorities/local"
|
|
14129
|
+
);
|
|
14130
|
+
}
|
|
14131
|
+
async function renderCaddyfile(proxies) {
|
|
14132
|
+
const ctx = validateTemplateContext({
|
|
14133
|
+
caddy_root: caddyRootPath(),
|
|
14134
|
+
proxies: Object.values(proxies)
|
|
14135
|
+
});
|
|
14136
|
+
await (0, import_promises2.writeFile)(caddyFilePath, await genCaddyfile(ctx));
|
|
14137
|
+
}
|
|
14120
14138
|
var caddyConfig;
|
|
14121
14139
|
function getCaddyConfig() {
|
|
14122
14140
|
if (!caddyConfig) {
|
|
14123
|
-
caddyConfig = useCaddyConfig();
|
|
14141
|
+
caddyConfig = useCaddyConfig({ renderCaddyfile });
|
|
14124
14142
|
}
|
|
14125
14143
|
return caddyConfig;
|
|
14126
14144
|
}
|
|
@@ -14176,10 +14194,7 @@ var CaddyInstant = class {
|
|
|
14176
14194
|
return this.caddyfile;
|
|
14177
14195
|
}
|
|
14178
14196
|
get caddyRoot() {
|
|
14179
|
-
return (
|
|
14180
|
-
import_node_process8.default.platform === "win32" ? `${import_node_process8.default.env.AppData}/Caddy` : `${import_node_process8.default.env.HOME}/Library/Application Support/Caddy`,
|
|
14181
|
-
"./pki/authorities/local"
|
|
14182
|
-
);
|
|
14197
|
+
return caddyRootPath();
|
|
14183
14198
|
}
|
|
14184
14199
|
async writeCaddyfile() {
|
|
14185
14200
|
return await (0, import_promises2.writeFile)(caddyFilePath, this.caddyfile || "");
|
package/dist/vite.js
CHANGED
package/dist/webpack.cjs
CHANGED
|
@@ -13197,29 +13197,31 @@ function writeConfig(proxies) {
|
|
|
13197
13197
|
(0, import_node_fs.writeFileSync)(temp, content);
|
|
13198
13198
|
(0, import_node_fs.renameSync)(temp, caddyConfigPath);
|
|
13199
13199
|
}
|
|
13200
|
-
async function mutateConfig(lock3, mutate) {
|
|
13201
|
-
const release = await lock3.acquire();
|
|
13202
|
-
try {
|
|
13203
|
-
const proxies = readConfig();
|
|
13204
|
-
mutate(proxies);
|
|
13205
|
-
writeConfig(proxies);
|
|
13206
|
-
return proxies;
|
|
13207
|
-
} finally {
|
|
13208
|
-
release();
|
|
13209
|
-
}
|
|
13210
|
-
}
|
|
13211
13200
|
function useCaddyConfig(options = {}) {
|
|
13212
13201
|
const lock3 = options.lock ?? createFileLock();
|
|
13202
|
+
async function mutate(apply) {
|
|
13203
|
+
var _a4;
|
|
13204
|
+
const release = await lock3.acquire();
|
|
13205
|
+
try {
|
|
13206
|
+
const proxies = readConfig();
|
|
13207
|
+
apply(proxies);
|
|
13208
|
+
writeConfig(proxies);
|
|
13209
|
+
await ((_a4 = options.renderCaddyfile) == null ? void 0 : _a4.call(options, proxies));
|
|
13210
|
+
return proxies;
|
|
13211
|
+
} finally {
|
|
13212
|
+
release();
|
|
13213
|
+
}
|
|
13214
|
+
}
|
|
13213
13215
|
return {
|
|
13214
13216
|
configJsonRef: () => (0, import_node_fs.existsSync)(caddyConfigPath) ? readConfig() : void 0,
|
|
13215
13217
|
async writeCaddyConfig(_proxies, key) {
|
|
13216
|
-
await
|
|
13218
|
+
await mutate((proxies) => {
|
|
13217
13219
|
for (const p of _proxies)
|
|
13218
13220
|
proxies[routeKey(p, key)] = { ...p, base: normalizeBase(p.base), ownerPid: import_node_process2.default.pid };
|
|
13219
13221
|
});
|
|
13220
13222
|
},
|
|
13221
13223
|
async removeProxy(key) {
|
|
13222
|
-
const proxies = await
|
|
13224
|
+
const proxies = await mutate((current) => {
|
|
13223
13225
|
for (const route of Object.keys(current)) {
|
|
13224
13226
|
if (route.endsWith(`#${key}`))
|
|
13225
13227
|
delete current[route];
|
|
@@ -13674,19 +13676,22 @@ function takeBackTerminal() {
|
|
|
13674
13676
|
return () => {
|
|
13675
13677
|
};
|
|
13676
13678
|
const wasRaw = stdin.isRaw === true;
|
|
13679
|
+
stdin.pause();
|
|
13677
13680
|
try {
|
|
13678
13681
|
stdin.setRawMode(false);
|
|
13679
13682
|
} catch {
|
|
13683
|
+
stdin.resume();
|
|
13680
13684
|
return () => {
|
|
13681
13685
|
};
|
|
13682
13686
|
}
|
|
13683
13687
|
return () => {
|
|
13684
|
-
if (
|
|
13685
|
-
|
|
13686
|
-
|
|
13687
|
-
|
|
13688
|
-
|
|
13688
|
+
if (wasRaw) {
|
|
13689
|
+
try {
|
|
13690
|
+
stdin.setRawMode(true);
|
|
13691
|
+
} catch {
|
|
13692
|
+
}
|
|
13689
13693
|
}
|
|
13694
|
+
stdin.resume();
|
|
13690
13695
|
};
|
|
13691
13696
|
}
|
|
13692
13697
|
var PrivilegeDeniedError = class extends Error {
|
|
@@ -14117,10 +14122,23 @@ function testCaddy() {
|
|
|
14117
14122
|
});
|
|
14118
14123
|
});
|
|
14119
14124
|
}
|
|
14125
|
+
function caddyRootPath() {
|
|
14126
|
+
return (0, import_node_path5.join)(
|
|
14127
|
+
import_node_process8.default.platform === "win32" ? `${import_node_process8.default.env.AppData}/Caddy` : `${import_node_process8.default.env.HOME}/Library/Application Support/Caddy`,
|
|
14128
|
+
"./pki/authorities/local"
|
|
14129
|
+
);
|
|
14130
|
+
}
|
|
14131
|
+
async function renderCaddyfile(proxies) {
|
|
14132
|
+
const ctx = validateTemplateContext({
|
|
14133
|
+
caddy_root: caddyRootPath(),
|
|
14134
|
+
proxies: Object.values(proxies)
|
|
14135
|
+
});
|
|
14136
|
+
await (0, import_promises2.writeFile)(caddyFilePath, await genCaddyfile(ctx));
|
|
14137
|
+
}
|
|
14120
14138
|
var caddyConfig;
|
|
14121
14139
|
function getCaddyConfig() {
|
|
14122
14140
|
if (!caddyConfig) {
|
|
14123
|
-
caddyConfig = useCaddyConfig();
|
|
14141
|
+
caddyConfig = useCaddyConfig({ renderCaddyfile });
|
|
14124
14142
|
}
|
|
14125
14143
|
return caddyConfig;
|
|
14126
14144
|
}
|
|
@@ -14176,10 +14194,7 @@ var CaddyInstant = class {
|
|
|
14176
14194
|
return this.caddyfile;
|
|
14177
14195
|
}
|
|
14178
14196
|
get caddyRoot() {
|
|
14179
|
-
return (
|
|
14180
|
-
import_node_process8.default.platform === "win32" ? `${import_node_process8.default.env.AppData}/Caddy` : `${import_node_process8.default.env.HOME}/Library/Application Support/Caddy`,
|
|
14181
|
-
"./pki/authorities/local"
|
|
14182
|
-
);
|
|
14197
|
+
return caddyRootPath();
|
|
14183
14198
|
}
|
|
14184
14199
|
async writeCaddyfile() {
|
|
14185
14200
|
return await (0, import_promises2.writeFile)(caddyFilePath, this.caddyfile || "");
|
package/dist/webpack.js
CHANGED
package/package.json
CHANGED
package/src/caddy/config.ts
CHANGED
|
@@ -84,43 +84,58 @@ function writeConfig(proxies: ProxyMap): void {
|
|
|
84
84
|
renameSync(temp, caddyConfigPath)
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
-
/** Applies `mutate` under the file lock, re-reading the latest state first. */
|
|
88
|
-
async function mutateConfig(
|
|
89
|
-
lock: ConfigLock,
|
|
90
|
-
mutate: (proxies: ProxyMap) => void,
|
|
91
|
-
): Promise<ProxyMap> {
|
|
92
|
-
const release = await lock.acquire()
|
|
93
|
-
try {
|
|
94
|
-
const proxies = readConfig()
|
|
95
|
-
mutate(proxies)
|
|
96
|
-
writeConfig(proxies)
|
|
97
|
-
return proxies
|
|
98
|
-
}
|
|
99
|
-
finally {
|
|
100
|
-
release()
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
|
|
104
87
|
export interface CaddyConfigOptions {
|
|
105
88
|
/** Injected in tests so they do not need the real lock. */
|
|
106
89
|
lock?: ConfigLock
|
|
90
|
+
/**
|
|
91
|
+
* Renders the Caddyfile from the routes, called inside the config lock.
|
|
92
|
+
*
|
|
93
|
+
* Rendering here rather than in the caller is what keeps the file in step
|
|
94
|
+
* with the JSON: two projects writing concurrently would otherwise render
|
|
95
|
+
* from their own stale view and the later write would win.
|
|
96
|
+
*/
|
|
97
|
+
renderCaddyfile?: (proxies: ProxyMap) => Promise<void>
|
|
107
98
|
}
|
|
108
99
|
|
|
109
100
|
export function useCaddyConfig(options: CaddyConfigOptions = {}): CaddyConfigApi {
|
|
110
101
|
const lock = options.lock ?? createFileLock()
|
|
111
102
|
|
|
103
|
+
/**
|
|
104
|
+
* Applies the change, then re-renders while still holding the lock.
|
|
105
|
+
*
|
|
106
|
+
* The Caddyfile has to follow every change: leaving a stopped project's site
|
|
107
|
+
* in it would keep proxying to an upstream that is gone. Doing it inside the
|
|
108
|
+
* lock also picks up routes whose owner process died, since `readConfig`
|
|
109
|
+
* drops those.
|
|
110
|
+
*/
|
|
111
|
+
async function mutate(
|
|
112
|
+
apply: (proxies: ProxyMap) => void,
|
|
113
|
+
): Promise<ProxyMap> {
|
|
114
|
+
const release = await lock.acquire()
|
|
115
|
+
try {
|
|
116
|
+
const proxies = readConfig()
|
|
117
|
+
apply(proxies)
|
|
118
|
+
writeConfig(proxies)
|
|
119
|
+
await options.renderCaddyfile?.(proxies)
|
|
120
|
+
return proxies
|
|
121
|
+
}
|
|
122
|
+
finally {
|
|
123
|
+
release()
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
112
127
|
return {
|
|
113
128
|
configJsonRef: () => (existsSync(caddyConfigPath) ? readConfig() : undefined),
|
|
114
129
|
|
|
115
130
|
async writeCaddyConfig(_proxies, key) {
|
|
116
|
-
await
|
|
131
|
+
await mutate((proxies) => {
|
|
117
132
|
for (const p of _proxies)
|
|
118
133
|
proxies[routeKey(p, key)] = { ...p, base: normalizeBase(p.base), ownerPid: process.pid }
|
|
119
134
|
})
|
|
120
135
|
},
|
|
121
136
|
|
|
122
137
|
async removeProxy(key) {
|
|
123
|
-
const proxies = await
|
|
138
|
+
const proxies = await mutate((current) => {
|
|
124
139
|
for (const route of Object.keys(current)) {
|
|
125
140
|
if (route.endsWith(`#${key}`))
|
|
126
141
|
delete current[route]
|
package/src/caddy/index.ts
CHANGED
|
@@ -106,11 +106,35 @@ interface RunOptions {
|
|
|
106
106
|
healthCheck?: boolean
|
|
107
107
|
}
|
|
108
108
|
|
|
109
|
+
/** Where Caddy keeps the local CA; the template serves it for device installs. */
|
|
110
|
+
function caddyRootPath(): string {
|
|
111
|
+
return join(
|
|
112
|
+
process.platform === 'win32'
|
|
113
|
+
? `${process.env.AppData!}/Caddy`
|
|
114
|
+
: `${process.env.HOME!}/Library/Application Support/Caddy`,
|
|
115
|
+
'./pki/authorities/local',
|
|
116
|
+
)
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Renders the Caddyfile from the routes currently on disk and writes it.
|
|
121
|
+
*
|
|
122
|
+
* Called from inside the config lock, so two projects writing at once cannot
|
|
123
|
+
* render from their own stale view of the routes.
|
|
124
|
+
*/
|
|
125
|
+
async function renderCaddyfile(proxies: Record<string, unknown>): Promise<void> {
|
|
126
|
+
const ctx = validateTemplateContext({
|
|
127
|
+
caddy_root: caddyRootPath(),
|
|
128
|
+
proxies: Object.values(proxies) as never,
|
|
129
|
+
})
|
|
130
|
+
await writeFile(caddyFilePath, await genCaddyfile(ctx))
|
|
131
|
+
}
|
|
132
|
+
|
|
109
133
|
let caddyConfig: ReturnType<typeof useCaddyConfig> | undefined
|
|
110
134
|
|
|
111
135
|
function getCaddyConfig(): ReturnType<typeof useCaddyConfig> {
|
|
112
136
|
if (!caddyConfig) {
|
|
113
|
-
caddyConfig = useCaddyConfig()
|
|
137
|
+
caddyConfig = useCaddyConfig({ renderCaddyfile: renderCaddyfile as never })
|
|
114
138
|
}
|
|
115
139
|
return caddyConfig
|
|
116
140
|
}
|
|
@@ -194,12 +218,7 @@ export class CaddyInstant {
|
|
|
194
218
|
}
|
|
195
219
|
|
|
196
220
|
get caddyRoot(): string {
|
|
197
|
-
return
|
|
198
|
-
process.platform === 'win32'
|
|
199
|
-
? `${process.env.AppData!}/Caddy`
|
|
200
|
-
: `${process.env.HOME!}/Library/Application Support/Caddy`,
|
|
201
|
-
'./pki/authorities/local',
|
|
202
|
-
)
|
|
221
|
+
return caddyRootPath()
|
|
203
222
|
}
|
|
204
223
|
|
|
205
224
|
async writeCaddyfile(): Promise<void> {
|
package/src/privileged/launch.ts
CHANGED
|
@@ -146,13 +146,18 @@ function runPrompt(sudoCommand: string): Promise<{ status: number | null, signal
|
|
|
146
146
|
}
|
|
147
147
|
|
|
148
148
|
/**
|
|
149
|
-
*
|
|
149
|
+
* Gives the terminal to `sudo` for the duration of the prompt.
|
|
150
150
|
*
|
|
151
|
-
* Vite
|
|
152
|
-
*
|
|
153
|
-
*
|
|
154
|
-
*
|
|
155
|
-
*
|
|
151
|
+
* Vite keeps stdin in raw mode with a `data` listener attached, so that every
|
|
152
|
+
* keystroke reaches its shortcut handler. Two things break the password read:
|
|
153
|
+
*
|
|
154
|
+
* 1. Raw mode does no line editing, so Enter never terminates the line sudo is
|
|
155
|
+
* waiting for.
|
|
156
|
+
* 2. The `data` listener is resumed, so it consumes the characters before sudo
|
|
157
|
+
* can see them. sudo then reads nothing and reports a wrong password.
|
|
158
|
+
*
|
|
159
|
+
* Both are undone here and restored afterwards, so Vite's shortcuts keep
|
|
160
|
+
* working once the prompt is over.
|
|
156
161
|
*/
|
|
157
162
|
function takeBackTerminal(): () => void {
|
|
158
163
|
const stdin = process.stdin
|
|
@@ -160,20 +165,28 @@ function takeBackTerminal(): () => void {
|
|
|
160
165
|
return () => {}
|
|
161
166
|
|
|
162
167
|
const wasRaw = stdin.isRaw === true
|
|
168
|
+
|
|
169
|
+
// `pause` detaches the stream from the tty without removing Vite's listener,
|
|
170
|
+
// so the same handler still works when the stream is resumed later.
|
|
171
|
+
stdin.pause()
|
|
172
|
+
|
|
163
173
|
try {
|
|
164
174
|
stdin.setRawMode(false)
|
|
165
175
|
}
|
|
166
176
|
catch {
|
|
177
|
+
stdin.resume()
|
|
167
178
|
return () => {}
|
|
168
179
|
}
|
|
169
180
|
|
|
170
181
|
return () => {
|
|
171
|
-
if (
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
182
|
+
if (wasRaw) {
|
|
183
|
+
try {
|
|
184
|
+
stdin.setRawMode(true)
|
|
185
|
+
}
|
|
186
|
+
catch {}
|
|
175
187
|
}
|
|
176
|
-
|
|
188
|
+
// Resume last: Vite's listener is still attached and expects a live stream.
|
|
189
|
+
stdin.resume()
|
|
177
190
|
}
|
|
178
191
|
}
|
|
179
192
|
|
package/src/privileged/server.ts
CHANGED
|
@@ -104,6 +104,8 @@ export interface HelperRuntime {
|
|
|
104
104
|
dispose: () => Promise<void>
|
|
105
105
|
/** Removes hosts entries a previous crashed session left behind. */
|
|
106
106
|
sweepStaleEntries: () => Promise<boolean>
|
|
107
|
+
/** Number of attached dev servers; a signal must not tear down a live one. */
|
|
108
|
+
clientCount: () => number
|
|
107
109
|
}
|
|
108
110
|
|
|
109
111
|
/**
|
|
@@ -332,6 +334,7 @@ export function createHelperRuntime(deps: HelperDeps): HelperRuntime {
|
|
|
332
334
|
},
|
|
333
335
|
dispose,
|
|
334
336
|
sweepStaleEntries,
|
|
337
|
+
clientCount: () => clients.size,
|
|
335
338
|
}
|
|
336
339
|
}
|
|
337
340
|
|
|
@@ -413,6 +416,19 @@ export function createNodeHelperDeps(options: NodeHelperDepsOptions): HelperDeps
|
|
|
413
416
|
const log = options.log ?? ((message: string) => process.stdout.write(`${message}\n`))
|
|
414
417
|
let caddy: CaddyChild | undefined
|
|
415
418
|
|
|
419
|
+
// Caddy runs in its own session, so it no longer dies with this process. The
|
|
420
|
+
// `exit` hook is the last chance to take it down; it must stay synchronous,
|
|
421
|
+
// which `kill` is. Nothing runs after SIGKILL, and that case is covered by
|
|
422
|
+
// the next start freeing the port.
|
|
423
|
+
process.on('exit', () => {
|
|
424
|
+
if (caddy?.pid === undefined)
|
|
425
|
+
return
|
|
426
|
+
try {
|
|
427
|
+
process.kill(caddy.pid, 'SIGTERM')
|
|
428
|
+
}
|
|
429
|
+
catch {}
|
|
430
|
+
})
|
|
431
|
+
|
|
416
432
|
return {
|
|
417
433
|
readHosts: () => readFileSync(hostsPath, 'utf8'),
|
|
418
434
|
writeHosts: (content) => {
|
|
@@ -465,10 +481,18 @@ export function createNodeHelperDeps(options: NodeHelperDepsOptions): HelperDeps
|
|
|
465
481
|
startCaddy: (emit) => {
|
|
466
482
|
// `--watch` makes Caddy reload when another project rewrites the shared
|
|
467
483
|
// Caddyfile. Without it the second project's route never takes effect.
|
|
484
|
+
//
|
|
485
|
+
// `detached` puts Caddy in its own session. It shares one Caddy between
|
|
486
|
+
// projects, so the Ctrl+C that stops one dev server must not reach it:
|
|
487
|
+
// the whole foreground process group gets SIGINT, and Caddy exits on
|
|
488
|
+
// SIGINT. `kill()` still targets the pid, and the exit event still fires.
|
|
489
|
+
// Windows has no process groups to escape and `detached` would open a
|
|
490
|
+
// console window there, so it stays off.
|
|
468
491
|
const child = spawn(options.caddyBin, ['run', '--adapter', 'caddyfile', '--config', options.caddyConfigPath, '--watch'], {
|
|
469
492
|
cwd: options.caddyCwd ?? process.cwd(),
|
|
470
493
|
env: { ...process.env, ...options.caddyEnv },
|
|
471
494
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
495
|
+
detached: platform() !== 'win32',
|
|
472
496
|
})
|
|
473
497
|
const handle: CaddyChild & { running?: boolean } = {
|
|
474
498
|
pid: child.pid,
|
package/src/privileged-helper.ts
CHANGED
|
@@ -86,17 +86,25 @@ async function main(): Promise<void> {
|
|
|
86
86
|
},
|
|
87
87
|
})
|
|
88
88
|
|
|
89
|
-
//
|
|
90
|
-
//
|
|
91
|
-
//
|
|
92
|
-
|
|
89
|
+
// Terminal signals reach the whole foreground process group, so they also hit
|
|
90
|
+
// this helper when one of several dev servers stops. Acting on them would tear
|
|
91
|
+
// down the shared Caddy and hosts entries the remaining projects still use.
|
|
92
|
+
// The socket closing is the only signal this helper acts on.
|
|
93
|
+
//
|
|
94
|
+
// Ctrl+C, Ctrl+\, Ctrl+Z and a terminal closing all arrive this way: SIGINT,
|
|
95
|
+
// SIGQUIT, SIGTSTP and SIGHUP. Ignoring SIGTSTP also keeps the helper from
|
|
96
|
+
// being suspended, which would stall every attached project's RPC.
|
|
97
|
+
for (const signal of ['SIGINT', 'SIGQUIT', 'SIGTSTP', 'SIGHUP'] as const)
|
|
98
|
+
process.on(signal, () => {})
|
|
93
99
|
|
|
94
|
-
|
|
100
|
+
// SIGTERM is different: IDE and process-tree runners send it to shut the tool
|
|
101
|
+
// down for real. It still must not drop a live session, so it only tears down
|
|
102
|
+
// when no dev server is attached.
|
|
103
|
+
process.on('SIGTERM', () => {
|
|
104
|
+
if (helper.runtime.clientCount() > 0)
|
|
105
|
+
return
|
|
95
106
|
void helper.runtime.dispose().finally(() => process.exit(0))
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
process.on('SIGTERM', shutdown)
|
|
99
|
-
process.on('SIGHUP', shutdown)
|
|
107
|
+
})
|
|
100
108
|
|
|
101
109
|
// A closed stdout (the parent died) must not interrupt the cleanup path.
|
|
102
110
|
process.stdout.on('error', () => {})
|