unplugin-https-reverse-proxy 4.1.0-beta.3 → 4.1.0-beta.4
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-HBXMM25C.js → chunk-H7LIW3S4.js} +246 -644
- package/dist/esbuild.cjs +249 -647
- package/dist/esbuild.js +1 -1
- package/dist/index.cjs +249 -647
- package/dist/index.js +1 -1
- package/dist/nuxt.cjs +247 -645
- package/dist/nuxt.js +1 -1
- package/dist/privileged-helper.cjs +110 -13
- package/dist/privileged-helper.js +111 -14
- package/dist/rollup.cjs +249 -647
- package/dist/rollup.js +1 -1
- package/dist/rspack.cjs +249 -647
- package/dist/rspack.js +1 -1
- package/dist/vite.cjs +249 -647
- package/dist/vite.js +1 -1
- package/dist/webpack.cjs +249 -647
- package/dist/webpack.js +1 -1
- package/package.json +1 -1
- package/src/caddy/config.ts +176 -57
- package/src/caddy/index.ts +82 -125
- package/src/privileged/bootstrap.ts +83 -2
- package/src/privileged/server.ts +95 -14
- package/src/privileged/session.ts +63 -14
package/dist/webpack.js
CHANGED
package/package.json
CHANGED
package/src/caddy/config.ts
CHANGED
|
@@ -1,72 +1,191 @@
|
|
|
1
1
|
import type { ProxyType } from './caddyfile'
|
|
2
|
-
import { existsSync, readFileSync,
|
|
3
|
-
import
|
|
4
|
-
import
|
|
2
|
+
import { existsSync, readFileSync, renameSync, unlinkSync, writeFileSync } from 'node:fs'
|
|
3
|
+
import process from 'node:process'
|
|
4
|
+
import * as lockfile from 'proper-lockfile'
|
|
5
5
|
import { caddyConfigPath } from './constants'
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
/** One project's route, plus the pid that owns it. */
|
|
8
|
+
type ProxyEntry = typeof ProxyType.infer & { ownerPid?: number }
|
|
9
|
+
|
|
10
|
+
type ProxyMap = Record<string, ProxyEntry>
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* A file lock held around every read-modify-write of the shared config.
|
|
14
|
+
*
|
|
15
|
+
* Several dev servers run as independent processes, so a read-then-write from
|
|
16
|
+
* two of them can interleave and drop an entry. Synchronous calls are only
|
|
17
|
+
* atomic within one event loop, which is why the lock has to be a real file
|
|
18
|
+
* lock rather than an in-process queue.
|
|
19
|
+
*/
|
|
20
|
+
interface ConfigLock {
|
|
21
|
+
acquire: () => Promise<() => void>
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface CaddyConfigApi {
|
|
25
|
+
configJsonRef: () => ProxyMap | undefined
|
|
26
|
+
/** Adds or replaces this project's routes, keeping everyone else's. */
|
|
27
|
+
writeCaddyConfig: (proxies: Array<typeof ProxyType.infer>, key: string) => Promise<void>
|
|
28
|
+
/** Drops one project's routes; the file goes away when nothing is left. */
|
|
29
|
+
removeProxy: (key: string) => Promise<void>
|
|
30
|
+
/** Reads the routes currently on disk, for regenerating the Caddyfile. */
|
|
31
|
+
readProxies: () => ProxyMap
|
|
10
32
|
cleanUp: () => Promise<void>
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
function setConfigContent(): void {
|
|
24
|
-
if (!existsSync(caddyConfigPath)) {
|
|
25
|
-
writeFileSync(caddyConfigPath, '{}')
|
|
26
|
-
}
|
|
27
|
-
try {
|
|
28
|
-
configContentRef(readFileSync(caddyConfigPath, 'utf-8'))
|
|
29
|
-
}
|
|
30
|
-
catch {
|
|
31
|
-
configContentRef('')
|
|
32
|
-
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** Owner pids that have exited can never clean up after themselves. */
|
|
36
|
+
function isAlive(pid: number | undefined): boolean {
|
|
37
|
+
if (pid === undefined)
|
|
38
|
+
return true
|
|
39
|
+
try {
|
|
40
|
+
process.kill(pid, 0)
|
|
41
|
+
return true
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
return false
|
|
33
45
|
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Reads the shared config, dropping entries whose owner process is gone.
|
|
50
|
+
*
|
|
51
|
+
* A SIGKILLed dev server cannot remove its own route, so without this sweep its
|
|
52
|
+
* domain would keep resolving to a proxy with no upstream behind it.
|
|
53
|
+
*/
|
|
54
|
+
function readConfig(): ProxyMap {
|
|
55
|
+
if (!existsSync(caddyConfigPath))
|
|
56
|
+
return {}
|
|
34
57
|
|
|
35
|
-
|
|
36
|
-
|
|
58
|
+
let parsed: ProxyMap
|
|
59
|
+
try {
|
|
60
|
+
parsed = JSON.parse(readFileSync(caddyConfigPath, 'utf-8')) as ProxyMap
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
// A half-written file is not worth preserving: it has no usable routes.
|
|
64
|
+
return {}
|
|
37
65
|
}
|
|
38
66
|
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
function writeCaddyConfig(_proxies: Array<typeof ProxyType.infer>): void {
|
|
44
|
-
const proxies = configJsonRef() || {}
|
|
45
|
-
|
|
46
|
-
_proxies.forEach((p) => {
|
|
47
|
-
let base = p.base || '/'
|
|
48
|
-
if (!base.startsWith('/'))
|
|
49
|
-
base = `/${base}`
|
|
50
|
-
if (base !== '/' && !base.endsWith('/'))
|
|
51
|
-
base = `${base}/`
|
|
52
|
-
const index = `${p.target}${p.portSuffix}${base}`
|
|
53
|
-
proxies[index] = { ...p, base }
|
|
54
|
-
})
|
|
55
|
-
|
|
56
|
-
const content = JSON.stringify(proxies, null, 2)
|
|
57
|
-
configContentRef(content)
|
|
58
|
-
return writeFileSync(caddyConfigPath, content)
|
|
67
|
+
const alive: ProxyMap = {}
|
|
68
|
+
for (const [key, entry] of Object.entries(parsed)) {
|
|
69
|
+
if (isAlive(entry?.ownerPid))
|
|
70
|
+
alive[key] = entry
|
|
59
71
|
}
|
|
72
|
+
return alive
|
|
73
|
+
}
|
|
60
74
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
75
|
+
/**
|
|
76
|
+
* Writes through a temporary file so a concurrent reader never sees a partial
|
|
77
|
+
* document. `rename` is atomic within a filesystem, which keeps the shared
|
|
78
|
+
* config readable at all times.
|
|
79
|
+
*/
|
|
80
|
+
function writeConfig(proxies: ProxyMap): void {
|
|
81
|
+
const content = JSON.stringify(proxies, null, 2)
|
|
82
|
+
const temp = `${caddyConfigPath}.${process.pid}.tmp`
|
|
83
|
+
writeFileSync(temp, content)
|
|
84
|
+
renameSync(temp, caddyConfigPath)
|
|
85
|
+
}
|
|
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()
|
|
65
101
|
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export interface CaddyConfigOptions {
|
|
105
|
+
/** Injected in tests so they do not need the real lock. */
|
|
106
|
+
lock?: ConfigLock
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export function useCaddyConfig(options: CaddyConfigOptions = {}): CaddyConfigApi {
|
|
110
|
+
const lock = options.lock ?? createFileLock()
|
|
66
111
|
|
|
67
112
|
return {
|
|
68
|
-
configJsonRef,
|
|
69
|
-
|
|
70
|
-
|
|
113
|
+
configJsonRef: () => (existsSync(caddyConfigPath) ? readConfig() : undefined),
|
|
114
|
+
|
|
115
|
+
async writeCaddyConfig(_proxies, key) {
|
|
116
|
+
await mutateConfig(lock, (proxies) => {
|
|
117
|
+
for (const p of _proxies)
|
|
118
|
+
proxies[routeKey(p, key)] = { ...p, base: normalizeBase(p.base), ownerPid: process.pid }
|
|
119
|
+
})
|
|
120
|
+
},
|
|
121
|
+
|
|
122
|
+
async removeProxy(key) {
|
|
123
|
+
const proxies = await mutateConfig(lock, (current) => {
|
|
124
|
+
for (const route of Object.keys(current)) {
|
|
125
|
+
if (route.endsWith(`#${key}`))
|
|
126
|
+
delete current[route]
|
|
127
|
+
}
|
|
128
|
+
})
|
|
129
|
+
|
|
130
|
+
if (Object.keys(proxies).length === 0)
|
|
131
|
+
removeConfigFile()
|
|
132
|
+
},
|
|
133
|
+
|
|
134
|
+
readProxies: () => readConfig(),
|
|
135
|
+
|
|
136
|
+
async cleanUp() {
|
|
137
|
+
removeConfigFile()
|
|
138
|
+
},
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function removeConfigFile(): void {
|
|
143
|
+
try {
|
|
144
|
+
if (existsSync(caddyConfigPath))
|
|
145
|
+
unlinkSync(caddyConfigPath)
|
|
146
|
+
}
|
|
147
|
+
catch {}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function normalizeBase(base: string | undefined): string {
|
|
151
|
+
let out = base || '/'
|
|
152
|
+
if (!out.startsWith('/'))
|
|
153
|
+
out = `/${out}`
|
|
154
|
+
if (out !== '/' && !out.endsWith('/'))
|
|
155
|
+
out = `${out}/`
|
|
156
|
+
return out
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Route key: the domain it answers on, plus the owning project.
|
|
161
|
+
*
|
|
162
|
+
* Two projects can legitimately serve the same domain on different bases, so
|
|
163
|
+
* the key has to carry the base as well as the owner.
|
|
164
|
+
*/
|
|
165
|
+
export function routeKey(proxy: typeof ProxyType.infer, ownerKey: string): string {
|
|
166
|
+
return `${proxy.target}${proxy.portSuffix}${normalizeBase(proxy.base)}#${ownerKey}`
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Builds the on-disk lock.
|
|
171
|
+
*
|
|
172
|
+
* `proper-lockfile` retries because the winner may hold the lock for a moment;
|
|
173
|
+
* `realpath: false` keeps it working when the temp directory is a symlink.
|
|
174
|
+
*/
|
|
175
|
+
function createFileLock(): ConfigLock {
|
|
176
|
+
return {
|
|
177
|
+
async acquire() {
|
|
178
|
+
if (!existsSync(caddyConfigPath))
|
|
179
|
+
writeFileSync(caddyConfigPath, '{}')
|
|
180
|
+
|
|
181
|
+
const release = await lockfile.lock(caddyConfigPath, {
|
|
182
|
+
realpath: false,
|
|
183
|
+
stale: 10_000,
|
|
184
|
+
retries: { retries: 20, minTimeout: 10, maxTimeout: 100 },
|
|
185
|
+
})
|
|
186
|
+
return () => {
|
|
187
|
+
void release().catch(() => {})
|
|
188
|
+
}
|
|
189
|
+
},
|
|
71
190
|
}
|
|
72
191
|
}
|
package/src/caddy/index.ts
CHANGED
|
@@ -1,20 +1,18 @@
|
|
|
1
1
|
import type { Buffer } from 'node:buffer'
|
|
2
2
|
import type { OpenedPrivilegedSession } from './privileged'
|
|
3
3
|
import { execFile } from 'node:child_process'
|
|
4
|
-
import { chmodSync, createWriteStream, existsSync, mkdirSync, unlinkSync
|
|
4
|
+
import { chmodSync, createWriteStream, existsSync, mkdirSync, unlinkSync } from 'node:fs'
|
|
5
5
|
import { readFile, unlink, writeFile } from 'node:fs/promises'
|
|
6
6
|
import { platform } from 'node:os'
|
|
7
7
|
import { join } from 'node:path'
|
|
8
8
|
import process from 'node:process'
|
|
9
|
-
import { effect } from 'alien-signals'
|
|
10
9
|
import { got } from 'got-cjs'
|
|
11
10
|
import { HttpProxyAgent } from 'http-proxy-agent'
|
|
12
11
|
import { HttpsProxyAgent } from 'https-proxy-agent'
|
|
13
|
-
import * as lockfile from 'proper-lockfile'
|
|
14
12
|
import { consola, once } from '../utils'
|
|
15
13
|
import { genCaddyfile, validateTemplateContext } from './caddyfile'
|
|
16
14
|
import { useCaddyConfig } from './config'
|
|
17
|
-
import { caddyFilePath,
|
|
15
|
+
import { caddyFilePath, caddyPath, supportList, TEMP_DIR } from './constants'
|
|
18
16
|
import { isCaddyReloadCancellation } from './log'
|
|
19
17
|
import { HelperCaddyProcess, openPrivilegedSession } from './privileged'
|
|
20
18
|
import { formatTlsHealthFailure, waitForLocalTls } from './tls-health'
|
|
@@ -133,6 +131,8 @@ function splitHostPort(addr: string): { host: string, port: string } {
|
|
|
133
131
|
/** Injection point for tests: opens the privileged helper without sudo. */
|
|
134
132
|
export interface CaddyDependencies {
|
|
135
133
|
openSession: (runtimeDir: string, reason?: { target: string, https: boolean }) => Promise<OpenedPrivilegedSession>
|
|
134
|
+
/** Shared route config; tests inject an in-memory one. */
|
|
135
|
+
config: () => ReturnType<typeof useCaddyConfig>
|
|
136
136
|
}
|
|
137
137
|
|
|
138
138
|
const defaultDependencies: CaddyDependencies = {
|
|
@@ -144,6 +144,7 @@ const defaultDependencies: CaddyDependencies = {
|
|
|
144
144
|
caddyConfigPath: caddyFilePath,
|
|
145
145
|
reason,
|
|
146
146
|
}),
|
|
147
|
+
config: () => getCaddyConfig(),
|
|
147
148
|
}
|
|
148
149
|
|
|
149
150
|
export class CaddyInstant {
|
|
@@ -151,8 +152,6 @@ export class CaddyInstant {
|
|
|
151
152
|
private stoped = false
|
|
152
153
|
private readonly deps: CaddyDependencies
|
|
153
154
|
|
|
154
|
-
/** has locked when start */
|
|
155
|
-
private locked = false
|
|
156
155
|
private caddyfile: string | undefined
|
|
157
156
|
|
|
158
157
|
private _caddyChild: HelperCaddyProcess | undefined
|
|
@@ -161,21 +160,11 @@ export class CaddyInstant {
|
|
|
161
160
|
private _source: string | undefined
|
|
162
161
|
private _target: string | undefined
|
|
163
162
|
private _stopEffects: Array<(() => void)> = []
|
|
163
|
+
/** Identifies this instance's routes in the shared config. */
|
|
164
|
+
private readonly proxyKey = `${process.pid}-${Math.random().toString(36).slice(2, 8)}`
|
|
164
165
|
|
|
165
166
|
constructor(deps: Partial<CaddyDependencies> = {}) {
|
|
166
167
|
this.deps = { ...defaultDependencies, ...deps }
|
|
167
|
-
this.locked = this.checkLock()
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
checkLock(): boolean {
|
|
171
|
-
if (!existsSync(caddyLockFilePath))
|
|
172
|
-
writeFileSync(caddyLockFilePath, '')
|
|
173
|
-
try {
|
|
174
|
-
return lockfile.checkSync(caddyLockFilePath)
|
|
175
|
-
}
|
|
176
|
-
catch {
|
|
177
|
-
return false
|
|
178
|
-
}
|
|
179
168
|
}
|
|
180
169
|
|
|
181
170
|
/**
|
|
@@ -260,9 +249,15 @@ export class CaddyInstant {
|
|
|
260
249
|
throw new Error(formatTlsHealthFailure(targetHost, health))
|
|
261
250
|
}
|
|
262
251
|
|
|
252
|
+
/**
|
|
253
|
+
* Regenerates the Caddyfile from the config on disk.
|
|
254
|
+
*
|
|
255
|
+
* Reading the file rather than a cached view matters here: another project
|
|
256
|
+
* may have added its route since this instance last looked.
|
|
257
|
+
*/
|
|
263
258
|
private async updateCaddyfile(): Promise<void> {
|
|
264
|
-
const {
|
|
265
|
-
const proxies = Object.values(
|
|
259
|
+
const { readProxies } = this.deps.config()
|
|
260
|
+
const proxies = Object.values(readProxies())
|
|
266
261
|
const ctx = validateTemplateContext({
|
|
267
262
|
caddy_root: this.caddyRoot,
|
|
268
263
|
proxies,
|
|
@@ -342,32 +337,17 @@ export class CaddyInstant {
|
|
|
342
337
|
},
|
|
343
338
|
]
|
|
344
339
|
|
|
345
|
-
const { writeCaddyConfig } =
|
|
346
|
-
writeCaddyConfig(proxies)
|
|
340
|
+
const { writeCaddyConfig } = this.deps.config()
|
|
341
|
+
await writeCaddyConfig(proxies, this.proxyKey)
|
|
347
342
|
|
|
348
343
|
await this.updateCaddyfile()
|
|
349
344
|
|
|
350
|
-
|
|
351
|
-
this
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
return
|
|
357
|
-
}
|
|
358
|
-
void this.updateCaddyfile()
|
|
359
|
-
}),
|
|
360
|
-
)
|
|
361
|
-
|
|
362
|
-
if (!existsSync(caddyLockFilePath))
|
|
363
|
-
writeFileSync(caddyLockFilePath, '')
|
|
364
|
-
|
|
365
|
-
if (!this.locked) {
|
|
366
|
-
// Ports 80/443 may still be held by a previous, uncleanly stopped run.
|
|
367
|
-
await session.client.call('port.free', { port: 443 })
|
|
368
|
-
if (process.platform === 'win32' || !https)
|
|
369
|
-
await session.client.call('port.free', { port: 80 })
|
|
370
|
-
}
|
|
345
|
+
// Ports 80/443 may still be held by a previous, uncleanly stopped run.
|
|
346
|
+
// The helper skips its own Caddy, so this never kills a proxy another
|
|
347
|
+
// project is already using.
|
|
348
|
+
await session.client.call('port.free', { port: 443 })
|
|
349
|
+
if (process.platform === 'win32' || !https)
|
|
350
|
+
await session.client.call('port.free', { port: 80 })
|
|
371
351
|
|
|
372
352
|
return new Promise<void>((resolve, reject) => {
|
|
373
353
|
let startupCheckStarted = false
|
|
@@ -388,8 +368,7 @@ export class CaddyInstant {
|
|
|
388
368
|
resolve()
|
|
389
369
|
}
|
|
390
370
|
catch (error) {
|
|
391
|
-
|
|
392
|
-
await this.baseCleanup(restore)
|
|
371
|
+
await this.baseCleanup(restore)
|
|
393
372
|
reject(error)
|
|
394
373
|
}
|
|
395
374
|
}
|
|
@@ -434,84 +413,65 @@ export class CaddyInstant {
|
|
|
434
413
|
}
|
|
435
414
|
}
|
|
436
415
|
|
|
437
|
-
|
|
438
|
-
lockfile.lockSync(caddyLockFilePath)
|
|
439
|
-
setupCleanup()
|
|
440
|
-
|
|
441
|
-
void (async () => {
|
|
442
|
-
try {
|
|
443
|
-
const child = new HelperCaddyProcess(session.client)
|
|
444
|
-
this._caddyChild = child
|
|
445
|
-
|
|
446
|
-
await session.client.call('caddy.start')
|
|
416
|
+
setupCleanup()
|
|
447
417
|
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
}
|
|
418
|
+
void (async () => {
|
|
419
|
+
try {
|
|
420
|
+
const child = new HelperCaddyProcess(session.client)
|
|
421
|
+
this._caddyChild = child
|
|
422
|
+
|
|
423
|
+
await session.client.call('caddy.start')
|
|
424
|
+
|
|
425
|
+
child.on('exit', (code: number | null) => {
|
|
426
|
+
if (code !== null && code !== 0)
|
|
427
|
+
reject(new Error(`Caddy exited with code ${code}`))
|
|
428
|
+
})
|
|
429
|
+
|
|
430
|
+
child.stderr.on('data', async (data: Buffer) => {
|
|
431
|
+
const lines = data.toString().split('\n').map((line: string) => line.trim())
|
|
432
|
+
for (const line of lines) {
|
|
433
|
+
// caddy log
|
|
434
|
+
// eslint-disable-next-line no-console
|
|
435
|
+
showCaddyLog && line && console.info(line)
|
|
436
|
+
if (isCaddyReloadCancellation(line)) {
|
|
437
|
+
consola.info('Caddy restarted before TLS issuance completed; retrying.\n')
|
|
438
|
+
continue
|
|
439
|
+
}
|
|
440
|
+
try {
|
|
441
|
+
if (line.includes('Error:') || (line && JSON.parse(line).level === 'error')) {
|
|
442
|
+
if (line.includes('parsing caddyfile tokens')) {
|
|
443
|
+
consola.error('Caddyfile syntax error, please contact the author:\n', `${this.caddyfile}\n\n${line}\n`)
|
|
444
|
+
await this.baseCleanup()
|
|
445
|
+
process.exit()
|
|
446
|
+
}
|
|
447
|
+
else {
|
|
448
|
+
consola.error(`${line}\n`)
|
|
449
|
+
return reject(line)
|
|
474
450
|
}
|
|
475
451
|
}
|
|
476
|
-
catch {}
|
|
477
|
-
|
|
478
|
-
if (line.includes('config file changed'))
|
|
479
|
-
consola.success('Detect added a new reverse proxy config, restarted.\n')
|
|
480
|
-
|
|
481
|
-
if (line.includes('caddy proxying') || line.includes('serving initial'))
|
|
482
|
-
void resolveWhenReady()
|
|
483
452
|
}
|
|
484
|
-
|
|
453
|
+
catch {}
|
|
485
454
|
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
void resolveWhenReady()
|
|
489
|
-
})
|
|
490
|
-
}
|
|
491
|
-
catch (error) {
|
|
492
|
-
// The hosts entry was written before Caddy started; a failed start
|
|
493
|
-
// must not leave it behind while the dev server keeps running.
|
|
494
|
-
if (!this.locked)
|
|
495
|
-
await this.baseCleanup(restore)
|
|
496
|
-
reject(error)
|
|
497
|
-
}
|
|
498
|
-
})()
|
|
499
|
-
}
|
|
500
|
-
else {
|
|
501
|
-
consola.info('Caddy is running in another process.')
|
|
455
|
+
if (line.includes('config file changed'))
|
|
456
|
+
consola.success('Detect added a new reverse proxy config, restarted.\n')
|
|
502
457
|
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
458
|
+
if (line.includes('caddy proxying') || line.includes('serving initial'))
|
|
459
|
+
void resolveWhenReady()
|
|
460
|
+
}
|
|
461
|
+
})
|
|
462
|
+
|
|
463
|
+
child.stdout.on('data', (data: Buffer) => {
|
|
464
|
+
consola.info(data.toString())
|
|
465
|
+
void resolveWhenReady()
|
|
466
|
+
})
|
|
467
|
+
}
|
|
468
|
+
catch (error) {
|
|
469
|
+
// The hosts entry was written before Caddy started; a failed start
|
|
470
|
+
// must not leave it behind while the dev server keeps running.
|
|
471
|
+
await this.baseCleanup(restore)
|
|
472
|
+
reject(error)
|
|
473
|
+
}
|
|
474
|
+
})()
|
|
515
475
|
})
|
|
516
476
|
}
|
|
517
477
|
|
|
@@ -541,15 +501,12 @@ export class CaddyInstant {
|
|
|
541
501
|
}
|
|
542
502
|
}
|
|
543
503
|
|
|
544
|
-
|
|
545
|
-
|
|
504
|
+
// Caddy and the shared Caddyfile belong to every project using this
|
|
505
|
+
// helper. Only this project's route is removed here; the helper stops
|
|
506
|
+
// Caddy when its last client disconnects.
|
|
507
|
+
if (!this.stoped) {
|
|
546
508
|
try {
|
|
547
|
-
await
|
|
548
|
-
await unlink(caddyFilePath).catch(() => {})
|
|
549
|
-
await unlink(caddyLockFilePath).catch(() => {})
|
|
550
|
-
if (caddyConfig) {
|
|
551
|
-
await caddyConfig.cleanUp()
|
|
552
|
-
}
|
|
509
|
+
await this.deps.config().removeProxy(this.proxyKey)
|
|
553
510
|
}
|
|
554
511
|
catch (e) {
|
|
555
512
|
consola.error(e)
|