vite-plugin-caddy-multiple-tls 1.5.0 → 1.6.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 +20 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.js +179 -76
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -92,6 +92,26 @@ export default config;
|
|
|
92
92
|
|
|
93
93
|
You can override auto-detection with `repo` or `branch` if needed.
|
|
94
94
|
|
|
95
|
+
If you run different projects that derive the same `<repo>.<branch>` host, add `instanceLabel` to keep domains unique:
|
|
96
|
+
|
|
97
|
+
```js
|
|
98
|
+
// vite.config.js
|
|
99
|
+
import { defineConfig } from 'vite';
|
|
100
|
+
import caddyTls from 'vite-plugin-caddy-multiple-tls';
|
|
101
|
+
|
|
102
|
+
const config = defineConfig({
|
|
103
|
+
plugins: [
|
|
104
|
+
caddyTls({
|
|
105
|
+
instanceLabel: 'web-1',
|
|
106
|
+
})
|
|
107
|
+
]
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
export default config;
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
This derives a host like `<repo>.<branch>.web-1.localhost`.
|
|
114
|
+
|
|
95
115
|
For a zero-config experience, use `baseDomain: 'localhost'` (the default) so the derived domain works without editing `/etc/hosts`.
|
|
96
116
|
|
|
97
117
|
`internalTls` defaults to `true` when you pass `baseDomain` or `domain`. You can override it if needed.
|
package/dist/index.d.ts
CHANGED
|
@@ -11,6 +11,8 @@ interface ViteCaddyTlsPluginOptions {
|
|
|
11
11
|
repo?: string;
|
|
12
12
|
/** Override branch name used in derived domains */
|
|
13
13
|
branch?: string;
|
|
14
|
+
/** Extra unique label appended after branch in derived domains */
|
|
15
|
+
instanceLabel?: string;
|
|
14
16
|
cors?: string;
|
|
15
17
|
/** Override the default Caddy server name (srv0) */
|
|
16
18
|
serverName?: string;
|
|
@@ -37,6 +39,6 @@ type LoopbackDomain = 'localtest.me' | 'lvh.me' | 'nip.io';
|
|
|
37
39
|
* ```
|
|
38
40
|
* @returns {Plugin} - a Vite plugin
|
|
39
41
|
*/
|
|
40
|
-
declare function viteCaddyTlsPlugin({ domain, baseDomain, loopbackDomain, repo, branch, cors, serverName, caddyApiUrl, internalTls, upstreamHostHeader, }?: ViteCaddyTlsPluginOptions): PluginOption;
|
|
42
|
+
declare function viteCaddyTlsPlugin({ domain, baseDomain, loopbackDomain, repo, branch, instanceLabel, cors, serverName, caddyApiUrl, internalTls, upstreamHostHeader, }?: ViteCaddyTlsPluginOptions): PluginOption;
|
|
41
43
|
|
|
42
44
|
export { type ViteCaddyTlsPluginOptions, viteCaddyTlsPlugin as default };
|
package/dist/index.js
CHANGED
|
@@ -1,18 +1,16 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
2
|
import { execSync as execSync2 } from "child_process";
|
|
3
|
-
import
|
|
3
|
+
import { createHash as createHash2 } from "crypto";
|
|
4
|
+
import path2 from "path";
|
|
4
5
|
|
|
5
6
|
// src/utils.ts
|
|
6
7
|
import { execSync } from "child_process";
|
|
8
|
+
import { createHash } from "crypto";
|
|
9
|
+
import { open, unlink } from "fs/promises";
|
|
10
|
+
import os from "os";
|
|
11
|
+
import path from "path";
|
|
7
12
|
var DEFAULT_SERVER_NAME = "srv0";
|
|
8
13
|
var DEFAULT_CADDY_API_URL = "http://localhost:2019";
|
|
9
|
-
var caddyApiUrl = DEFAULT_CADDY_API_URL;
|
|
10
|
-
function setCaddyApiUrl(url) {
|
|
11
|
-
caddyApiUrl = url;
|
|
12
|
-
}
|
|
13
|
-
function getCaddyApiUrl() {
|
|
14
|
-
return caddyApiUrl;
|
|
15
|
-
}
|
|
16
14
|
function isRecord(value) {
|
|
17
15
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
18
16
|
}
|
|
@@ -27,6 +25,42 @@ function parseConfig(text) {
|
|
|
27
25
|
function isTlsPolicyOverlapError(text) {
|
|
28
26
|
return text.includes("cannot apply more than one automation policy to host");
|
|
29
27
|
}
|
|
28
|
+
function getApiUrl(apiUrl) {
|
|
29
|
+
return apiUrl ?? DEFAULT_CADDY_API_URL;
|
|
30
|
+
}
|
|
31
|
+
function getLockPath(apiUrl) {
|
|
32
|
+
const key = createHash("sha1").update(getApiUrl(apiUrl)).digest("hex").slice(0, 12);
|
|
33
|
+
return path.join(os.tmpdir(), `vite-plugin-caddy-multiple-tls-${key}.lock`);
|
|
34
|
+
}
|
|
35
|
+
function sleep(ms) {
|
|
36
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
37
|
+
}
|
|
38
|
+
async function withApiLock(apiUrl, fn) {
|
|
39
|
+
const lockPath = getLockPath(apiUrl);
|
|
40
|
+
const startedAt = Date.now();
|
|
41
|
+
const timeoutMs = 5e3;
|
|
42
|
+
while (true) {
|
|
43
|
+
try {
|
|
44
|
+
const handle = await open(lockPath, "wx");
|
|
45
|
+
try {
|
|
46
|
+
await fn();
|
|
47
|
+
} finally {
|
|
48
|
+
await handle.close();
|
|
49
|
+
await unlink(lockPath).catch(() => void 0);
|
|
50
|
+
}
|
|
51
|
+
return;
|
|
52
|
+
} catch (e) {
|
|
53
|
+
if (e.code !== "EEXIST") {
|
|
54
|
+
throw e;
|
|
55
|
+
}
|
|
56
|
+
if (Date.now() - startedAt >= timeoutMs) {
|
|
57
|
+
await fn();
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
await sleep(50);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
30
64
|
function validateCaddyIsInstalled() {
|
|
31
65
|
try {
|
|
32
66
|
execSync("caddy version");
|
|
@@ -36,29 +70,28 @@ function validateCaddyIsInstalled() {
|
|
|
36
70
|
return false;
|
|
37
71
|
}
|
|
38
72
|
}
|
|
39
|
-
async function isCaddyRunning() {
|
|
73
|
+
async function isCaddyRunning(apiUrl) {
|
|
40
74
|
try {
|
|
41
|
-
const res = await fetch(`${
|
|
75
|
+
const res = await fetch(`${getApiUrl(apiUrl)}/config/`);
|
|
42
76
|
return res.ok;
|
|
43
77
|
} catch (e) {
|
|
44
78
|
return false;
|
|
45
79
|
}
|
|
46
80
|
}
|
|
47
|
-
async function startCaddy() {
|
|
81
|
+
async function startCaddy(apiUrl) {
|
|
48
82
|
try {
|
|
49
83
|
execSync("caddy start", { stdio: "ignore" });
|
|
50
|
-
for (let i = 0; i < 10; i++) {
|
|
51
|
-
if (await isCaddyRunning()) return true;
|
|
52
|
-
await new Promise((r) => setTimeout(r, 500));
|
|
53
|
-
}
|
|
54
|
-
return false;
|
|
55
84
|
} catch (e) {
|
|
56
|
-
console.error("Failed to start Caddy:", e);
|
|
57
|
-
return false;
|
|
58
85
|
}
|
|
86
|
+
for (let i = 0; i < 10; i++) {
|
|
87
|
+
if (await isCaddyRunning(apiUrl)) return true;
|
|
88
|
+
await sleep(500);
|
|
89
|
+
}
|
|
90
|
+
return false;
|
|
59
91
|
}
|
|
60
|
-
async function ensureBaseConfig(serverName = DEFAULT_SERVER_NAME) {
|
|
61
|
-
const
|
|
92
|
+
async function ensureBaseConfig(serverName = DEFAULT_SERVER_NAME, apiUrl) {
|
|
93
|
+
const resolvedApiUrl = getApiUrl(apiUrl);
|
|
94
|
+
const serverUrl = `${resolvedApiUrl}/config/apps/http/servers/${serverName}`;
|
|
62
95
|
const res = await fetch(serverUrl);
|
|
63
96
|
if (res.ok) return;
|
|
64
97
|
const baseConfig = {
|
|
@@ -70,7 +103,7 @@ async function ensureBaseConfig(serverName = DEFAULT_SERVER_NAME) {
|
|
|
70
103
|
[serverName]: baseConfig
|
|
71
104
|
}
|
|
72
105
|
};
|
|
73
|
-
const configRes = await fetch(`${
|
|
106
|
+
const configRes = await fetch(`${resolvedApiUrl}/config/`);
|
|
74
107
|
if (!configRes.ok) {
|
|
75
108
|
const text = await configRes.text();
|
|
76
109
|
throw new Error(`Failed to read Caddy config: ${text}`);
|
|
@@ -82,7 +115,7 @@ async function ensureBaseConfig(serverName = DEFAULT_SERVER_NAME) {
|
|
|
82
115
|
}
|
|
83
116
|
const isEmptyConfig = configText.trim() === "" || config === null || isRecord(config) && Object.keys(config).length === 0;
|
|
84
117
|
if (isEmptyConfig) {
|
|
85
|
-
const loadRes = await fetch(`${
|
|
118
|
+
const loadRes = await fetch(`${resolvedApiUrl}/load`, {
|
|
86
119
|
method: "POST",
|
|
87
120
|
headers: { "Content-Type": "application/json" },
|
|
88
121
|
body: JSON.stringify({
|
|
@@ -104,7 +137,7 @@ async function ensureBaseConfig(serverName = DEFAULT_SERVER_NAME) {
|
|
|
104
137
|
let hasHttp = isRecord(http);
|
|
105
138
|
let hasServers = isRecord(servers);
|
|
106
139
|
if (!hasApps) {
|
|
107
|
-
const createAppsRes = await fetch(`${
|
|
140
|
+
const createAppsRes = await fetch(`${resolvedApiUrl}/config/apps`, {
|
|
108
141
|
method: "PUT",
|
|
109
142
|
headers: { "Content-Type": "application/json" },
|
|
110
143
|
body: JSON.stringify({})
|
|
@@ -116,7 +149,7 @@ async function ensureBaseConfig(serverName = DEFAULT_SERVER_NAME) {
|
|
|
116
149
|
hasApps = true;
|
|
117
150
|
}
|
|
118
151
|
if (!hasHttp) {
|
|
119
|
-
const createHttpRes = await fetch(`${
|
|
152
|
+
const createHttpRes = await fetch(`${resolvedApiUrl}/config/apps/http`, {
|
|
120
153
|
method: "PUT",
|
|
121
154
|
headers: { "Content-Type": "application/json" },
|
|
122
155
|
body: JSON.stringify({ servers: {} })
|
|
@@ -129,7 +162,7 @@ async function ensureBaseConfig(serverName = DEFAULT_SERVER_NAME) {
|
|
|
129
162
|
hasServers = true;
|
|
130
163
|
}
|
|
131
164
|
if (!hasServers) {
|
|
132
|
-
const createServersRes = await fetch(`${
|
|
165
|
+
const createServersRes = await fetch(`${resolvedApiUrl}/config/apps/http/servers`, {
|
|
133
166
|
method: "PUT",
|
|
134
167
|
headers: { "Content-Type": "application/json" },
|
|
135
168
|
body: JSON.stringify({})
|
|
@@ -149,8 +182,9 @@ async function ensureBaseConfig(serverName = DEFAULT_SERVER_NAME) {
|
|
|
149
182
|
throw new Error(`Failed to initialize Caddy base configuration: ${text}`);
|
|
150
183
|
}
|
|
151
184
|
}
|
|
152
|
-
async function ensureTlsAutomation() {
|
|
153
|
-
const
|
|
185
|
+
async function ensureTlsAutomation(apiUrl) {
|
|
186
|
+
const resolvedApiUrl = getApiUrl(apiUrl);
|
|
187
|
+
const policiesUrl = `${resolvedApiUrl}/config/apps/tls/automation/policies`;
|
|
154
188
|
const policiesRes = await fetch(policiesUrl);
|
|
155
189
|
if (policiesRes.ok) return;
|
|
156
190
|
const policiesText = await policiesRes.text();
|
|
@@ -159,7 +193,7 @@ async function ensureTlsAutomation() {
|
|
|
159
193
|
`Failed to initialize Caddy TLS automation: ${policiesText}`
|
|
160
194
|
);
|
|
161
195
|
}
|
|
162
|
-
const automationRes = await fetch(`${
|
|
196
|
+
const automationRes = await fetch(`${resolvedApiUrl}/config/apps/tls/automation`, {
|
|
163
197
|
method: "PUT",
|
|
164
198
|
headers: { "Content-Type": "application/json" },
|
|
165
199
|
body: JSON.stringify({ policies: [] })
|
|
@@ -171,7 +205,7 @@ async function ensureTlsAutomation() {
|
|
|
171
205
|
`Failed to initialize Caddy TLS automation: ${automationText}`
|
|
172
206
|
);
|
|
173
207
|
}
|
|
174
|
-
const tlsRes = await fetch(`${
|
|
208
|
+
const tlsRes = await fetch(`${resolvedApiUrl}/config/apps/tls`, {
|
|
175
209
|
method: "PUT",
|
|
176
210
|
headers: { "Content-Type": "application/json" },
|
|
177
211
|
body: JSON.stringify({ automation: { policies: [] } })
|
|
@@ -187,7 +221,47 @@ function formatDialAddress(host, port) {
|
|
|
187
221
|
}
|
|
188
222
|
return `${host}:${port}`;
|
|
189
223
|
}
|
|
190
|
-
|
|
224
|
+
function extractMatchedHosts(route) {
|
|
225
|
+
if (!isRecord(route)) return [];
|
|
226
|
+
const match = route.match;
|
|
227
|
+
if (!Array.isArray(match)) return [];
|
|
228
|
+
const hosts = [];
|
|
229
|
+
for (const item of match) {
|
|
230
|
+
if (!isRecord(item) || !Array.isArray(item.host)) continue;
|
|
231
|
+
for (const host of item.host) {
|
|
232
|
+
if (typeof host === "string") {
|
|
233
|
+
hosts.push(host);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
return hosts;
|
|
238
|
+
}
|
|
239
|
+
function intersectsDomains(targetDomains, routeDomains) {
|
|
240
|
+
if (targetDomains.length === 0 || routeDomains.length === 0) return false;
|
|
241
|
+
const targetSet = new Set(targetDomains);
|
|
242
|
+
return routeDomains.some((domain) => targetSet.has(domain));
|
|
243
|
+
}
|
|
244
|
+
async function cleanupStaleRoutesForDomains(domains, currentRouteId, serverName = DEFAULT_SERVER_NAME, apiUrl) {
|
|
245
|
+
if (domains.length === 0) return;
|
|
246
|
+
const res = await fetch(
|
|
247
|
+
`${getApiUrl(apiUrl)}/config/apps/http/servers/${serverName}/routes`
|
|
248
|
+
);
|
|
249
|
+
if (!res.ok) return;
|
|
250
|
+
const text = await res.text();
|
|
251
|
+
const parsed = parseConfig(text);
|
|
252
|
+
if (!Array.isArray(parsed)) return;
|
|
253
|
+
for (const route of parsed) {
|
|
254
|
+
if (!isRecord(route)) continue;
|
|
255
|
+
const id = route["@id"];
|
|
256
|
+
if (typeof id !== "string") continue;
|
|
257
|
+
if (!id.startsWith("vite-proxy-")) continue;
|
|
258
|
+
if (id === currentRouteId) continue;
|
|
259
|
+
const routeDomains = extractMatchedHosts(route);
|
|
260
|
+
if (!intersectsDomains(domains, routeDomains)) continue;
|
|
261
|
+
await removeRoute(id, apiUrl);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
async function addRoute(id, domains, port, cors, serverName = DEFAULT_SERVER_NAME, upstreamHost = "127.0.0.1", upstreamHostHeader, apiUrl) {
|
|
191
265
|
const handlers = [];
|
|
192
266
|
if (cors) {
|
|
193
267
|
handlers.push({
|
|
@@ -238,7 +312,7 @@ async function addRoute(id, domains, port, cors, serverName = DEFAULT_SERVER_NAM
|
|
|
238
312
|
terminal: true
|
|
239
313
|
};
|
|
240
314
|
const res = await fetch(
|
|
241
|
-
`${
|
|
315
|
+
`${getApiUrl(apiUrl)}/config/apps/http/servers/${serverName}/routes`,
|
|
242
316
|
{
|
|
243
317
|
method: "POST",
|
|
244
318
|
// Append to routes list
|
|
@@ -251,8 +325,8 @@ async function addRoute(id, domains, port, cors, serverName = DEFAULT_SERVER_NAM
|
|
|
251
325
|
throw new Error(`Failed to add route: ${text}`);
|
|
252
326
|
}
|
|
253
327
|
}
|
|
254
|
-
async function addTlsPolicy(id, domains) {
|
|
255
|
-
await ensureTlsAutomation();
|
|
328
|
+
async function addTlsPolicy(id, domains, apiUrl) {
|
|
329
|
+
await ensureTlsAutomation(apiUrl);
|
|
256
330
|
const policy = {
|
|
257
331
|
"@id": id,
|
|
258
332
|
subjects: domains,
|
|
@@ -262,7 +336,7 @@ async function addTlsPolicy(id, domains) {
|
|
|
262
336
|
}
|
|
263
337
|
]
|
|
264
338
|
};
|
|
265
|
-
const res = await fetch(`${
|
|
339
|
+
const res = await fetch(`${getApiUrl(apiUrl)}/config/apps/tls/automation/policies`, {
|
|
266
340
|
method: "POST",
|
|
267
341
|
headers: { "Content-Type": "application/json" },
|
|
268
342
|
body: JSON.stringify(policy)
|
|
@@ -275,8 +349,8 @@ async function addTlsPolicy(id, domains) {
|
|
|
275
349
|
throw new Error(`Failed to add TLS policy: ${text}`);
|
|
276
350
|
}
|
|
277
351
|
}
|
|
278
|
-
async function removeRoute(id) {
|
|
279
|
-
const res = await fetch(`${
|
|
352
|
+
async function removeRoute(id, apiUrl) {
|
|
353
|
+
const res = await fetch(`${getApiUrl(apiUrl)}/id/${id}`, {
|
|
280
354
|
method: "DELETE"
|
|
281
355
|
});
|
|
282
356
|
if (!res.ok && res.status !== 404) {
|
|
@@ -285,8 +359,8 @@ async function removeRoute(id) {
|
|
|
285
359
|
}
|
|
286
360
|
return true;
|
|
287
361
|
}
|
|
288
|
-
async function removeTlsPolicy(id) {
|
|
289
|
-
const res = await fetch(`${
|
|
362
|
+
async function removeTlsPolicy(id, apiUrl) {
|
|
363
|
+
const res = await fetch(`${getApiUrl(apiUrl)}/id/${id}`, {
|
|
290
364
|
method: "DELETE"
|
|
291
365
|
});
|
|
292
366
|
if (!res.ok && res.status !== 404) {
|
|
@@ -295,6 +369,18 @@ async function removeTlsPolicy(id) {
|
|
|
295
369
|
}
|
|
296
370
|
return true;
|
|
297
371
|
}
|
|
372
|
+
async function ensureCaddyReady(serverName = DEFAULT_SERVER_NAME, apiUrl) {
|
|
373
|
+
await withApiLock(apiUrl, async () => {
|
|
374
|
+
let running = await isCaddyRunning(apiUrl);
|
|
375
|
+
if (!running) {
|
|
376
|
+
running = await startCaddy(apiUrl);
|
|
377
|
+
}
|
|
378
|
+
if (!running) {
|
|
379
|
+
throw new Error("Failed to start Caddy server.");
|
|
380
|
+
}
|
|
381
|
+
await ensureBaseConfig(serverName, apiUrl);
|
|
382
|
+
});
|
|
383
|
+
}
|
|
298
384
|
|
|
299
385
|
// src/index.ts
|
|
300
386
|
var LOOPBACK_DOMAINS = {
|
|
@@ -310,7 +396,7 @@ function getGitRepoInfo() {
|
|
|
310
396
|
try {
|
|
311
397
|
const repoRoot = execGit("git rev-parse --show-toplevel");
|
|
312
398
|
if (repoRoot) {
|
|
313
|
-
info.repo =
|
|
399
|
+
info.repo = path2.basename(repoRoot);
|
|
314
400
|
}
|
|
315
401
|
} catch (e) {
|
|
316
402
|
}
|
|
@@ -364,7 +450,13 @@ function buildDerivedDomain(options) {
|
|
|
364
450
|
const repoLabel = sanitizeDomainLabel(repo);
|
|
365
451
|
const branchLabel = sanitizeDomainLabel(branch);
|
|
366
452
|
if (!repoLabel || !branchLabel) return null;
|
|
367
|
-
|
|
453
|
+
const labels = [repoLabel, branchLabel];
|
|
454
|
+
if (options.instanceLabel !== void 0) {
|
|
455
|
+
const instanceLabel = sanitizeDomainLabel(options.instanceLabel);
|
|
456
|
+
if (!instanceLabel) return null;
|
|
457
|
+
labels.push(instanceLabel);
|
|
458
|
+
}
|
|
459
|
+
return `${labels.join(".")}.${baseDomain}`;
|
|
368
460
|
}
|
|
369
461
|
function normalizeDomain(domain) {
|
|
370
462
|
const trimmed = domain.trim().toLowerCase();
|
|
@@ -396,22 +488,27 @@ function viteCaddyTlsPlugin({
|
|
|
396
488
|
loopbackDomain,
|
|
397
489
|
repo,
|
|
398
490
|
branch,
|
|
491
|
+
instanceLabel,
|
|
399
492
|
cors,
|
|
400
493
|
serverName,
|
|
401
|
-
caddyApiUrl
|
|
494
|
+
caddyApiUrl,
|
|
402
495
|
internalTls,
|
|
403
496
|
upstreamHostHeader
|
|
404
497
|
} = {}) {
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
498
|
+
const normalizedApiUrl = caddyApiUrl ? normalizeCaddyApiUrl(caddyApiUrl) : null;
|
|
499
|
+
const pluginCaddyApiUrl = normalizedApiUrl ?? DEFAULT_CADDY_API_URL;
|
|
500
|
+
if (caddyApiUrl !== void 0 && !normalizedApiUrl) {
|
|
501
|
+
console.warn(
|
|
502
|
+
`caddyApiUrl is empty after trimming. Falling back to ${DEFAULT_CADDY_API_URL}.`
|
|
503
|
+
);
|
|
504
|
+
}
|
|
505
|
+
function getInstanceKey(domains, configRoot) {
|
|
506
|
+
const keyMaterial = JSON.stringify({
|
|
507
|
+
domains: [...domains].sort(),
|
|
508
|
+
cwd: process.cwd(),
|
|
509
|
+
root: configRoot ?? null
|
|
510
|
+
});
|
|
511
|
+
return createHash2("sha1").update(keyMaterial).digest("hex").slice(0, 12);
|
|
415
512
|
}
|
|
416
513
|
function isPreviewServer(server) {
|
|
417
514
|
return server.config.isProduction;
|
|
@@ -440,10 +537,11 @@ function viteCaddyTlsPlugin({
|
|
|
440
537
|
baseDomain,
|
|
441
538
|
loopbackDomain,
|
|
442
539
|
repo,
|
|
443
|
-
branch
|
|
540
|
+
branch,
|
|
541
|
+
instanceLabel
|
|
444
542
|
});
|
|
445
543
|
const domainArray = resolvedDomains ?? [];
|
|
446
|
-
const routeId = `vite-proxy-${
|
|
544
|
+
const routeId = `vite-proxy-${getInstanceKey(domainArray, config.root)}`;
|
|
447
545
|
const shouldUseInternalTls = internalTls ?? (baseDomain !== void 0 || loopbackDomain !== void 0 || domain !== void 0);
|
|
448
546
|
const tlsPolicyId = shouldUseInternalTls ? `${routeId}-tls` : null;
|
|
449
547
|
let cleanupStarted = false;
|
|
@@ -458,6 +556,9 @@ function viteCaddyTlsPlugin({
|
|
|
458
556
|
if (baseDomain !== void 0 && !normalizeBaseDomain(baseDomain)) {
|
|
459
557
|
issues.push("`baseDomain` is empty after trimming");
|
|
460
558
|
}
|
|
559
|
+
if (instanceLabel !== void 0 && !sanitizeDomainLabel(instanceLabel)) {
|
|
560
|
+
issues.push("`instanceLabel` is empty after sanitization");
|
|
561
|
+
}
|
|
461
562
|
const info = getGitRepoInfo();
|
|
462
563
|
const resolvedRepo = repo ?? info.repo;
|
|
463
564
|
const resolvedBranch = branch ?? info.branch;
|
|
@@ -553,9 +654,12 @@ function viteCaddyTlsPlugin({
|
|
|
553
654
|
if (cleanupStarted) return;
|
|
554
655
|
cleanupStarted = true;
|
|
555
656
|
if (tlsPolicyId) {
|
|
556
|
-
await removeWithRetry(
|
|
657
|
+
await removeWithRetry(
|
|
658
|
+
() => removeTlsPolicy(tlsPolicyId, pluginCaddyApiUrl),
|
|
659
|
+
"TLS policy"
|
|
660
|
+
);
|
|
557
661
|
}
|
|
558
|
-
await removeWithRetry(() => removeRoute(routeId), "route");
|
|
662
|
+
await removeWithRetry(() => removeRoute(routeId, pluginCaddyApiUrl), "route");
|
|
559
663
|
}
|
|
560
664
|
function onServerClose() {
|
|
561
665
|
void cleanupRoute();
|
|
@@ -599,32 +703,32 @@ function viteCaddyTlsPlugin({
|
|
|
599
703
|
if (!validateCaddyIsInstalled()) {
|
|
600
704
|
return;
|
|
601
705
|
}
|
|
602
|
-
let running = await isCaddyRunning();
|
|
603
|
-
if (!running) {
|
|
604
|
-
running = await startCaddy();
|
|
605
|
-
if (!running) {
|
|
606
|
-
console.error("Failed to start Caddy server.");
|
|
607
|
-
return;
|
|
608
|
-
}
|
|
609
|
-
}
|
|
610
706
|
try {
|
|
611
|
-
await
|
|
707
|
+
await ensureCaddyReady(serverName, pluginCaddyApiUrl);
|
|
612
708
|
} catch (e) {
|
|
613
709
|
console.error(
|
|
614
|
-
`Failed to configure Caddy base settings. Is the Caddy Admin API reachable at ${
|
|
710
|
+
`Failed to configure Caddy base settings. Is the Caddy Admin API reachable at ${pluginCaddyApiUrl}?`,
|
|
615
711
|
e
|
|
616
712
|
);
|
|
617
713
|
return;
|
|
618
714
|
}
|
|
619
715
|
const port = getServerPort();
|
|
620
716
|
const upstreamHost = getUpstreamHost();
|
|
717
|
+
await cleanupStaleRoutesForDomains(
|
|
718
|
+
domainArray,
|
|
719
|
+
routeId,
|
|
720
|
+
serverName,
|
|
721
|
+
pluginCaddyApiUrl
|
|
722
|
+
);
|
|
723
|
+
await removeRoute(routeId, pluginCaddyApiUrl);
|
|
621
724
|
if (tlsPolicyId) {
|
|
725
|
+
await removeTlsPolicy(tlsPolicyId, pluginCaddyApiUrl);
|
|
622
726
|
try {
|
|
623
|
-
await addTlsPolicy(tlsPolicyId, domainArray);
|
|
727
|
+
await addTlsPolicy(tlsPolicyId, domainArray, pluginCaddyApiUrl);
|
|
624
728
|
tlsPolicyAdded = true;
|
|
625
729
|
} catch (e) {
|
|
626
730
|
console.error(
|
|
627
|
-
`Failed to add TLS policy to Caddy. Is the Caddy Admin API reachable at ${
|
|
731
|
+
`Failed to add TLS policy to Caddy. Is the Caddy Admin API reachable at ${pluginCaddyApiUrl}?`,
|
|
628
732
|
e
|
|
629
733
|
);
|
|
630
734
|
return;
|
|
@@ -638,14 +742,15 @@ function viteCaddyTlsPlugin({
|
|
|
638
742
|
cors,
|
|
639
743
|
serverName,
|
|
640
744
|
upstreamHost,
|
|
641
|
-
upstreamHostHeader
|
|
745
|
+
upstreamHostHeader,
|
|
746
|
+
pluginCaddyApiUrl
|
|
642
747
|
);
|
|
643
748
|
} catch (e) {
|
|
644
749
|
if (tlsPolicyAdded && tlsPolicyId) {
|
|
645
|
-
await removeTlsPolicy(tlsPolicyId);
|
|
750
|
+
await removeTlsPolicy(tlsPolicyId, pluginCaddyApiUrl);
|
|
646
751
|
}
|
|
647
752
|
console.error(
|
|
648
|
-
`Failed to add route to Caddy. Is the Caddy Admin API reachable at ${
|
|
753
|
+
`Failed to add route to Caddy. Is the Caddy Admin API reachable at ${pluginCaddyApiUrl}?`,
|
|
649
754
|
e
|
|
650
755
|
);
|
|
651
756
|
return;
|
|
@@ -680,11 +785,8 @@ function viteCaddyTlsPlugin({
|
|
|
680
785
|
const originalListen = server.listen.bind(server);
|
|
681
786
|
server.listen = async function(port, isRestart) {
|
|
682
787
|
const result = await originalListen(port, isRestart);
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
} else {
|
|
686
|
-
updateResolvedTarget();
|
|
687
|
-
}
|
|
788
|
+
resolvedPort = null;
|
|
789
|
+
updateResolvedTarget();
|
|
688
790
|
runSetupOnce();
|
|
689
791
|
return result;
|
|
690
792
|
};
|
|
@@ -711,7 +813,8 @@ function viteCaddyTlsPlugin({
|
|
|
711
813
|
baseDomain,
|
|
712
814
|
loopbackDomain,
|
|
713
815
|
repo,
|
|
714
|
-
branch
|
|
816
|
+
branch,
|
|
817
|
+
instanceLabel
|
|
715
818
|
});
|
|
716
819
|
const defaultHmrDomain = resolvedDomains?.[0];
|
|
717
820
|
const hmrConfig = userConfig.server?.hmr === void 0 && defaultHmrDomain ? {
|