unplugin-cloudflare-tunnel 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/{.github/README.md → README.md} +125 -32
- package/dist/astro.d.mts +1 -1
- package/dist/astro.mjs +2 -1
- package/dist/esbuild.d.mts +1 -1
- package/dist/esbuild.mjs +1 -1
- package/dist/farm.d.mts +1 -1
- package/dist/farm.mjs +1 -1
- package/dist/index.d.mts +2 -172
- package/dist/index.mjs +1 -1088
- package/dist/options-DI3sWmXl.d.mts +67 -0
- package/dist/rolldown.d.mts +2677 -626
- package/dist/rolldown.mjs +1 -1
- package/dist/rollup.d.mts +1 -1
- package/dist/rollup.mjs +1 -1
- package/dist/rspack.d.mts +1 -1
- package/dist/rspack.mjs +1 -1
- package/dist/src-D0eR3kCb.mjs +1949 -0
- package/dist/vite.d.mts +1 -1
- package/dist/vite.mjs +1 -1
- package/dist/webpack.d.mts +1 -1
- package/dist/webpack.mjs +1 -1
- package/package.json +23 -21
- package/dist/api.d.mts +0 -53
- package/dist/api.mjs +0 -58
- package/dist/schemas-Cpk3vGGi.mjs +0 -792
- package/dist/schemas-DKJtFAG_.d.mts +0 -702
|
@@ -0,0 +1,1949 @@
|
|
|
1
|
+
import * as NodeModule from "node:module";
|
|
2
|
+
import { bin, install } from "cloudflared";
|
|
3
|
+
import * as NodeUtil from "node:util";
|
|
4
|
+
import * as NodeChildProcess from "node:child_process";
|
|
5
|
+
import { createUnplugin } from "unplugin";
|
|
6
|
+
import NodeFS from "node:fs/promises";
|
|
7
|
+
Object.freeze({ status: "aborted" });
|
|
8
|
+
function $constructor(name, initializer, params) {
|
|
9
|
+
function init(inst, def) {
|
|
10
|
+
if (!inst._zod) Object.defineProperty(inst, "_zod", {
|
|
11
|
+
value: {
|
|
12
|
+
def,
|
|
13
|
+
constr: _,
|
|
14
|
+
traits: /* @__PURE__ */ new Set()
|
|
15
|
+
},
|
|
16
|
+
enumerable: false
|
|
17
|
+
});
|
|
18
|
+
if (inst._zod.traits.has(name)) return;
|
|
19
|
+
inst._zod.traits.add(name);
|
|
20
|
+
initializer(inst, def);
|
|
21
|
+
const proto = _.prototype;
|
|
22
|
+
const keys = Object.keys(proto);
|
|
23
|
+
for (let i = 0; i < keys.length; i++) {
|
|
24
|
+
const k = keys[i];
|
|
25
|
+
if (!(k in inst)) inst[k] = proto[k].bind(inst);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
const Parent = params?.Parent ?? Object;
|
|
29
|
+
class Definition extends Parent {}
|
|
30
|
+
Object.defineProperty(Definition, "name", { value: name });
|
|
31
|
+
function _(def) {
|
|
32
|
+
var _a;
|
|
33
|
+
const inst = params?.Parent ? new Definition() : this;
|
|
34
|
+
init(inst, def);
|
|
35
|
+
(_a = inst._zod).deferred ?? (_a.deferred = []);
|
|
36
|
+
for (const fn of inst._zod.deferred) fn();
|
|
37
|
+
return inst;
|
|
38
|
+
}
|
|
39
|
+
Object.defineProperty(_, "init", { value: init });
|
|
40
|
+
Object.defineProperty(_, Symbol.hasInstance, { value: (inst) => {
|
|
41
|
+
if (params?.Parent && inst instanceof params.Parent) return true;
|
|
42
|
+
return inst?._zod?.traits?.has(name);
|
|
43
|
+
} });
|
|
44
|
+
Object.defineProperty(_, "name", { value: name });
|
|
45
|
+
return _;
|
|
46
|
+
}
|
|
47
|
+
var $ZodAsyncError = class extends Error {
|
|
48
|
+
constructor() {
|
|
49
|
+
super(`Encountered Promise during synchronous parse. Use .parseAsync() instead.`);
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
const globalConfig = {};
|
|
53
|
+
function config(newConfig) {
|
|
54
|
+
if (newConfig) Object.assign(globalConfig, newConfig);
|
|
55
|
+
return globalConfig;
|
|
56
|
+
}
|
|
57
|
+
//#endregion
|
|
58
|
+
//#region node_modules/zod/v4/core/util.js
|
|
59
|
+
function jsonStringifyReplacer(_, value) {
|
|
60
|
+
if (typeof value === "bigint") return value.toString();
|
|
61
|
+
return value;
|
|
62
|
+
}
|
|
63
|
+
function cached(getter) {
|
|
64
|
+
return { get value() {
|
|
65
|
+
{
|
|
66
|
+
const value = getter();
|
|
67
|
+
Object.defineProperty(this, "value", { value });
|
|
68
|
+
return value;
|
|
69
|
+
}
|
|
70
|
+
throw new Error("cached value already set");
|
|
71
|
+
} };
|
|
72
|
+
}
|
|
73
|
+
function cleanRegex(source) {
|
|
74
|
+
const start = source.startsWith("^") ? 1 : 0;
|
|
75
|
+
const end = source.endsWith("$") ? source.length - 1 : source.length;
|
|
76
|
+
return source.slice(start, end);
|
|
77
|
+
}
|
|
78
|
+
const EVALUATING = Symbol("evaluating");
|
|
79
|
+
function defineLazy(object, key, getter) {
|
|
80
|
+
let value = void 0;
|
|
81
|
+
Object.defineProperty(object, key, {
|
|
82
|
+
get() {
|
|
83
|
+
if (value === EVALUATING) return;
|
|
84
|
+
if (value === void 0) {
|
|
85
|
+
value = EVALUATING;
|
|
86
|
+
value = getter();
|
|
87
|
+
}
|
|
88
|
+
return value;
|
|
89
|
+
},
|
|
90
|
+
set(v) {
|
|
91
|
+
Object.defineProperty(object, key, { value: v });
|
|
92
|
+
},
|
|
93
|
+
configurable: true
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
const captureStackTrace = "captureStackTrace" in Error ? Error.captureStackTrace : (..._args) => {};
|
|
97
|
+
function isObject(data) {
|
|
98
|
+
return typeof data === "object" && data !== null && !Array.isArray(data);
|
|
99
|
+
}
|
|
100
|
+
cached(() => {
|
|
101
|
+
if (typeof navigator !== "undefined" && navigator?.userAgent?.includes("Cloudflare")) return false;
|
|
102
|
+
try {
|
|
103
|
+
new Function("");
|
|
104
|
+
return true;
|
|
105
|
+
} catch (_) {
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
function clone(inst, def, params) {
|
|
110
|
+
const cl = new inst._zod.constr(def ?? inst._zod.def);
|
|
111
|
+
if (!def || params?.parent) cl._zod.parent = inst;
|
|
112
|
+
return cl;
|
|
113
|
+
}
|
|
114
|
+
function normalizeParams(_params) {
|
|
115
|
+
const params = _params;
|
|
116
|
+
if (!params) return {};
|
|
117
|
+
if (typeof params === "string") return { error: () => params };
|
|
118
|
+
if (params?.message !== void 0) {
|
|
119
|
+
if (params?.error !== void 0) throw new Error("Cannot specify both `message` and `error` params");
|
|
120
|
+
params.error = params.message;
|
|
121
|
+
}
|
|
122
|
+
delete params.message;
|
|
123
|
+
if (typeof params.error === "string") return {
|
|
124
|
+
...params,
|
|
125
|
+
error: () => params.error
|
|
126
|
+
};
|
|
127
|
+
return params;
|
|
128
|
+
}
|
|
129
|
+
function optionalKeys(shape) {
|
|
130
|
+
return Object.keys(shape).filter((k) => {
|
|
131
|
+
return shape[k]._zod.optin === "optional" && shape[k]._zod.optout === "optional";
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER, -Number.MAX_VALUE, Number.MAX_VALUE;
|
|
135
|
+
function aborted(x, startIndex = 0) {
|
|
136
|
+
if (x.aborted === true) return true;
|
|
137
|
+
for (let i = startIndex; i < x.issues.length; i++) if (x.issues[i]?.continue !== true) return true;
|
|
138
|
+
return false;
|
|
139
|
+
}
|
|
140
|
+
function prefixIssues(path, issues) {
|
|
141
|
+
return issues.map((iss) => {
|
|
142
|
+
var _a;
|
|
143
|
+
(_a = iss).path ?? (_a.path = []);
|
|
144
|
+
iss.path.unshift(path);
|
|
145
|
+
return iss;
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
function unwrapMessage(message) {
|
|
149
|
+
return typeof message === "string" ? message : message?.message;
|
|
150
|
+
}
|
|
151
|
+
function finalizeIssue(iss, ctx, config) {
|
|
152
|
+
const full = {
|
|
153
|
+
...iss,
|
|
154
|
+
path: iss.path ?? []
|
|
155
|
+
};
|
|
156
|
+
if (!iss.message) full.message = unwrapMessage(iss.inst?._zod.def?.error?.(iss)) ?? unwrapMessage(ctx?.error?.(iss)) ?? unwrapMessage(config.customError?.(iss)) ?? unwrapMessage(config.localeError?.(iss)) ?? "Invalid input";
|
|
157
|
+
delete full.inst;
|
|
158
|
+
delete full.continue;
|
|
159
|
+
if (!ctx?.reportInput) delete full.input;
|
|
160
|
+
return full;
|
|
161
|
+
}
|
|
162
|
+
//#endregion
|
|
163
|
+
//#region node_modules/zod/v4/core/errors.js
|
|
164
|
+
const initializer = (inst, def) => {
|
|
165
|
+
inst.name = "$ZodError";
|
|
166
|
+
Object.defineProperty(inst, "_zod", {
|
|
167
|
+
value: inst._zod,
|
|
168
|
+
enumerable: false
|
|
169
|
+
});
|
|
170
|
+
Object.defineProperty(inst, "issues", {
|
|
171
|
+
value: def,
|
|
172
|
+
enumerable: false
|
|
173
|
+
});
|
|
174
|
+
inst.message = JSON.stringify(def, jsonStringifyReplacer, 2);
|
|
175
|
+
Object.defineProperty(inst, "toString", {
|
|
176
|
+
value: () => inst.message,
|
|
177
|
+
enumerable: false
|
|
178
|
+
});
|
|
179
|
+
};
|
|
180
|
+
const $ZodError = $constructor("$ZodError", initializer);
|
|
181
|
+
const $ZodRealError = $constructor("$ZodError", initializer, { Parent: Error });
|
|
182
|
+
//#endregion
|
|
183
|
+
//#region node_modules/zod/v4/core/parse.js
|
|
184
|
+
const _parse = (_Err) => (schema, value, _ctx, _params) => {
|
|
185
|
+
const ctx = _ctx ? Object.assign(_ctx, { async: false }) : { async: false };
|
|
186
|
+
const result = schema._zod.run({
|
|
187
|
+
value,
|
|
188
|
+
issues: []
|
|
189
|
+
}, ctx);
|
|
190
|
+
if (result instanceof Promise) throw new $ZodAsyncError();
|
|
191
|
+
if (result.issues.length) {
|
|
192
|
+
const e = new (_params?.Err ?? _Err)(result.issues.map((iss) => finalizeIssue(iss, ctx, config())));
|
|
193
|
+
captureStackTrace(e, _params?.callee);
|
|
194
|
+
throw e;
|
|
195
|
+
}
|
|
196
|
+
return result.value;
|
|
197
|
+
};
|
|
198
|
+
const parse = /* @__PURE__ */ _parse($ZodRealError);
|
|
199
|
+
const _parseAsync = (_Err) => async (schema, value, _ctx, params) => {
|
|
200
|
+
const ctx = _ctx ? Object.assign(_ctx, { async: true }) : { async: true };
|
|
201
|
+
let result = schema._zod.run({
|
|
202
|
+
value,
|
|
203
|
+
issues: []
|
|
204
|
+
}, ctx);
|
|
205
|
+
if (result instanceof Promise) result = await result;
|
|
206
|
+
if (result.issues.length) {
|
|
207
|
+
const e = new (params?.Err ?? _Err)(result.issues.map((iss) => finalizeIssue(iss, ctx, config())));
|
|
208
|
+
captureStackTrace(e, params?.callee);
|
|
209
|
+
throw e;
|
|
210
|
+
}
|
|
211
|
+
return result.value;
|
|
212
|
+
};
|
|
213
|
+
const parseAsync = /* @__PURE__ */ _parseAsync($ZodRealError);
|
|
214
|
+
const _safeParse = (_Err) => (schema, value, _ctx) => {
|
|
215
|
+
const ctx = _ctx ? {
|
|
216
|
+
..._ctx,
|
|
217
|
+
async: false
|
|
218
|
+
} : { async: false };
|
|
219
|
+
const result = schema._zod.run({
|
|
220
|
+
value,
|
|
221
|
+
issues: []
|
|
222
|
+
}, ctx);
|
|
223
|
+
if (result instanceof Promise) throw new $ZodAsyncError();
|
|
224
|
+
return result.issues.length ? {
|
|
225
|
+
success: false,
|
|
226
|
+
error: new (_Err ?? $ZodError)(result.issues.map((iss) => finalizeIssue(iss, ctx, config())))
|
|
227
|
+
} : {
|
|
228
|
+
success: true,
|
|
229
|
+
data: result.value
|
|
230
|
+
};
|
|
231
|
+
};
|
|
232
|
+
const safeParse = /* @__PURE__ */ _safeParse($ZodRealError);
|
|
233
|
+
const _safeParseAsync = (_Err) => async (schema, value, _ctx) => {
|
|
234
|
+
const ctx = _ctx ? Object.assign(_ctx, { async: true }) : { async: true };
|
|
235
|
+
let result = schema._zod.run({
|
|
236
|
+
value,
|
|
237
|
+
issues: []
|
|
238
|
+
}, ctx);
|
|
239
|
+
if (result instanceof Promise) result = await result;
|
|
240
|
+
return result.issues.length ? {
|
|
241
|
+
success: false,
|
|
242
|
+
error: new _Err(result.issues.map((iss) => finalizeIssue(iss, ctx, config())))
|
|
243
|
+
} : {
|
|
244
|
+
success: true,
|
|
245
|
+
data: result.value
|
|
246
|
+
};
|
|
247
|
+
};
|
|
248
|
+
const safeParseAsync = /* @__PURE__ */ _safeParseAsync($ZodRealError);
|
|
249
|
+
const string$1 = (params) => {
|
|
250
|
+
const regex = params ? `[\\s\\S]{${params?.minimum ?? 0},${params?.maximum ?? ""}}` : `[\\s\\S]*`;
|
|
251
|
+
return new RegExp(`^${regex}$`);
|
|
252
|
+
};
|
|
253
|
+
const number$1 = /^-?\d+(?:\.\d+)?$/;
|
|
254
|
+
const boolean$1 = /^(?:true|false)$/i;
|
|
255
|
+
//#endregion
|
|
256
|
+
//#region node_modules/zod/v4/core/versions.js
|
|
257
|
+
const version = {
|
|
258
|
+
major: 4,
|
|
259
|
+
minor: 3,
|
|
260
|
+
patch: 6
|
|
261
|
+
};
|
|
262
|
+
//#endregion
|
|
263
|
+
//#region node_modules/zod/v4/core/schemas.js
|
|
264
|
+
const $ZodType = /* @__PURE__ */ $constructor("$ZodType", (inst, def) => {
|
|
265
|
+
var _a;
|
|
266
|
+
inst ?? (inst = {});
|
|
267
|
+
inst._zod.def = def;
|
|
268
|
+
inst._zod.bag = inst._zod.bag || {};
|
|
269
|
+
inst._zod.version = version;
|
|
270
|
+
const checks = [...inst._zod.def.checks ?? []];
|
|
271
|
+
if (inst._zod.traits.has("$ZodCheck")) checks.unshift(inst);
|
|
272
|
+
for (const ch of checks) for (const fn of ch._zod.onattach) fn(inst);
|
|
273
|
+
if (checks.length === 0) {
|
|
274
|
+
(_a = inst._zod).deferred ?? (_a.deferred = []);
|
|
275
|
+
inst._zod.deferred?.push(() => {
|
|
276
|
+
inst._zod.run = inst._zod.parse;
|
|
277
|
+
});
|
|
278
|
+
} else {
|
|
279
|
+
const runChecks = (payload, checks, ctx) => {
|
|
280
|
+
let isAborted = aborted(payload);
|
|
281
|
+
let asyncResult;
|
|
282
|
+
for (const ch of checks) {
|
|
283
|
+
if (ch._zod.def.when) {
|
|
284
|
+
if (!ch._zod.def.when(payload)) continue;
|
|
285
|
+
} else if (isAborted) continue;
|
|
286
|
+
const currLen = payload.issues.length;
|
|
287
|
+
const _ = ch._zod.check(payload);
|
|
288
|
+
if (_ instanceof Promise && ctx?.async === false) throw new $ZodAsyncError();
|
|
289
|
+
if (asyncResult || _ instanceof Promise) asyncResult = (asyncResult ?? Promise.resolve()).then(async () => {
|
|
290
|
+
await _;
|
|
291
|
+
if (payload.issues.length === currLen) return;
|
|
292
|
+
if (!isAborted) isAborted = aborted(payload, currLen);
|
|
293
|
+
});
|
|
294
|
+
else {
|
|
295
|
+
if (payload.issues.length === currLen) continue;
|
|
296
|
+
if (!isAborted) isAborted = aborted(payload, currLen);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
if (asyncResult) return asyncResult.then(() => {
|
|
300
|
+
return payload;
|
|
301
|
+
});
|
|
302
|
+
return payload;
|
|
303
|
+
};
|
|
304
|
+
const handleCanaryResult = (canary, payload, ctx) => {
|
|
305
|
+
if (aborted(canary)) {
|
|
306
|
+
canary.aborted = true;
|
|
307
|
+
return canary;
|
|
308
|
+
}
|
|
309
|
+
const checkResult = runChecks(payload, checks, ctx);
|
|
310
|
+
if (checkResult instanceof Promise) {
|
|
311
|
+
if (ctx.async === false) throw new $ZodAsyncError();
|
|
312
|
+
return checkResult.then((checkResult) => inst._zod.parse(checkResult, ctx));
|
|
313
|
+
}
|
|
314
|
+
return inst._zod.parse(checkResult, ctx);
|
|
315
|
+
};
|
|
316
|
+
inst._zod.run = (payload, ctx) => {
|
|
317
|
+
if (ctx.skipChecks) return inst._zod.parse(payload, ctx);
|
|
318
|
+
if (ctx.direction === "backward") {
|
|
319
|
+
const canary = inst._zod.parse({
|
|
320
|
+
value: payload.value,
|
|
321
|
+
issues: []
|
|
322
|
+
}, {
|
|
323
|
+
...ctx,
|
|
324
|
+
skipChecks: true
|
|
325
|
+
});
|
|
326
|
+
if (canary instanceof Promise) return canary.then((canary) => {
|
|
327
|
+
return handleCanaryResult(canary, payload, ctx);
|
|
328
|
+
});
|
|
329
|
+
return handleCanaryResult(canary, payload, ctx);
|
|
330
|
+
}
|
|
331
|
+
const result = inst._zod.parse(payload, ctx);
|
|
332
|
+
if (result instanceof Promise) {
|
|
333
|
+
if (ctx.async === false) throw new $ZodAsyncError();
|
|
334
|
+
return result.then((result) => runChecks(result, checks, ctx));
|
|
335
|
+
}
|
|
336
|
+
return runChecks(result, checks, ctx);
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
defineLazy(inst, "~standard", () => ({
|
|
340
|
+
validate: (value) => {
|
|
341
|
+
try {
|
|
342
|
+
const r = safeParse(inst, value);
|
|
343
|
+
return r.success ? { value: r.data } : { issues: r.error?.issues };
|
|
344
|
+
} catch (_) {
|
|
345
|
+
return safeParseAsync(inst, value).then((r) => r.success ? { value: r.data } : { issues: r.error?.issues });
|
|
346
|
+
}
|
|
347
|
+
},
|
|
348
|
+
vendor: "zod",
|
|
349
|
+
version: 1
|
|
350
|
+
}));
|
|
351
|
+
});
|
|
352
|
+
const $ZodString = /* @__PURE__ */ $constructor("$ZodString", (inst, def) => {
|
|
353
|
+
$ZodType.init(inst, def);
|
|
354
|
+
inst._zod.pattern = [...inst?._zod.bag?.patterns ?? []].pop() ?? string$1(inst._zod.bag);
|
|
355
|
+
inst._zod.parse = (payload, _) => {
|
|
356
|
+
if (def.coerce) try {
|
|
357
|
+
payload.value = String(payload.value);
|
|
358
|
+
} catch (_) {}
|
|
359
|
+
if (typeof payload.value === "string") return payload;
|
|
360
|
+
payload.issues.push({
|
|
361
|
+
expected: "string",
|
|
362
|
+
code: "invalid_type",
|
|
363
|
+
input: payload.value,
|
|
364
|
+
inst
|
|
365
|
+
});
|
|
366
|
+
return payload;
|
|
367
|
+
};
|
|
368
|
+
});
|
|
369
|
+
const $ZodNumber = /* @__PURE__ */ $constructor("$ZodNumber", (inst, def) => {
|
|
370
|
+
$ZodType.init(inst, def);
|
|
371
|
+
inst._zod.pattern = inst._zod.bag.pattern ?? number$1;
|
|
372
|
+
inst._zod.parse = (payload, _ctx) => {
|
|
373
|
+
if (def.coerce) try {
|
|
374
|
+
payload.value = Number(payload.value);
|
|
375
|
+
} catch (_) {}
|
|
376
|
+
const input = payload.value;
|
|
377
|
+
if (typeof input === "number" && !Number.isNaN(input) && Number.isFinite(input)) return payload;
|
|
378
|
+
const received = typeof input === "number" ? Number.isNaN(input) ? "NaN" : !Number.isFinite(input) ? "Infinity" : void 0 : void 0;
|
|
379
|
+
payload.issues.push({
|
|
380
|
+
expected: "number",
|
|
381
|
+
code: "invalid_type",
|
|
382
|
+
input,
|
|
383
|
+
inst,
|
|
384
|
+
...received ? { received } : {}
|
|
385
|
+
});
|
|
386
|
+
return payload;
|
|
387
|
+
};
|
|
388
|
+
});
|
|
389
|
+
const $ZodBoolean = /* @__PURE__ */ $constructor("$ZodBoolean", (inst, def) => {
|
|
390
|
+
$ZodType.init(inst, def);
|
|
391
|
+
inst._zod.pattern = boolean$1;
|
|
392
|
+
inst._zod.parse = (payload, _ctx) => {
|
|
393
|
+
if (def.coerce) try {
|
|
394
|
+
payload.value = Boolean(payload.value);
|
|
395
|
+
} catch (_) {}
|
|
396
|
+
const input = payload.value;
|
|
397
|
+
if (typeof input === "boolean") return payload;
|
|
398
|
+
payload.issues.push({
|
|
399
|
+
expected: "boolean",
|
|
400
|
+
code: "invalid_type",
|
|
401
|
+
input,
|
|
402
|
+
inst
|
|
403
|
+
});
|
|
404
|
+
return payload;
|
|
405
|
+
};
|
|
406
|
+
});
|
|
407
|
+
const $ZodAny = /* @__PURE__ */ $constructor("$ZodAny", (inst, def) => {
|
|
408
|
+
$ZodType.init(inst, def);
|
|
409
|
+
inst._zod.parse = (payload) => payload;
|
|
410
|
+
});
|
|
411
|
+
const $ZodUnknown = /* @__PURE__ */ $constructor("$ZodUnknown", (inst, def) => {
|
|
412
|
+
$ZodType.init(inst, def);
|
|
413
|
+
inst._zod.parse = (payload) => payload;
|
|
414
|
+
});
|
|
415
|
+
function handleArrayResult(result, final, index) {
|
|
416
|
+
if (result.issues.length) final.issues.push(...prefixIssues(index, result.issues));
|
|
417
|
+
final.value[index] = result.value;
|
|
418
|
+
}
|
|
419
|
+
const $ZodArray = /* @__PURE__ */ $constructor("$ZodArray", (inst, def) => {
|
|
420
|
+
$ZodType.init(inst, def);
|
|
421
|
+
inst._zod.parse = (payload, ctx) => {
|
|
422
|
+
const input = payload.value;
|
|
423
|
+
if (!Array.isArray(input)) {
|
|
424
|
+
payload.issues.push({
|
|
425
|
+
expected: "array",
|
|
426
|
+
code: "invalid_type",
|
|
427
|
+
input,
|
|
428
|
+
inst
|
|
429
|
+
});
|
|
430
|
+
return payload;
|
|
431
|
+
}
|
|
432
|
+
payload.value = Array(input.length);
|
|
433
|
+
const proms = [];
|
|
434
|
+
for (let i = 0; i < input.length; i++) {
|
|
435
|
+
const item = input[i];
|
|
436
|
+
const result = def.element._zod.run({
|
|
437
|
+
value: item,
|
|
438
|
+
issues: []
|
|
439
|
+
}, ctx);
|
|
440
|
+
if (result instanceof Promise) proms.push(result.then((result) => handleArrayResult(result, payload, i)));
|
|
441
|
+
else handleArrayResult(result, payload, i);
|
|
442
|
+
}
|
|
443
|
+
if (proms.length) return Promise.all(proms).then(() => payload);
|
|
444
|
+
return payload;
|
|
445
|
+
};
|
|
446
|
+
});
|
|
447
|
+
function handlePropertyResult(result, final, key, input, isOptionalOut) {
|
|
448
|
+
if (result.issues.length) {
|
|
449
|
+
if (isOptionalOut && !(key in input)) return;
|
|
450
|
+
final.issues.push(...prefixIssues(key, result.issues));
|
|
451
|
+
}
|
|
452
|
+
if (result.value === void 0) {
|
|
453
|
+
if (key in input) final.value[key] = void 0;
|
|
454
|
+
} else final.value[key] = result.value;
|
|
455
|
+
}
|
|
456
|
+
function normalizeDef(def) {
|
|
457
|
+
const keys = Object.keys(def.shape);
|
|
458
|
+
for (const k of keys) if (!def.shape?.[k]?._zod?.traits?.has("$ZodType")) throw new Error(`Invalid element at key "${k}": expected a Zod schema`);
|
|
459
|
+
const okeys = optionalKeys(def.shape);
|
|
460
|
+
return {
|
|
461
|
+
...def,
|
|
462
|
+
keys,
|
|
463
|
+
keySet: new Set(keys),
|
|
464
|
+
numKeys: keys.length,
|
|
465
|
+
optionalKeys: new Set(okeys)
|
|
466
|
+
};
|
|
467
|
+
}
|
|
468
|
+
function handleCatchall(proms, input, payload, ctx, def, inst) {
|
|
469
|
+
const unrecognized = [];
|
|
470
|
+
const keySet = def.keySet;
|
|
471
|
+
const _catchall = def.catchall._zod;
|
|
472
|
+
const t = _catchall.def.type;
|
|
473
|
+
const isOptionalOut = _catchall.optout === "optional";
|
|
474
|
+
for (const key in input) {
|
|
475
|
+
if (keySet.has(key)) continue;
|
|
476
|
+
if (t === "never") {
|
|
477
|
+
unrecognized.push(key);
|
|
478
|
+
continue;
|
|
479
|
+
}
|
|
480
|
+
const r = _catchall.run({
|
|
481
|
+
value: input[key],
|
|
482
|
+
issues: []
|
|
483
|
+
}, ctx);
|
|
484
|
+
if (r instanceof Promise) proms.push(r.then((r) => handlePropertyResult(r, payload, key, input, isOptionalOut)));
|
|
485
|
+
else handlePropertyResult(r, payload, key, input, isOptionalOut);
|
|
486
|
+
}
|
|
487
|
+
if (unrecognized.length) payload.issues.push({
|
|
488
|
+
code: "unrecognized_keys",
|
|
489
|
+
keys: unrecognized,
|
|
490
|
+
input,
|
|
491
|
+
inst
|
|
492
|
+
});
|
|
493
|
+
if (!proms.length) return payload;
|
|
494
|
+
return Promise.all(proms).then(() => {
|
|
495
|
+
return payload;
|
|
496
|
+
});
|
|
497
|
+
}
|
|
498
|
+
const $ZodObject = /* @__PURE__ */ $constructor("$ZodObject", (inst, def) => {
|
|
499
|
+
$ZodType.init(inst, def);
|
|
500
|
+
if (!Object.getOwnPropertyDescriptor(def, "shape")?.get) {
|
|
501
|
+
const sh = def.shape;
|
|
502
|
+
Object.defineProperty(def, "shape", { get: () => {
|
|
503
|
+
const newSh = { ...sh };
|
|
504
|
+
Object.defineProperty(def, "shape", { value: newSh });
|
|
505
|
+
return newSh;
|
|
506
|
+
} });
|
|
507
|
+
}
|
|
508
|
+
const _normalized = cached(() => normalizeDef(def));
|
|
509
|
+
defineLazy(inst._zod, "propValues", () => {
|
|
510
|
+
const shape = def.shape;
|
|
511
|
+
const propValues = {};
|
|
512
|
+
for (const key in shape) {
|
|
513
|
+
const field = shape[key]._zod;
|
|
514
|
+
if (field.values) {
|
|
515
|
+
propValues[key] ?? (propValues[key] = /* @__PURE__ */ new Set());
|
|
516
|
+
for (const v of field.values) propValues[key].add(v);
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
return propValues;
|
|
520
|
+
});
|
|
521
|
+
const isObject$2 = isObject;
|
|
522
|
+
const catchall = def.catchall;
|
|
523
|
+
let value;
|
|
524
|
+
inst._zod.parse = (payload, ctx) => {
|
|
525
|
+
value ?? (value = _normalized.value);
|
|
526
|
+
const input = payload.value;
|
|
527
|
+
if (!isObject$2(input)) {
|
|
528
|
+
payload.issues.push({
|
|
529
|
+
expected: "object",
|
|
530
|
+
code: "invalid_type",
|
|
531
|
+
input,
|
|
532
|
+
inst
|
|
533
|
+
});
|
|
534
|
+
return payload;
|
|
535
|
+
}
|
|
536
|
+
payload.value = {};
|
|
537
|
+
const proms = [];
|
|
538
|
+
const shape = value.shape;
|
|
539
|
+
for (const key of value.keys) {
|
|
540
|
+
const el = shape[key];
|
|
541
|
+
const isOptionalOut = el._zod.optout === "optional";
|
|
542
|
+
const r = el._zod.run({
|
|
543
|
+
value: input[key],
|
|
544
|
+
issues: []
|
|
545
|
+
}, ctx);
|
|
546
|
+
if (r instanceof Promise) proms.push(r.then((r) => handlePropertyResult(r, payload, key, input, isOptionalOut)));
|
|
547
|
+
else handlePropertyResult(r, payload, key, input, isOptionalOut);
|
|
548
|
+
}
|
|
549
|
+
if (!catchall) return proms.length ? Promise.all(proms).then(() => payload) : payload;
|
|
550
|
+
return handleCatchall(proms, input, payload, ctx, _normalized.value, inst);
|
|
551
|
+
};
|
|
552
|
+
});
|
|
553
|
+
function handleOptionalResult(result, input) {
|
|
554
|
+
if (result.issues.length && input === void 0) return {
|
|
555
|
+
issues: [],
|
|
556
|
+
value: void 0
|
|
557
|
+
};
|
|
558
|
+
return result;
|
|
559
|
+
}
|
|
560
|
+
const $ZodOptional = /* @__PURE__ */ $constructor("$ZodOptional", (inst, def) => {
|
|
561
|
+
$ZodType.init(inst, def);
|
|
562
|
+
inst._zod.optin = "optional";
|
|
563
|
+
inst._zod.optout = "optional";
|
|
564
|
+
defineLazy(inst._zod, "values", () => {
|
|
565
|
+
return def.innerType._zod.values ? new Set([...def.innerType._zod.values, void 0]) : void 0;
|
|
566
|
+
});
|
|
567
|
+
defineLazy(inst._zod, "pattern", () => {
|
|
568
|
+
const pattern = def.innerType._zod.pattern;
|
|
569
|
+
return pattern ? new RegExp(`^(${cleanRegex(pattern.source)})?$`) : void 0;
|
|
570
|
+
});
|
|
571
|
+
inst._zod.parse = (payload, ctx) => {
|
|
572
|
+
if (def.innerType._zod.optin === "optional") {
|
|
573
|
+
const result = def.innerType._zod.run(payload, ctx);
|
|
574
|
+
if (result instanceof Promise) return result.then((r) => handleOptionalResult(r, payload.value));
|
|
575
|
+
return handleOptionalResult(result, payload.value);
|
|
576
|
+
}
|
|
577
|
+
if (payload.value === void 0) return payload;
|
|
578
|
+
return def.innerType._zod.run(payload, ctx);
|
|
579
|
+
};
|
|
580
|
+
});
|
|
581
|
+
const $ZodNullable = /* @__PURE__ */ $constructor("$ZodNullable", (inst, def) => {
|
|
582
|
+
$ZodType.init(inst, def);
|
|
583
|
+
defineLazy(inst._zod, "optin", () => def.innerType._zod.optin);
|
|
584
|
+
defineLazy(inst._zod, "optout", () => def.innerType._zod.optout);
|
|
585
|
+
defineLazy(inst._zod, "pattern", () => {
|
|
586
|
+
const pattern = def.innerType._zod.pattern;
|
|
587
|
+
return pattern ? new RegExp(`^(${cleanRegex(pattern.source)}|null)$`) : void 0;
|
|
588
|
+
});
|
|
589
|
+
defineLazy(inst._zod, "values", () => {
|
|
590
|
+
return def.innerType._zod.values ? new Set([...def.innerType._zod.values, null]) : void 0;
|
|
591
|
+
});
|
|
592
|
+
inst._zod.parse = (payload, ctx) => {
|
|
593
|
+
if (payload.value === null) return payload;
|
|
594
|
+
return def.innerType._zod.run(payload, ctx);
|
|
595
|
+
};
|
|
596
|
+
});
|
|
597
|
+
//#endregion
|
|
598
|
+
//#region node_modules/zod/v4/core/registries.js
|
|
599
|
+
var _a;
|
|
600
|
+
var $ZodRegistry = class {
|
|
601
|
+
constructor() {
|
|
602
|
+
this._map = /* @__PURE__ */ new WeakMap();
|
|
603
|
+
this._idmap = /* @__PURE__ */ new Map();
|
|
604
|
+
}
|
|
605
|
+
add(schema, ..._meta) {
|
|
606
|
+
const meta = _meta[0];
|
|
607
|
+
this._map.set(schema, meta);
|
|
608
|
+
if (meta && typeof meta === "object" && "id" in meta) this._idmap.set(meta.id, schema);
|
|
609
|
+
return this;
|
|
610
|
+
}
|
|
611
|
+
clear() {
|
|
612
|
+
this._map = /* @__PURE__ */ new WeakMap();
|
|
613
|
+
this._idmap = /* @__PURE__ */ new Map();
|
|
614
|
+
return this;
|
|
615
|
+
}
|
|
616
|
+
remove(schema) {
|
|
617
|
+
const meta = this._map.get(schema);
|
|
618
|
+
if (meta && typeof meta === "object" && "id" in meta) this._idmap.delete(meta.id);
|
|
619
|
+
this._map.delete(schema);
|
|
620
|
+
return this;
|
|
621
|
+
}
|
|
622
|
+
get(schema) {
|
|
623
|
+
const p = schema._zod.parent;
|
|
624
|
+
if (p) {
|
|
625
|
+
const pm = { ...this.get(p) ?? {} };
|
|
626
|
+
delete pm.id;
|
|
627
|
+
const f = {
|
|
628
|
+
...pm,
|
|
629
|
+
...this._map.get(schema)
|
|
630
|
+
};
|
|
631
|
+
return Object.keys(f).length ? f : void 0;
|
|
632
|
+
}
|
|
633
|
+
return this._map.get(schema);
|
|
634
|
+
}
|
|
635
|
+
has(schema) {
|
|
636
|
+
return this._map.has(schema);
|
|
637
|
+
}
|
|
638
|
+
};
|
|
639
|
+
function registry() {
|
|
640
|
+
return new $ZodRegistry();
|
|
641
|
+
}
|
|
642
|
+
(_a = globalThis).__zod_globalRegistry ?? (_a.__zod_globalRegistry = registry());
|
|
643
|
+
globalThis.__zod_globalRegistry;
|
|
644
|
+
//#endregion
|
|
645
|
+
//#region node_modules/zod/v4/core/api.js
|
|
646
|
+
/* @__NO_SIDE_EFFECTS__ */
|
|
647
|
+
function _string(Class, params) {
|
|
648
|
+
return new Class({
|
|
649
|
+
type: "string",
|
|
650
|
+
...normalizeParams(params)
|
|
651
|
+
});
|
|
652
|
+
}
|
|
653
|
+
/* @__NO_SIDE_EFFECTS__ */
|
|
654
|
+
function _number(Class, params) {
|
|
655
|
+
return new Class({
|
|
656
|
+
type: "number",
|
|
657
|
+
checks: [],
|
|
658
|
+
...normalizeParams(params)
|
|
659
|
+
});
|
|
660
|
+
}
|
|
661
|
+
/* @__NO_SIDE_EFFECTS__ */
|
|
662
|
+
function _boolean(Class, params) {
|
|
663
|
+
return new Class({
|
|
664
|
+
type: "boolean",
|
|
665
|
+
...normalizeParams(params)
|
|
666
|
+
});
|
|
667
|
+
}
|
|
668
|
+
/* @__NO_SIDE_EFFECTS__ */
|
|
669
|
+
function _any(Class) {
|
|
670
|
+
return new Class({ type: "any" });
|
|
671
|
+
}
|
|
672
|
+
/* @__NO_SIDE_EFFECTS__ */
|
|
673
|
+
function _unknown(Class) {
|
|
674
|
+
return new Class({ type: "unknown" });
|
|
675
|
+
}
|
|
676
|
+
//#endregion
|
|
677
|
+
//#region node_modules/zod/v4/mini/schemas.js
|
|
678
|
+
const ZodMiniType = /* @__PURE__ */ $constructor("ZodMiniType", (inst, def) => {
|
|
679
|
+
if (!inst._zod) throw new Error("Uninitialized schema in ZodMiniType.");
|
|
680
|
+
$ZodType.init(inst, def);
|
|
681
|
+
inst.def = def;
|
|
682
|
+
inst.type = def.type;
|
|
683
|
+
inst.parse = (data, params) => parse(inst, data, params, { callee: inst.parse });
|
|
684
|
+
inst.safeParse = (data, params) => safeParse(inst, data, params);
|
|
685
|
+
inst.parseAsync = async (data, params) => parseAsync(inst, data, params, { callee: inst.parseAsync });
|
|
686
|
+
inst.safeParseAsync = async (data, params) => safeParseAsync(inst, data, params);
|
|
687
|
+
inst.check = (...checks) => {
|
|
688
|
+
return inst.clone({
|
|
689
|
+
...def,
|
|
690
|
+
checks: [...def.checks ?? [], ...checks.map((ch) => typeof ch === "function" ? { _zod: {
|
|
691
|
+
check: ch,
|
|
692
|
+
def: { check: "custom" },
|
|
693
|
+
onattach: []
|
|
694
|
+
} } : ch)]
|
|
695
|
+
}, { parent: true });
|
|
696
|
+
};
|
|
697
|
+
inst.with = inst.check;
|
|
698
|
+
inst.clone = (_def, params) => clone(inst, _def, params);
|
|
699
|
+
inst.brand = () => inst;
|
|
700
|
+
inst.register = ((reg, meta) => {
|
|
701
|
+
reg.add(inst, meta);
|
|
702
|
+
return inst;
|
|
703
|
+
});
|
|
704
|
+
inst.apply = (fn) => fn(inst);
|
|
705
|
+
});
|
|
706
|
+
const ZodMiniString = /* @__PURE__ */ $constructor("ZodMiniString", (inst, def) => {
|
|
707
|
+
$ZodString.init(inst, def);
|
|
708
|
+
ZodMiniType.init(inst, def);
|
|
709
|
+
});
|
|
710
|
+
/* @__NO_SIDE_EFFECTS__ */
|
|
711
|
+
function string(params) {
|
|
712
|
+
return /* @__PURE__ */ _string(ZodMiniString, params);
|
|
713
|
+
}
|
|
714
|
+
const ZodMiniNumber = /* @__PURE__ */ $constructor("ZodMiniNumber", (inst, def) => {
|
|
715
|
+
$ZodNumber.init(inst, def);
|
|
716
|
+
ZodMiniType.init(inst, def);
|
|
717
|
+
});
|
|
718
|
+
/* @__NO_SIDE_EFFECTS__ */
|
|
719
|
+
function number(params) {
|
|
720
|
+
return /* @__PURE__ */ _number(ZodMiniNumber, params);
|
|
721
|
+
}
|
|
722
|
+
const ZodMiniBoolean = /* @__PURE__ */ $constructor("ZodMiniBoolean", (inst, def) => {
|
|
723
|
+
$ZodBoolean.init(inst, def);
|
|
724
|
+
ZodMiniType.init(inst, def);
|
|
725
|
+
});
|
|
726
|
+
/* @__NO_SIDE_EFFECTS__ */
|
|
727
|
+
function boolean(params) {
|
|
728
|
+
return /* @__PURE__ */ _boolean(ZodMiniBoolean, params);
|
|
729
|
+
}
|
|
730
|
+
const ZodMiniAny = /* @__PURE__ */ $constructor("ZodMiniAny", (inst, def) => {
|
|
731
|
+
$ZodAny.init(inst, def);
|
|
732
|
+
ZodMiniType.init(inst, def);
|
|
733
|
+
});
|
|
734
|
+
/* @__NO_SIDE_EFFECTS__ */
|
|
735
|
+
function any() {
|
|
736
|
+
return /* @__PURE__ */ _any(ZodMiniAny);
|
|
737
|
+
}
|
|
738
|
+
const ZodMiniUnknown = /* @__PURE__ */ $constructor("ZodMiniUnknown", (inst, def) => {
|
|
739
|
+
$ZodUnknown.init(inst, def);
|
|
740
|
+
ZodMiniType.init(inst, def);
|
|
741
|
+
});
|
|
742
|
+
/* @__NO_SIDE_EFFECTS__ */
|
|
743
|
+
function unknown() {
|
|
744
|
+
return /* @__PURE__ */ _unknown(ZodMiniUnknown);
|
|
745
|
+
}
|
|
746
|
+
const ZodMiniArray = /* @__PURE__ */ $constructor("ZodMiniArray", (inst, def) => {
|
|
747
|
+
$ZodArray.init(inst, def);
|
|
748
|
+
ZodMiniType.init(inst, def);
|
|
749
|
+
});
|
|
750
|
+
/* @__NO_SIDE_EFFECTS__ */
|
|
751
|
+
function array(element, params) {
|
|
752
|
+
return new ZodMiniArray({
|
|
753
|
+
type: "array",
|
|
754
|
+
element,
|
|
755
|
+
...normalizeParams(params)
|
|
756
|
+
});
|
|
757
|
+
}
|
|
758
|
+
const ZodMiniObject = /* @__PURE__ */ $constructor("ZodMiniObject", (inst, def) => {
|
|
759
|
+
$ZodObject.init(inst, def);
|
|
760
|
+
ZodMiniType.init(inst, def);
|
|
761
|
+
defineLazy(inst, "shape", () => def.shape);
|
|
762
|
+
});
|
|
763
|
+
/* @__NO_SIDE_EFFECTS__ */
|
|
764
|
+
function object(shape, params) {
|
|
765
|
+
return new ZodMiniObject({
|
|
766
|
+
type: "object",
|
|
767
|
+
shape: shape ?? {},
|
|
768
|
+
...normalizeParams(params)
|
|
769
|
+
});
|
|
770
|
+
}
|
|
771
|
+
const ZodMiniOptional = /* @__PURE__ */ $constructor("ZodMiniOptional", (inst, def) => {
|
|
772
|
+
$ZodOptional.init(inst, def);
|
|
773
|
+
ZodMiniType.init(inst, def);
|
|
774
|
+
});
|
|
775
|
+
/* @__NO_SIDE_EFFECTS__ */
|
|
776
|
+
function optional(innerType) {
|
|
777
|
+
return new ZodMiniOptional({
|
|
778
|
+
type: "optional",
|
|
779
|
+
innerType
|
|
780
|
+
});
|
|
781
|
+
}
|
|
782
|
+
const ZodMiniNullable = /* @__PURE__ */ $constructor("ZodMiniNullable", (inst, def) => {
|
|
783
|
+
$ZodNullable.init(inst, def);
|
|
784
|
+
ZodMiniType.init(inst, def);
|
|
785
|
+
});
|
|
786
|
+
/* @__NO_SIDE_EFFECTS__ */
|
|
787
|
+
function nullable(innerType) {
|
|
788
|
+
return new ZodMiniNullable({
|
|
789
|
+
type: "nullable",
|
|
790
|
+
innerType
|
|
791
|
+
});
|
|
792
|
+
}
|
|
793
|
+
/* @__NO_SIDE_EFFECTS__ */
|
|
794
|
+
function nullish(innerType) {
|
|
795
|
+
return /* @__PURE__ */ optional(/* @__PURE__ */ nullable(innerType));
|
|
796
|
+
}
|
|
797
|
+
const CloudflareApiResponseSchema = /* @__PURE__ */ object({
|
|
798
|
+
success: /* @__PURE__ */ boolean(),
|
|
799
|
+
errors: /* @__PURE__ */ optional(/* @__PURE__ */ array(/* @__PURE__ */ object({
|
|
800
|
+
code: /* @__PURE__ */ number(),
|
|
801
|
+
message: /* @__PURE__ */ string()
|
|
802
|
+
}))),
|
|
803
|
+
messages: /* @__PURE__ */ optional(/* @__PURE__ */ array(/* @__PURE__ */ string())),
|
|
804
|
+
result: /* @__PURE__ */ unknown()
|
|
805
|
+
});
|
|
806
|
+
const AccountSchema = /* @__PURE__ */ object({
|
|
807
|
+
id: /* @__PURE__ */ string(),
|
|
808
|
+
name: /* @__PURE__ */ string()
|
|
809
|
+
});
|
|
810
|
+
const ZoneSchema = /* @__PURE__ */ object({
|
|
811
|
+
id: /* @__PURE__ */ string(),
|
|
812
|
+
name: /* @__PURE__ */ string(),
|
|
813
|
+
account: /* @__PURE__ */ optional(/* @__PURE__ */ object({ id: /* @__PURE__ */ string() }))
|
|
814
|
+
});
|
|
815
|
+
const TunnelSchema = /* @__PURE__ */ object({
|
|
816
|
+
id: /* @__PURE__ */ string(),
|
|
817
|
+
name: /* @__PURE__ */ string(),
|
|
818
|
+
account_tag: /* @__PURE__ */ string(),
|
|
819
|
+
created_at: /* @__PURE__ */ string(),
|
|
820
|
+
connections: /* @__PURE__ */ optional(/* @__PURE__ */ array(/* @__PURE__ */ unknown()))
|
|
821
|
+
});
|
|
822
|
+
const DNSRecordSchema = /* @__PURE__ */ object({
|
|
823
|
+
id: /* @__PURE__ */ string(),
|
|
824
|
+
type: /* @__PURE__ */ string(),
|
|
825
|
+
name: /* @__PURE__ */ string(),
|
|
826
|
+
content: /* @__PURE__ */ string(),
|
|
827
|
+
proxied: /* @__PURE__ */ boolean(),
|
|
828
|
+
comment: /* @__PURE__ */ nullish(/* @__PURE__ */ string())
|
|
829
|
+
});
|
|
830
|
+
function normalizeHost(host) {
|
|
831
|
+
if (!host || host === "0.0.0.0" || host === "::" || host === "::0") return "localhost";
|
|
832
|
+
return host;
|
|
833
|
+
}
|
|
834
|
+
function normalizeAddress(address) {
|
|
835
|
+
if (address && typeof address === "object") return {
|
|
836
|
+
host: normalizeHost("address" in address && address.address ? address.address : void 0),
|
|
837
|
+
port: "port" in address && typeof address.port === "number" ? address.port : void 0
|
|
838
|
+
};
|
|
839
|
+
return { host: "localhost" };
|
|
840
|
+
}
|
|
841
|
+
async function ensureCloudflaredBinary(binPath) {
|
|
842
|
+
try {
|
|
843
|
+
await NodeFS.access(binPath);
|
|
844
|
+
} catch {
|
|
845
|
+
console.log("[unplugin-cloudflare-tunnel] Installing cloudflared binary...");
|
|
846
|
+
await install(binPath);
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
function getLocalTarget(host, port) {
|
|
850
|
+
return `http://${host.includes(":") ? `[${host}]` : host}:${port}`;
|
|
851
|
+
}
|
|
852
|
+
//#endregion
|
|
853
|
+
//#region src/core/process.ts
|
|
854
|
+
function createKillCloudflared(params) {
|
|
855
|
+
const { getChild, clearTunnelUrl, markShuttingDown, debugLog = () => {}, platform = process.platform, exec = NodeChildProcess.exec, setTimeoutFn = setTimeout, clearTimeoutFn = clearTimeout } = params;
|
|
856
|
+
return (signal = "SIGTERM") => {
|
|
857
|
+
const child = getChild();
|
|
858
|
+
if (!child || child.killed) return Promise.resolve();
|
|
859
|
+
markShuttingDown();
|
|
860
|
+
clearTunnelUrl();
|
|
861
|
+
const activeChild = child;
|
|
862
|
+
return new Promise((resolve) => {
|
|
863
|
+
let settled = false;
|
|
864
|
+
let forceKillTimer;
|
|
865
|
+
const settle = () => {
|
|
866
|
+
if (settled) return;
|
|
867
|
+
settled = true;
|
|
868
|
+
if (forceKillTimer) clearTimeoutFn(forceKillTimer);
|
|
869
|
+
resolve();
|
|
870
|
+
};
|
|
871
|
+
activeChild.once("exit", () => {
|
|
872
|
+
settle();
|
|
873
|
+
});
|
|
874
|
+
try {
|
|
875
|
+
debugLog(`[unplugin-cloudflare-tunnel] Terminating cloudflared process (PID: ${activeChild.pid}) with ${signal}...`);
|
|
876
|
+
if (!activeChild.kill(signal)) {
|
|
877
|
+
if (platform === "win32") exec(`taskkill /pid ${activeChild.pid} /T /F`, () => settle());
|
|
878
|
+
else settle();
|
|
879
|
+
return;
|
|
880
|
+
}
|
|
881
|
+
if (signal === "SIGTERM") forceKillTimer = setTimeoutFn(() => {
|
|
882
|
+
if (settled) return;
|
|
883
|
+
debugLog("[unplugin-cloudflare-tunnel] Force killing cloudflared process...");
|
|
884
|
+
if (platform === "win32") exec(`taskkill /pid ${activeChild.pid} /T /F`, () => settle());
|
|
885
|
+
else try {
|
|
886
|
+
if (!activeChild.kill("SIGKILL")) settle();
|
|
887
|
+
} catch {
|
|
888
|
+
settle();
|
|
889
|
+
}
|
|
890
|
+
}, 2e3);
|
|
891
|
+
} catch (error) {
|
|
892
|
+
debugLog(`[unplugin-cloudflare-tunnel] Note: Error killing cloudflared: ${error instanceof Error ? error.message : String(error)}`);
|
|
893
|
+
settle();
|
|
894
|
+
}
|
|
895
|
+
});
|
|
896
|
+
};
|
|
897
|
+
}
|
|
898
|
+
//#endregion
|
|
899
|
+
//#region src/index.ts
|
|
900
|
+
/**
|
|
901
|
+
* @fileoverview Cloudflare Tunnel Unplugin
|
|
902
|
+
*
|
|
903
|
+
* A cross-bundler plugin that automatically creates and manages
|
|
904
|
+
* Cloudflare tunnels for local development, providing instant HTTPS access
|
|
905
|
+
* to your local dev server from anywhere on the internet.
|
|
906
|
+
*
|
|
907
|
+
* @author Cloudflare Tunnel Plugin Contributors
|
|
908
|
+
* @version 1.0.0
|
|
909
|
+
* @license MIT
|
|
910
|
+
*/
|
|
911
|
+
const PLUGIN_NAME = "unplugin-cloudflare-tunnel";
|
|
912
|
+
const INFO_LOG_REGEX = /^.*Z INF .*/;
|
|
913
|
+
const LOG_LEVEL_RANK = {
|
|
914
|
+
debug: 10,
|
|
915
|
+
info: 20,
|
|
916
|
+
warn: 30,
|
|
917
|
+
error: 40,
|
|
918
|
+
fatal: 50
|
|
919
|
+
};
|
|
920
|
+
function shouldLog(threshold, level) {
|
|
921
|
+
return LOG_LEVEL_RANK[level] >= LOG_LEVEL_RANK[threshold];
|
|
922
|
+
}
|
|
923
|
+
function supportsColor() {
|
|
924
|
+
if (!process.stdout.isTTY) return false;
|
|
925
|
+
if (process.env.NO_COLOR !== void 0) return false;
|
|
926
|
+
if (process.env.TERM === "dumb") return false;
|
|
927
|
+
if (process.env.FORCE_COLOR === "0") return false;
|
|
928
|
+
return true;
|
|
929
|
+
}
|
|
930
|
+
const ANSI = {
|
|
931
|
+
reset: "\x1B[0m",
|
|
932
|
+
dim: "\x1B[2m",
|
|
933
|
+
bold: "\x1B[1m",
|
|
934
|
+
blue: "\x1B[34m",
|
|
935
|
+
yellow: "\x1B[33m"
|
|
936
|
+
};
|
|
937
|
+
const ANSI_STYLE_SEQUENCE_REGEX = new RegExp(`${String.fromCharCode(27)}\\[[0-9;]*m`, "g");
|
|
938
|
+
function stripAnsi(text) {
|
|
939
|
+
return text.replace(ANSI_STYLE_SEQUENCE_REGEX, "");
|
|
940
|
+
}
|
|
941
|
+
function colorize(text, ansi) {
|
|
942
|
+
if (!supportsColor()) return text;
|
|
943
|
+
return `${ansi}${text}${ANSI.reset}`;
|
|
944
|
+
}
|
|
945
|
+
const unpluginFactory = (options = {}) => {
|
|
946
|
+
const { enabled = true } = options;
|
|
947
|
+
if (enabled === false) {
|
|
948
|
+
const VIRTUAL_MODULE_ID_STUB = "virtual:unplugin-cloudflare-tunnel";
|
|
949
|
+
return {
|
|
950
|
+
name: PLUGIN_NAME,
|
|
951
|
+
enforce: "pre",
|
|
952
|
+
resolveId(id) {
|
|
953
|
+
if (id === VIRTUAL_MODULE_ID_STUB) return id;
|
|
954
|
+
},
|
|
955
|
+
loadInclude(id) {
|
|
956
|
+
return id === VIRTUAL_MODULE_ID_STUB;
|
|
957
|
+
},
|
|
958
|
+
load(id) {
|
|
959
|
+
if (id === VIRTUAL_MODULE_ID_STUB) return "export function getTunnelUrl() { return \"\"; }";
|
|
960
|
+
}
|
|
961
|
+
};
|
|
962
|
+
}
|
|
963
|
+
const GLOBAL_STATE = Symbol.for("unplugin-cloudflare-tunnel.state");
|
|
964
|
+
const globalState = globalThis[GLOBAL_STATE] ?? {};
|
|
965
|
+
globalThis[GLOBAL_STATE] = globalState;
|
|
966
|
+
let child = globalState.child;
|
|
967
|
+
const VIRTUAL_MODULE_ID = "virtual:unplugin-cloudflare-tunnel";
|
|
968
|
+
const requestedMode = options.mode;
|
|
969
|
+
if (requestedMode && !["quick", "named"].includes(requestedMode)) throw new Error("[unplugin-cloudflare-tunnel] mode must be one of: 'quick', 'named'");
|
|
970
|
+
const hasHostname = "hostname" in options && typeof options.hostname === "string";
|
|
971
|
+
const isQuickMode = requestedMode ? requestedMode === "quick" : !hasHostname;
|
|
972
|
+
if (requestedMode === "named" && !hasHostname) throw new Error("[unplugin-cloudflare-tunnel] hostname is required when mode is set to named");
|
|
973
|
+
if (isQuickMode) {
|
|
974
|
+
const invalidOptions = [
|
|
975
|
+
"apiToken",
|
|
976
|
+
"accountId",
|
|
977
|
+
"zoneId",
|
|
978
|
+
"tunnelName",
|
|
979
|
+
"dns",
|
|
980
|
+
"ssl",
|
|
981
|
+
"cleanup"
|
|
982
|
+
].filter((opt) => opt in options);
|
|
983
|
+
if (invalidOptions.length > 0) throw new Error(`[unplugin-cloudflare-tunnel] The following options are only supported in named tunnel mode: ${invalidOptions.join(", ")}. Set mode to 'named' and provide a hostname, or remove these options for quick tunnel mode.`);
|
|
984
|
+
}
|
|
985
|
+
let providedApiToken;
|
|
986
|
+
let hostname;
|
|
987
|
+
let tunnelName;
|
|
988
|
+
let forcedAccount;
|
|
989
|
+
let forcedZone;
|
|
990
|
+
let dnsOption;
|
|
991
|
+
let sslOption;
|
|
992
|
+
let cleanupConfig;
|
|
993
|
+
if (isQuickMode) {
|
|
994
|
+
tunnelName = "quick-tunnel";
|
|
995
|
+
cleanupConfig = {};
|
|
996
|
+
} else {
|
|
997
|
+
const namedOptions = options;
|
|
998
|
+
providedApiToken = namedOptions.apiToken;
|
|
999
|
+
hostname = namedOptions.hostname;
|
|
1000
|
+
forcedAccount = namedOptions.accountId;
|
|
1001
|
+
forcedZone = namedOptions.zoneId;
|
|
1002
|
+
tunnelName = namedOptions.tunnelName || "dev-tunnel";
|
|
1003
|
+
dnsOption = namedOptions.dns;
|
|
1004
|
+
sslOption = namedOptions.ssl;
|
|
1005
|
+
cleanupConfig = namedOptions.cleanup || {};
|
|
1006
|
+
}
|
|
1007
|
+
const { port: userProvidedPort, logFile, logLevel, protocol = "http2", debug = false } = options;
|
|
1008
|
+
const effectivePluginLogLevel = logLevel ?? (debug ? "debug" : "info");
|
|
1009
|
+
const redactForDebug = (value) => {
|
|
1010
|
+
if (typeof value === "string") {
|
|
1011
|
+
if (value.startsWith("eyJ") && value.length > 40) return "[REDACTED_TOKEN]";
|
|
1012
|
+
return value;
|
|
1013
|
+
}
|
|
1014
|
+
if (Array.isArray(value)) return value.map((item) => redactForDebug(item));
|
|
1015
|
+
if (value && typeof value === "object") {
|
|
1016
|
+
const entries = Object.entries(value).map(([key, nestedValue]) => {
|
|
1017
|
+
if (/token|authorization|secret|password/i.test(key)) return [key, "[REDACTED]"];
|
|
1018
|
+
return [key, redactForDebug(nestedValue)];
|
|
1019
|
+
});
|
|
1020
|
+
return Object.fromEntries(entries);
|
|
1021
|
+
}
|
|
1022
|
+
return value;
|
|
1023
|
+
};
|
|
1024
|
+
const formatDebugValue = (value) => {
|
|
1025
|
+
const redactedValue = redactForDebug(value);
|
|
1026
|
+
if (typeof redactedValue === "string") return redactedValue;
|
|
1027
|
+
return NodeUtil.inspect(redactedValue, {
|
|
1028
|
+
depth: null,
|
|
1029
|
+
colors: supportsColor(),
|
|
1030
|
+
compact: false,
|
|
1031
|
+
breakLength: 120,
|
|
1032
|
+
sorted: true
|
|
1033
|
+
});
|
|
1034
|
+
};
|
|
1035
|
+
const pluginLog = {
|
|
1036
|
+
debug: (...args) => {
|
|
1037
|
+
if (debug || effectivePluginLogLevel === "debug") console.log("[cloudflare-tunnel:debug]", ...args.map((arg) => formatDebugValue(arg)));
|
|
1038
|
+
},
|
|
1039
|
+
info: (message) => {
|
|
1040
|
+
if (shouldLog(effectivePluginLogLevel, "info")) console.log(`[unplugin-cloudflare-tunnel] ${message}`);
|
|
1041
|
+
},
|
|
1042
|
+
warn: (message) => {
|
|
1043
|
+
if (shouldLog(effectivePluginLogLevel, "warn")) console.warn(`[unplugin-cloudflare-tunnel] ${message}`);
|
|
1044
|
+
},
|
|
1045
|
+
error: (message) => {
|
|
1046
|
+
if (shouldLog(effectivePluginLogLevel, "error")) console.error(`[unplugin-cloudflare-tunnel] ${message}`);
|
|
1047
|
+
}
|
|
1048
|
+
};
|
|
1049
|
+
const debugLog = pluginLog.debug;
|
|
1050
|
+
const makeLocalDisplay = (localTarget) => {
|
|
1051
|
+
if (!localTarget) return localTarget;
|
|
1052
|
+
return localTarget.replace("http://[::1]:", "http://localhost:").replace("http://127.0.0.1:", "http://localhost:");
|
|
1053
|
+
};
|
|
1054
|
+
const announceConnecting = () => {
|
|
1055
|
+
if (globalState.__tunnelConnectingAnnounced) return;
|
|
1056
|
+
globalState.__tunnelConnectingAnnounced = true;
|
|
1057
|
+
const message = isQuickMode ? "cf tunnel connecting…" : hostname ? `cf tunnel connecting… (${hostname})` : "cf tunnel connecting…";
|
|
1058
|
+
console.log("");
|
|
1059
|
+
console.log(colorize(message, ANSI.bold));
|
|
1060
|
+
};
|
|
1061
|
+
const announceTunnel = (params) => {
|
|
1062
|
+
if (!params.url) return;
|
|
1063
|
+
if (globalState.__lastAnnouncedTunnelKey === params.key) return;
|
|
1064
|
+
globalState.__lastAnnouncedTunnelKey = params.key;
|
|
1065
|
+
const cols = process.stdout.columns ?? 80;
|
|
1066
|
+
const maxWidth = Math.max(10, cols - 2);
|
|
1067
|
+
const header = `${colorize("[", ANSI.yellow)}unplugin-cloudflare-tunnel${colorize("]", ANSI.yellow)}`;
|
|
1068
|
+
const urlLine = colorize(params.url, ANSI.blue + ANSI.bold);
|
|
1069
|
+
const localLine = params.localTarget ? makeLocalDisplay(params.localTarget) : "";
|
|
1070
|
+
const headerPlainLen = stripAnsi(header).length;
|
|
1071
|
+
const contentPlainLen = Math.max(stripAnsi(urlLine).length, localLine.length, 10, 5);
|
|
1072
|
+
const width = Math.min(90, maxWidth, Math.max(44, headerPlainLen, contentPlainLen + 4));
|
|
1073
|
+
const rule = "─".repeat(width);
|
|
1074
|
+
const center = (text) => {
|
|
1075
|
+
const plainLen = stripAnsi(text).length;
|
|
1076
|
+
const pad = Math.max(0, Math.floor((width - plainLen) / 2));
|
|
1077
|
+
return `${" ".repeat(pad)}${text}`;
|
|
1078
|
+
};
|
|
1079
|
+
if (cols < 70) {
|
|
1080
|
+
const out = [];
|
|
1081
|
+
out.push("");
|
|
1082
|
+
out.push(`${header} ${colorize("Tunnel URL", ANSI.bold)} ${urlLine}`);
|
|
1083
|
+
if (localLine) out.push(`${header} ${colorize("Local", ANSI.dim + ANSI.bold)} ${localLine}`);
|
|
1084
|
+
out.push("");
|
|
1085
|
+
console.log(out.join("\n"));
|
|
1086
|
+
return;
|
|
1087
|
+
}
|
|
1088
|
+
const out = [];
|
|
1089
|
+
out.push("");
|
|
1090
|
+
out.push(center(header));
|
|
1091
|
+
out.push(rule);
|
|
1092
|
+
out.push(center(colorize("Tunnel URL", ANSI.bold)));
|
|
1093
|
+
out.push(center(urlLine));
|
|
1094
|
+
if (localLine) {
|
|
1095
|
+
out.push("");
|
|
1096
|
+
out.push(center(colorize("Local", ANSI.dim + ANSI.bold)));
|
|
1097
|
+
out.push(center(localLine));
|
|
1098
|
+
}
|
|
1099
|
+
out.push(rule);
|
|
1100
|
+
out.push("");
|
|
1101
|
+
console.log(out.join("\n"));
|
|
1102
|
+
};
|
|
1103
|
+
if (!isQuickMode && (!hostname || typeof hostname !== "string")) throw new Error("[unplugin-cloudflare-tunnel] hostname is required and must be a valid string in named tunnel mode");
|
|
1104
|
+
let tunnelUrl = hostname ? `https://${hostname}` : "";
|
|
1105
|
+
if (tunnelName && !/^[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?$/.test(tunnelName)) throw new Error("[unplugin-cloudflare-tunnel] tunnelName must contain only letters, numbers, and hyphens. It cannot start or end with a hyphen.");
|
|
1106
|
+
if (userProvidedPort && (typeof userProvidedPort !== "number" || userProvidedPort < 1 || userProvidedPort > 65535)) throw new Error("[unplugin-cloudflare-tunnel] port must be a valid number between 1 and 65535");
|
|
1107
|
+
if (logLevel && ![
|
|
1108
|
+
"debug",
|
|
1109
|
+
"info",
|
|
1110
|
+
"warn",
|
|
1111
|
+
"error",
|
|
1112
|
+
"fatal"
|
|
1113
|
+
].includes(logLevel)) throw new Error("[unplugin-cloudflare-tunnel] logLevel must be one of: debug, info, warn, error, fatal");
|
|
1114
|
+
const effectiveLogLevel = logLevel ?? (debug ? "info" : "warn");
|
|
1115
|
+
const cloudflaredProcessLogLevel = effectiveLogLevel === "debug" ? "debug" : "info";
|
|
1116
|
+
debugLog("Effective cloudflared log level filter:", effectiveLogLevel);
|
|
1117
|
+
debugLog("Effective cloudflared process log level:", cloudflaredProcessLogLevel);
|
|
1118
|
+
debugLog("Effective cloudflared protocol:", protocol);
|
|
1119
|
+
if (dnsOption) {
|
|
1120
|
+
if (!dnsOption.startsWith("*.") && dnsOption !== hostname) throw new Error("[unplugin-cloudflare-tunnel] dns option must either be a wildcard (e.g., '*.example.com') or exactly match the hostname");
|
|
1121
|
+
}
|
|
1122
|
+
if (sslOption) {
|
|
1123
|
+
if (!sslOption.startsWith("*.") && sslOption !== hostname) throw new Error("[unplugin-cloudflare-tunnel] ssl option must either be a wildcard (e.g., '*.example.com') or exactly match the hostname");
|
|
1124
|
+
}
|
|
1125
|
+
if (!["http2", "quic"].includes(protocol)) throw new Error("[unplugin-cloudflare-tunnel] protocol must be one of: 'http2', 'quic'");
|
|
1126
|
+
const trackSslCertificate = (certificateId, hosts, tunnelName, timestamp = (/* @__PURE__ */ new Date()).toISOString()) => {
|
|
1127
|
+
const trackingKey = `ssl-cert-${certificateId}`;
|
|
1128
|
+
globalState[trackingKey] = {
|
|
1129
|
+
id: certificateId,
|
|
1130
|
+
hosts,
|
|
1131
|
+
tunnelName,
|
|
1132
|
+
timestamp,
|
|
1133
|
+
pluginVersion: "1.0.0"
|
|
1134
|
+
};
|
|
1135
|
+
debugLog(`Tracking SSL certificate: ${certificateId} for hosts: ${hosts.join(", ")}`);
|
|
1136
|
+
};
|
|
1137
|
+
const cleanupMismatchedDnsRecords = async (apiToken, zoneId, dnsComment, currentHostname, tunnelId) => {
|
|
1138
|
+
try {
|
|
1139
|
+
const pluginDnsRecords = await cf(apiToken, "GET", `/zones/${zoneId}/dns_records?comment=${dnsComment}&match=all`, void 0, /* @__PURE__ */ array(DNSRecordSchema));
|
|
1140
|
+
debugLog(`Found ${pluginDnsRecords.length} DNS records for current tunnel: ${dnsComment}`);
|
|
1141
|
+
const expectedCnameContent = `${tunnelId}.cfargotunnel.com`;
|
|
1142
|
+
const mismatchedRecords = pluginDnsRecords.filter((record) => {
|
|
1143
|
+
if (record.name === currentHostname && record.content === expectedCnameContent) return false;
|
|
1144
|
+
if (dnsOption && record.name === dnsOption && record.content === expectedCnameContent) return false;
|
|
1145
|
+
return true;
|
|
1146
|
+
});
|
|
1147
|
+
debugLog(`Found ${mismatchedRecords.length} mismatched DNS records`, mismatchedRecords.map((r) => ({
|
|
1148
|
+
name: r.name,
|
|
1149
|
+
content: r.content,
|
|
1150
|
+
expected: expectedCnameContent,
|
|
1151
|
+
comment: r.comment
|
|
1152
|
+
})));
|
|
1153
|
+
const deletedRecords = [];
|
|
1154
|
+
if (mismatchedRecords.length > 0) {
|
|
1155
|
+
console.log(`[unplugin-cloudflare-tunnel] 🧹 Cleaning up ${mismatchedRecords.length} mismatched DNS records from tunnel '${dnsComment}'...`);
|
|
1156
|
+
for (const record of mismatchedRecords) try {
|
|
1157
|
+
await cf(apiToken, "DELETE", `/zones/${zoneId}/dns_records/${record.id}`);
|
|
1158
|
+
deletedRecords.push(record);
|
|
1159
|
+
console.log(`[unplugin-cloudflare-tunnel] ✅ Deleted mismatched DNS record: ${record.name} → ${record.content}`);
|
|
1160
|
+
} catch (error) {
|
|
1161
|
+
console.error(`[unplugin-cloudflare-tunnel] ❌ Failed to delete DNS record ${record.name}: ${error.message}`);
|
|
1162
|
+
}
|
|
1163
|
+
}
|
|
1164
|
+
return {
|
|
1165
|
+
found: mismatchedRecords,
|
|
1166
|
+
deleted: deletedRecords
|
|
1167
|
+
};
|
|
1168
|
+
} catch (error) {
|
|
1169
|
+
console.error(`[unplugin-cloudflare-tunnel] ❌ DNS cleanup failed: ${error.message}`);
|
|
1170
|
+
return {
|
|
1171
|
+
found: [],
|
|
1172
|
+
deleted: []
|
|
1173
|
+
};
|
|
1174
|
+
}
|
|
1175
|
+
};
|
|
1176
|
+
const cf = async (apiToken, method, url, body, resultSchema) => {
|
|
1177
|
+
try {
|
|
1178
|
+
debugLog("→ CF API", method, url, body ? { body } : "");
|
|
1179
|
+
const response = await fetch(`https://api.cloudflare.com/client/v4${url}`, {
|
|
1180
|
+
method,
|
|
1181
|
+
headers: {
|
|
1182
|
+
Authorization: `Bearer ${apiToken}`,
|
|
1183
|
+
"Content-Type": "application/json",
|
|
1184
|
+
"User-Agent": "unplugin-cloudflare-tunnel/1.0.0"
|
|
1185
|
+
},
|
|
1186
|
+
...body ? { body: JSON.stringify(body) } : {}
|
|
1187
|
+
});
|
|
1188
|
+
if (!response.ok) {
|
|
1189
|
+
const errorText = await response.text().catch(() => "Unknown error");
|
|
1190
|
+
throw new Error(`[unplugin-cloudflare-tunnel] API request failed: ${response.status} ${response.statusText}. Response: ${errorText}`);
|
|
1191
|
+
}
|
|
1192
|
+
const rawData = await response.json();
|
|
1193
|
+
debugLog("← CF API response", rawData);
|
|
1194
|
+
const apiResponse = CloudflareApiResponseSchema.parse(rawData);
|
|
1195
|
+
if (!apiResponse.success) {
|
|
1196
|
+
const errorMsg = apiResponse.errors?.map((e) => e.message || `Error ${e.code}`).join(", ") || "Unknown API error";
|
|
1197
|
+
throw new Error(`[unplugin-cloudflare-tunnel] Cloudflare API error: ${errorMsg}`);
|
|
1198
|
+
}
|
|
1199
|
+
if (resultSchema) {
|
|
1200
|
+
const parsed = resultSchema.parse(apiResponse.result);
|
|
1201
|
+
debugLog("← Parsed result", parsed);
|
|
1202
|
+
return parsed;
|
|
1203
|
+
}
|
|
1204
|
+
debugLog("← Result (untyped)", apiResponse.result);
|
|
1205
|
+
return apiResponse.result;
|
|
1206
|
+
} catch (error) {
|
|
1207
|
+
if (error instanceof Error) {
|
|
1208
|
+
if (error.message.includes("[unplugin-cloudflare-tunnel]")) throw error;
|
|
1209
|
+
throw new Error(`[unplugin-cloudflare-tunnel] API request failed: ${error.message}`);
|
|
1210
|
+
}
|
|
1211
|
+
throw new Error("[unplugin-cloudflare-tunnel] Unknown API error occurred");
|
|
1212
|
+
}
|
|
1213
|
+
};
|
|
1214
|
+
const retryWithBackoff = async (fn, maxRetries = 5, initialDelayMs = 1e3) => {
|
|
1215
|
+
let attempt = 0;
|
|
1216
|
+
while (true) try {
|
|
1217
|
+
return await fn();
|
|
1218
|
+
} catch (error) {
|
|
1219
|
+
attempt += 1;
|
|
1220
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1221
|
+
if (attempt > maxRetries) {
|
|
1222
|
+
console.error(`[unplugin-cloudflare-tunnel] ❌ Edge certificate request failed after ${maxRetries} retries: ${message}`);
|
|
1223
|
+
throw error;
|
|
1224
|
+
}
|
|
1225
|
+
const delay = initialDelayMs * 2 ** (attempt - 1);
|
|
1226
|
+
console.error(`[unplugin-cloudflare-tunnel] ⚠️ Edge certificate request failed (attempt ${attempt}/${maxRetries}): ${message}`);
|
|
1227
|
+
console.error(`[unplugin-cloudflare-tunnel] ⏳ Retrying in ${delay}ms...`);
|
|
1228
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
1229
|
+
}
|
|
1230
|
+
};
|
|
1231
|
+
const spawnQuickTunnel = async (localTarget, protocol) => {
|
|
1232
|
+
const cloudflaredArgs = ["tunnel"];
|
|
1233
|
+
cloudflaredArgs.push("--loglevel", "info");
|
|
1234
|
+
if (logFile) cloudflaredArgs.push("--logfile", logFile);
|
|
1235
|
+
cloudflaredArgs.push("--protocol", protocol);
|
|
1236
|
+
cloudflaredArgs.push("--url", localTarget);
|
|
1237
|
+
debugLog("Spawning quick tunnel:", bin, cloudflaredArgs);
|
|
1238
|
+
const child = NodeChildProcess.spawn(bin, cloudflaredArgs, {
|
|
1239
|
+
stdio: [
|
|
1240
|
+
"ignore",
|
|
1241
|
+
"pipe",
|
|
1242
|
+
"pipe"
|
|
1243
|
+
],
|
|
1244
|
+
detached: false,
|
|
1245
|
+
windowsHide: true,
|
|
1246
|
+
shell: process.platform === "win32"
|
|
1247
|
+
});
|
|
1248
|
+
debugLog(`[unplugin-cloudflare-tunnel] Quick tunnel process spawned with PID: ${child.pid}`);
|
|
1249
|
+
return new Promise((resolve, reject) => {
|
|
1250
|
+
let urlFound = false;
|
|
1251
|
+
let settled = false;
|
|
1252
|
+
const rejectOnce = (error) => {
|
|
1253
|
+
if (settled) return;
|
|
1254
|
+
settled = true;
|
|
1255
|
+
reject(error);
|
|
1256
|
+
};
|
|
1257
|
+
const resolveOnce = (result) => {
|
|
1258
|
+
if (settled) return;
|
|
1259
|
+
settled = true;
|
|
1260
|
+
resolve(result);
|
|
1261
|
+
};
|
|
1262
|
+
const timeout = setTimeout(() => {
|
|
1263
|
+
if (!urlFound) {
|
|
1264
|
+
try {
|
|
1265
|
+
child.kill("SIGTERM");
|
|
1266
|
+
} catch {}
|
|
1267
|
+
rejectOnce(/* @__PURE__ */ new Error("Quick tunnel URL not found in output within 30 seconds"));
|
|
1268
|
+
}
|
|
1269
|
+
}, 3e4);
|
|
1270
|
+
child.stdout?.on("data", (data) => {
|
|
1271
|
+
const output = data.toString();
|
|
1272
|
+
if (!globalState.shuttingDown || debug) {
|
|
1273
|
+
if (effectiveLogLevel === "debug" || effectiveLogLevel === "info") console.log(`[cloudflared stdout] ${output.trim()}`);
|
|
1274
|
+
else for (const line of output.split("\n")) if (!INFO_LOG_REGEX.test(line)) console.log(`[cloudflared stdout] ${line.trim()}`);
|
|
1275
|
+
}
|
|
1276
|
+
});
|
|
1277
|
+
child.stderr?.on("data", (data) => {
|
|
1278
|
+
const error = data.toString().trim();
|
|
1279
|
+
const urlMatch = error.match(/https:\/\/[a-zA-Z0-9-]+\.trycloudflare\.com/);
|
|
1280
|
+
if (urlMatch && !urlFound) {
|
|
1281
|
+
urlFound = true;
|
|
1282
|
+
clearTimeout(timeout);
|
|
1283
|
+
resolveOnce({
|
|
1284
|
+
child,
|
|
1285
|
+
url: urlMatch[0]
|
|
1286
|
+
});
|
|
1287
|
+
}
|
|
1288
|
+
if (error.includes("Failed to parse ICMP reply") || error.includes("unknow ip version 0")) {
|
|
1289
|
+
if (logLevel === "debug") console.log(`[cloudflared debug] ${error}`);
|
|
1290
|
+
return;
|
|
1291
|
+
}
|
|
1292
|
+
if (!globalState.shuttingDown || debug) {
|
|
1293
|
+
if (effectiveLogLevel === "debug" || effectiveLogLevel === "info") console.error(`[cloudflared stderr] ${error}`);
|
|
1294
|
+
else for (const line of error.split("\n")) if (!INFO_LOG_REGEX.test(line)) console.error(`[cloudflared stderr] ${line.trim()}`);
|
|
1295
|
+
}
|
|
1296
|
+
});
|
|
1297
|
+
child.on("error", (error) => {
|
|
1298
|
+
clearTimeout(timeout);
|
|
1299
|
+
rejectOnce(/* @__PURE__ */ new Error(`Failed to start quick tunnel process: ${error.message}`));
|
|
1300
|
+
});
|
|
1301
|
+
child.on("exit", (code, signal) => {
|
|
1302
|
+
clearTimeout(timeout);
|
|
1303
|
+
if (!urlFound) rejectOnce(/* @__PURE__ */ new Error(`Quick tunnel process exited before URL was found (code: ${code}, signal: ${signal})`));
|
|
1304
|
+
});
|
|
1305
|
+
});
|
|
1306
|
+
};
|
|
1307
|
+
const killCloudflared = createKillCloudflared({
|
|
1308
|
+
getChild: () => child,
|
|
1309
|
+
clearTunnelUrl: () => {
|
|
1310
|
+
globalState.tunnelUrl = void 0;
|
|
1311
|
+
},
|
|
1312
|
+
markShuttingDown: () => {
|
|
1313
|
+
globalState.shuttingDown = true;
|
|
1314
|
+
},
|
|
1315
|
+
debugLog
|
|
1316
|
+
});
|
|
1317
|
+
let exitHandlersRegistered = globalState.exitHandlersRegistered ?? false;
|
|
1318
|
+
const registerExitHandler = () => {
|
|
1319
|
+
if (exitHandlersRegistered) return;
|
|
1320
|
+
exitHandlersRegistered = true;
|
|
1321
|
+
globalState.exitHandlersRegistered = true;
|
|
1322
|
+
const cleanup = () => killCloudflared("SIGTERM");
|
|
1323
|
+
process.once("exit", cleanup);
|
|
1324
|
+
process.once("beforeExit", cleanup);
|
|
1325
|
+
[
|
|
1326
|
+
"SIGINT",
|
|
1327
|
+
"SIGTERM",
|
|
1328
|
+
"SIGQUIT",
|
|
1329
|
+
"SIGHUP"
|
|
1330
|
+
].forEach((signal) => {
|
|
1331
|
+
process.once(signal, () => {
|
|
1332
|
+
killCloudflared(signal);
|
|
1333
|
+
try {
|
|
1334
|
+
process.kill(process.pid, signal);
|
|
1335
|
+
} catch {
|
|
1336
|
+
process.exit(0);
|
|
1337
|
+
}
|
|
1338
|
+
});
|
|
1339
|
+
});
|
|
1340
|
+
process.once("uncaughtExceptionMonitor", (error) => {
|
|
1341
|
+
console.error("[unplugin-cloudflare-tunnel] Uncaught exception, cleaning up cloudflared...", error);
|
|
1342
|
+
killCloudflared("SIGTERM");
|
|
1343
|
+
});
|
|
1344
|
+
};
|
|
1345
|
+
const configureServer = async (server) => {
|
|
1346
|
+
const generateDnsComment = () => {
|
|
1347
|
+
return `unplugin-cloudflare-tunnel:${tunnelName}`;
|
|
1348
|
+
};
|
|
1349
|
+
const registerListeningHandler = (handler) => {
|
|
1350
|
+
const httpServer = server.httpServer;
|
|
1351
|
+
const invokeHandler = () => {
|
|
1352
|
+
try {
|
|
1353
|
+
const maybePromise = handler();
|
|
1354
|
+
if (maybePromise && typeof maybePromise.then === "function") maybePromise.catch((error) => {
|
|
1355
|
+
console.error(`[unplugin-cloudflare-tunnel] ❌ Dev server listening hook failed: ${error.message}`);
|
|
1356
|
+
});
|
|
1357
|
+
} catch (error) {
|
|
1358
|
+
console.error(`[unplugin-cloudflare-tunnel] ❌ Dev server listening hook failed: ${error.message}`);
|
|
1359
|
+
}
|
|
1360
|
+
};
|
|
1361
|
+
if (!httpServer) {
|
|
1362
|
+
invokeHandler();
|
|
1363
|
+
return;
|
|
1364
|
+
}
|
|
1365
|
+
httpServer.on("listening", invokeHandler);
|
|
1366
|
+
if (httpServer.listening) invokeHandler();
|
|
1367
|
+
};
|
|
1368
|
+
try {
|
|
1369
|
+
const { host: serverHost, port: detectedPort } = normalizeAddress(server.httpServer?.address());
|
|
1370
|
+
const configPortValue = server.config?.server?.port;
|
|
1371
|
+
const resolvedConfigPort = typeof configPortValue === "string" ? Number.parseInt(configPortValue, 10) : configPortValue;
|
|
1372
|
+
const port = userProvidedPort || detectedPort || (typeof resolvedConfigPort === "number" && !Number.isNaN(resolvedConfigPort) ? resolvedConfigPort : void 0) || 5173;
|
|
1373
|
+
const originRequest = server.httpServer ? void 0 : { httpHostHeader: `${serverHost}:${port}` };
|
|
1374
|
+
const newConfigHash = JSON.stringify({
|
|
1375
|
+
isQuickMode,
|
|
1376
|
+
hostname,
|
|
1377
|
+
port,
|
|
1378
|
+
tunnelName,
|
|
1379
|
+
dnsOption,
|
|
1380
|
+
sslOption,
|
|
1381
|
+
originRequest
|
|
1382
|
+
});
|
|
1383
|
+
if (globalState.child && !globalState.child.killed && globalState.configHash === newConfigHash) {
|
|
1384
|
+
tunnelUrl = await globalState.tunnelUrl ?? "";
|
|
1385
|
+
debugLog("[unplugin-cloudflare-tunnel] Config unchanged – re-using existing tunnel");
|
|
1386
|
+
globalState.shuttingDown = false;
|
|
1387
|
+
registerExitHandler();
|
|
1388
|
+
return;
|
|
1389
|
+
}
|
|
1390
|
+
if (globalState.child && !globalState.child.killed) {
|
|
1391
|
+
debugLog("[unplugin-cloudflare-tunnel] Config changed – terminating previous tunnel...");
|
|
1392
|
+
try {
|
|
1393
|
+
globalState.child.kill("SIGTERM");
|
|
1394
|
+
} catch {}
|
|
1395
|
+
}
|
|
1396
|
+
delete globalState.child;
|
|
1397
|
+
delete globalState.configHash;
|
|
1398
|
+
globalState.shuttingDown = false;
|
|
1399
|
+
if (isQuickMode) {
|
|
1400
|
+
debugLog("[unplugin-cloudflare-tunnel] Starting quick tunnel mode...");
|
|
1401
|
+
debugLog("Quick tunnel mode - no API token or hostname required");
|
|
1402
|
+
await ensureCloudflaredBinary(bin);
|
|
1403
|
+
const localTarget = getLocalTarget(serverHost, port);
|
|
1404
|
+
debugLog("← Quick tunnel connecting to local target", localTarget);
|
|
1405
|
+
try {
|
|
1406
|
+
const { child: quickChild, url } = await spawnQuickTunnel(localTarget, protocol);
|
|
1407
|
+
tunnelUrl = url;
|
|
1408
|
+
child = quickChild;
|
|
1409
|
+
globalState.child = child;
|
|
1410
|
+
globalState.configHash = newConfigHash;
|
|
1411
|
+
globalState.tunnelUrl = Promise.resolve(url);
|
|
1412
|
+
registerExitHandler();
|
|
1413
|
+
registerListeningHandler(() => {
|
|
1414
|
+
const { host: actualServerHost, port: actualPort } = normalizeAddress(server.httpServer?.address());
|
|
1415
|
+
const actualLocalTarget = getLocalTarget(actualServerHost, actualPort ?? port);
|
|
1416
|
+
announceTunnel({
|
|
1417
|
+
key: `quick:${url}:${actualPort ?? port}`,
|
|
1418
|
+
url,
|
|
1419
|
+
localTarget: actualLocalTarget
|
|
1420
|
+
});
|
|
1421
|
+
});
|
|
1422
|
+
registerListeningHandler(async () => {
|
|
1423
|
+
try {
|
|
1424
|
+
const { host: actualServerHost, port: actualPort } = normalizeAddress(server.httpServer?.address());
|
|
1425
|
+
if (server.httpServer && actualPort !== void 0 && actualPort !== port) {
|
|
1426
|
+
pluginLog.warn(`Port conflict detected - server is using port ${actualPort} instead of ${port}`);
|
|
1427
|
+
pluginLog.info("Restarting quick tunnel for the new port...");
|
|
1428
|
+
killCloudflared("SIGTERM");
|
|
1429
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
1430
|
+
const newLocalTarget = getLocalTarget(actualServerHost, actualPort ?? port);
|
|
1431
|
+
const { child: newChild, url: newUrl } = await spawnQuickTunnel(newLocalTarget, protocol);
|
|
1432
|
+
tunnelUrl = newUrl;
|
|
1433
|
+
child = newChild;
|
|
1434
|
+
globalState.child = child;
|
|
1435
|
+
globalState.tunnelUrl = Promise.resolve(newUrl);
|
|
1436
|
+
announceTunnel({
|
|
1437
|
+
key: `quick:${newUrl}:${actualPort ?? port}`,
|
|
1438
|
+
url: newUrl,
|
|
1439
|
+
localTarget: newLocalTarget
|
|
1440
|
+
});
|
|
1441
|
+
globalState.configHash = JSON.stringify({
|
|
1442
|
+
isQuickMode,
|
|
1443
|
+
hostname,
|
|
1444
|
+
port: actualPort,
|
|
1445
|
+
tunnelName,
|
|
1446
|
+
dnsOption,
|
|
1447
|
+
sslOption
|
|
1448
|
+
});
|
|
1449
|
+
}
|
|
1450
|
+
} catch (error) {
|
|
1451
|
+
console.error(`[unplugin-cloudflare-tunnel] ❌ Failed to update quick tunnel for port change: ${error.message}`);
|
|
1452
|
+
}
|
|
1453
|
+
});
|
|
1454
|
+
server.httpServer?.once("close", () => {
|
|
1455
|
+
killCloudflared("SIGTERM");
|
|
1456
|
+
});
|
|
1457
|
+
return;
|
|
1458
|
+
} catch (error) {
|
|
1459
|
+
console.error(`[unplugin-cloudflare-tunnel] ❌ Quick tunnel setup failed: ${error.message}`);
|
|
1460
|
+
throw error;
|
|
1461
|
+
}
|
|
1462
|
+
}
|
|
1463
|
+
debugLog("[unplugin-cloudflare-tunnel] Starting named tunnel mode...");
|
|
1464
|
+
const apiToken = providedApiToken || process.env.CLOUDFLARE_API_TOKEN;
|
|
1465
|
+
if (!apiToken) throw new Error("[unplugin-cloudflare-tunnel] API token is required. Provide it via 'apiToken' option or set the CLOUDFLARE_API_TOKEN environment variable. Get your token at: https://dash.cloudflare.com/profile/api-tokens");
|
|
1466
|
+
debugLog(`[unplugin-cloudflare-tunnel] Using port ${port}${userProvidedPort === port ? " (user-provided)" : " (from bundler config)"}`);
|
|
1467
|
+
await ensureCloudflaredBinary(bin);
|
|
1468
|
+
const apexDomain = hostname.split(".").slice(-2).join(".");
|
|
1469
|
+
const parentDomain = hostname.split(".").slice(1).join(".");
|
|
1470
|
+
debugLog("← Apex domain", apexDomain);
|
|
1471
|
+
debugLog("← Parent domain", parentDomain);
|
|
1472
|
+
let resolvedZone;
|
|
1473
|
+
let zoneId = forcedZone;
|
|
1474
|
+
if (!zoneId) {
|
|
1475
|
+
let zones = [];
|
|
1476
|
+
try {
|
|
1477
|
+
zones = await cf(apiToken, "GET", `/zones?name=${parentDomain}`, void 0, /* @__PURE__ */ array(ZoneSchema));
|
|
1478
|
+
} catch (error) {
|
|
1479
|
+
debugLog("← Error fetching zone for parent domain", error);
|
|
1480
|
+
}
|
|
1481
|
+
if (zones.length === 0) zones = await cf(apiToken, "GET", `/zones?name=${apexDomain}`, void 0, /* @__PURE__ */ array(ZoneSchema));
|
|
1482
|
+
resolvedZone = zones[0];
|
|
1483
|
+
zoneId = resolvedZone?.id;
|
|
1484
|
+
}
|
|
1485
|
+
let accountId = forcedAccount || resolvedZone?.account?.id;
|
|
1486
|
+
if (!accountId) accountId = (await cf(apiToken, "GET", "/accounts", void 0, /* @__PURE__ */ array(AccountSchema)))[0]?.id;
|
|
1487
|
+
if (!accountId) throw new Error("Unable to determine Cloudflare account ID");
|
|
1488
|
+
if (!zoneId) throw new Error(`Zone ${apexDomain} not found in account ${accountId}`);
|
|
1489
|
+
const { autoCleanup = true } = cleanupConfig;
|
|
1490
|
+
let [tunnel] = await cf(apiToken, "GET", `/accounts/${accountId}/cfd_tunnel?name=${tunnelName}`, void 0, /* @__PURE__ */ array(TunnelSchema));
|
|
1491
|
+
if (!tunnel) {
|
|
1492
|
+
pluginLog.info(`Creating tunnel '${tunnelName}'...`);
|
|
1493
|
+
tunnel = await cf(apiToken, "POST", `/accounts/${accountId}/cfd_tunnel`, {
|
|
1494
|
+
name: tunnelName,
|
|
1495
|
+
config_src: "cloudflare"
|
|
1496
|
+
}, TunnelSchema);
|
|
1497
|
+
}
|
|
1498
|
+
const tunnelId = tunnel.id;
|
|
1499
|
+
const localTarget = getLocalTarget(serverHost, port);
|
|
1500
|
+
debugLog("← Connecting to local target", localTarget);
|
|
1501
|
+
await cf(apiToken, "PUT", `/accounts/${accountId}/cfd_tunnel/${tunnelId}/configurations`, { config: { ingress: [{
|
|
1502
|
+
hostname,
|
|
1503
|
+
service: localTarget,
|
|
1504
|
+
...originRequest ? { originRequest } : {}
|
|
1505
|
+
}, { service: "http_status:404" }] } });
|
|
1506
|
+
const token = await cf(apiToken, "GET", `/accounts/${accountId}/cfd_tunnel/${tunnelId}/token`, void 0, /* @__PURE__ */ string());
|
|
1507
|
+
const generateSslTagHostname = () => {
|
|
1508
|
+
return `cf-tunnel-plugin-${tunnelName}--${parentDomain}`;
|
|
1509
|
+
};
|
|
1510
|
+
const finalizeNamedTunnelSetup = async () => {
|
|
1511
|
+
if (autoCleanup) {
|
|
1512
|
+
debugLog(`[unplugin-cloudflare-tunnel] Running resource cleanup for tunnel '${tunnelName}'...`);
|
|
1513
|
+
const dnsCleanup = await cleanupMismatchedDnsRecords(apiToken, zoneId, generateDnsComment(), hostname, tunnelId);
|
|
1514
|
+
if (dnsCleanup.found.length > 0) pluginLog.warn(`DNS cleanup: ${dnsCleanup.found.length} mismatched, ${dnsCleanup.deleted.length} deleted`);
|
|
1515
|
+
} else debugLog("← Cleanup skipped", cleanupConfig);
|
|
1516
|
+
if (dnsOption) {
|
|
1517
|
+
const ensureDnsRecord = async (type, content) => {
|
|
1518
|
+
if ((await cf(apiToken, "GET", `/zones/${zoneId}/dns_records?type=${type}&name=${encodeURIComponent(dnsOption)}`, void 0, /* @__PURE__ */ array(DNSRecordSchema))).length === 0) {
|
|
1519
|
+
console.log(`[unplugin-cloudflare-tunnel] Creating ${type} record for ${dnsOption}...`);
|
|
1520
|
+
await cf(apiToken, "POST", `/zones/${zoneId}/dns_records`, {
|
|
1521
|
+
type,
|
|
1522
|
+
name: dnsOption,
|
|
1523
|
+
content,
|
|
1524
|
+
proxied: true,
|
|
1525
|
+
comment: generateDnsComment()
|
|
1526
|
+
}, DNSRecordSchema);
|
|
1527
|
+
}
|
|
1528
|
+
};
|
|
1529
|
+
await ensureDnsRecord("CNAME", `${tunnelId}.cfargotunnel.com`);
|
|
1530
|
+
} else {
|
|
1531
|
+
const wildcardDns = `*.${parentDomain}`;
|
|
1532
|
+
if ((await cf(apiToken, "GET", `/zones/${zoneId}/dns_records?type=CNAME&name=${wildcardDns}`, void 0, /* @__PURE__ */ array(DNSRecordSchema))).length === 0) {
|
|
1533
|
+
const existingRecord = (await cf(apiToken, "GET", `/zones/${zoneId}/dns_records?type=CNAME&name=${hostname}`, void 0, /* @__PURE__ */ array(DNSRecordSchema)))[0];
|
|
1534
|
+
const expectedContent = `${tunnelId}.cfargotunnel.com`;
|
|
1535
|
+
if (!existingRecord) {
|
|
1536
|
+
console.log(`[unplugin-cloudflare-tunnel] Creating DNS record for ${hostname}...`);
|
|
1537
|
+
await cf(apiToken, "POST", `/zones/${zoneId}/dns_records`, {
|
|
1538
|
+
type: "CNAME",
|
|
1539
|
+
name: hostname,
|
|
1540
|
+
content: expectedContent,
|
|
1541
|
+
proxied: true,
|
|
1542
|
+
comment: generateDnsComment()
|
|
1543
|
+
}, DNSRecordSchema);
|
|
1544
|
+
} else if (existingRecord.content !== expectedContent) {
|
|
1545
|
+
debugLog(`← DNS record for ${hostname} points to different tunnel, updating...`);
|
|
1546
|
+
pluginLog.info(`Updating DNS record for ${hostname} to point to tunnel '${tunnelName}'...`);
|
|
1547
|
+
await cf(apiToken, "PUT", `/zones/${zoneId}/dns_records/${existingRecord.id}`, {
|
|
1548
|
+
type: "CNAME",
|
|
1549
|
+
name: hostname,
|
|
1550
|
+
content: expectedContent,
|
|
1551
|
+
proxied: true,
|
|
1552
|
+
comment: generateDnsComment()
|
|
1553
|
+
}, DNSRecordSchema);
|
|
1554
|
+
}
|
|
1555
|
+
}
|
|
1556
|
+
}
|
|
1557
|
+
const certListRaw = await cf(apiToken, "GET", `/zones/${zoneId}/ssl/certificate_packs?status=all`, void 0, /* @__PURE__ */ any());
|
|
1558
|
+
const certPacks = Array.isArray(certListRaw) ? certListRaw : certListRaw.result || [];
|
|
1559
|
+
if (autoCleanup) {
|
|
1560
|
+
const mismatchedSslCerts = certPacks.filter((cert) => {
|
|
1561
|
+
return (cert.hostnames || cert.hosts || []).some((host) => host.startsWith(`cf-tunnel-plugin-${tunnelName}--`));
|
|
1562
|
+
}).filter((cert) => {
|
|
1563
|
+
return !(cert.hostnames || cert.hosts || []).some((host) => {
|
|
1564
|
+
if (host.startsWith("cf-tunnel-plugin-")) return false;
|
|
1565
|
+
return host === hostname || host.startsWith("*.") && hostname.endsWith(host.slice(1));
|
|
1566
|
+
});
|
|
1567
|
+
});
|
|
1568
|
+
if (mismatchedSslCerts.length > 0) {
|
|
1569
|
+
for (const cert of mismatchedSslCerts) await cf(apiToken, "DELETE", `/zones/${zoneId}/ssl/certificate_packs/${cert.id}`);
|
|
1570
|
+
pluginLog.warn(`SSL cleanup: ${mismatchedSslCerts.length} deleted`);
|
|
1571
|
+
}
|
|
1572
|
+
}
|
|
1573
|
+
const certContainingHost = (host) => certPacks.filter((c) => (c.hostnames || c.hosts || []).includes(host))?.[0];
|
|
1574
|
+
if (sslOption) {
|
|
1575
|
+
const isWildcard = sslOption.startsWith("*.");
|
|
1576
|
+
const certNeededHost = sslOption;
|
|
1577
|
+
const matchingCert = certContainingHost(certNeededHost);
|
|
1578
|
+
if (!matchingCert) {
|
|
1579
|
+
console.log(`[unplugin-cloudflare-tunnel] Requesting ${isWildcard ? "wildcard " : ""}certificate for ${certNeededHost}...`);
|
|
1580
|
+
const tagHostname = generateSslTagHostname();
|
|
1581
|
+
const certificateHosts = [certNeededHost, tagHostname];
|
|
1582
|
+
debugLog(`Adding tag hostname to certificate: ${tagHostname}`);
|
|
1583
|
+
const newCert = await retryWithBackoff(() => cf(apiToken, "POST", `/zones/${zoneId}/ssl/certificate_packs/order`, {
|
|
1584
|
+
hosts: certificateHosts,
|
|
1585
|
+
certificate_authority: "lets_encrypt",
|
|
1586
|
+
type: "advanced",
|
|
1587
|
+
validation_method: isWildcard ? "txt" : "http",
|
|
1588
|
+
validity_days: 90,
|
|
1589
|
+
cloudflare_branding: false
|
|
1590
|
+
}));
|
|
1591
|
+
if (newCert?.id) trackSslCertificate(newCert.id, certificateHosts, tunnelName);
|
|
1592
|
+
} else debugLog("← Edge certificate already exists", matchingCert);
|
|
1593
|
+
} else {
|
|
1594
|
+
const wildcardDomain = `*.${parentDomain}`;
|
|
1595
|
+
const wildcardExists = certContainingHost(wildcardDomain);
|
|
1596
|
+
if (!wildcardExists) {
|
|
1597
|
+
const totalTls = await cf(apiToken, "GET", `/zones/${zoneId}/acm/total_tls`, void 0, /* @__PURE__ */ object({ status: /* @__PURE__ */ string() }));
|
|
1598
|
+
debugLog("← Total TLS", totalTls);
|
|
1599
|
+
const existingHostnameCert = certContainingHost(hostname);
|
|
1600
|
+
if (totalTls.status !== "on" && !existingHostnameCert) {
|
|
1601
|
+
pluginLog.info(`Requesting edge certificate for ${hostname}...`);
|
|
1602
|
+
const tagHostname = generateSslTagHostname();
|
|
1603
|
+
const certificateHosts = [hostname, tagHostname];
|
|
1604
|
+
debugLog(`Adding tag hostname to certificate: ${tagHostname}`);
|
|
1605
|
+
const newCert = await retryWithBackoff(() => cf(apiToken, "POST", `/zones/${zoneId}/ssl/certificate_packs/order`, {
|
|
1606
|
+
hosts: certificateHosts,
|
|
1607
|
+
certificate_authority: "lets_encrypt",
|
|
1608
|
+
type: "advanced",
|
|
1609
|
+
validation_method: "txt",
|
|
1610
|
+
validity_days: 90,
|
|
1611
|
+
cloudflare_branding: false
|
|
1612
|
+
}));
|
|
1613
|
+
if (newCert?.id) trackSslCertificate(newCert.id, certificateHosts, tunnelName);
|
|
1614
|
+
} else debugLog("← Edge certificate already exists", existingHostnameCert);
|
|
1615
|
+
} else debugLog("← Edge certificate (wildcard) already exists", wildcardExists, wildcardDomain);
|
|
1616
|
+
}
|
|
1617
|
+
};
|
|
1618
|
+
let tunnelReady = false;
|
|
1619
|
+
let localTargetForAnnouncement = localTarget;
|
|
1620
|
+
let activeTunnelProtocol;
|
|
1621
|
+
const announceNamedTunnelIfReady = () => {
|
|
1622
|
+
if (!tunnelReady) return;
|
|
1623
|
+
announceTunnel({
|
|
1624
|
+
key: `named:${hostname}:${localTargetForAnnouncement}`,
|
|
1625
|
+
url: `https://${hostname}`,
|
|
1626
|
+
localTarget: localTargetForAnnouncement
|
|
1627
|
+
});
|
|
1628
|
+
};
|
|
1629
|
+
const logCloudflaredLines = (kind, text) => {
|
|
1630
|
+
if (globalState.shuttingDown && !debug) return;
|
|
1631
|
+
const isVerbose = effectiveLogLevel === "debug" || effectiveLogLevel === "info";
|
|
1632
|
+
const lines = text.split("\n").map((l) => l.trim()).filter(Boolean);
|
|
1633
|
+
if (isVerbose) {
|
|
1634
|
+
for (const line of lines) {
|
|
1635
|
+
const prefix = kind === "stdout" ? "[cloudflared stdout]" : "[cloudflared stderr]";
|
|
1636
|
+
if (kind === "stdout") console.log(`${prefix} ${line}`);
|
|
1637
|
+
else console.error(`${prefix} ${line}`);
|
|
1638
|
+
}
|
|
1639
|
+
return;
|
|
1640
|
+
}
|
|
1641
|
+
for (const line of lines) {
|
|
1642
|
+
if (INFO_LOG_REGEX.test(line)) continue;
|
|
1643
|
+
const prefix = kind === "stdout" ? "[cloudflared stdout]" : "[cloudflared stderr]";
|
|
1644
|
+
if (kind === "stdout") console.log(`${prefix} ${line}`);
|
|
1645
|
+
else console.error(`${prefix} ${line}`);
|
|
1646
|
+
}
|
|
1647
|
+
};
|
|
1648
|
+
const spawnNamedTunnelProcess = (protocol) => {
|
|
1649
|
+
const cloudflaredArgs = ["tunnel"];
|
|
1650
|
+
cloudflaredArgs.push("--loglevel", cloudflaredProcessLogLevel);
|
|
1651
|
+
if (logFile) cloudflaredArgs.push("--logfile", logFile);
|
|
1652
|
+
cloudflaredArgs.push("--protocol", protocol);
|
|
1653
|
+
debugLog("Spawning cloudflared", bin, cloudflaredArgs);
|
|
1654
|
+
const spawnedChild = NodeChildProcess.spawn(bin, [
|
|
1655
|
+
...cloudflaredArgs,
|
|
1656
|
+
"run",
|
|
1657
|
+
"--token",
|
|
1658
|
+
token
|
|
1659
|
+
], {
|
|
1660
|
+
stdio: [
|
|
1661
|
+
"ignore",
|
|
1662
|
+
"pipe",
|
|
1663
|
+
"pipe"
|
|
1664
|
+
],
|
|
1665
|
+
detached: false,
|
|
1666
|
+
windowsHide: true,
|
|
1667
|
+
shell: process.platform === "win32"
|
|
1668
|
+
});
|
|
1669
|
+
child = spawnedChild;
|
|
1670
|
+
globalState.child = spawnedChild;
|
|
1671
|
+
globalState.configHash = newConfigHash;
|
|
1672
|
+
debugLog(`[unplugin-cloudflare-tunnel] Process spawned with PID: ${spawnedChild.pid}`);
|
|
1673
|
+
const handleCloudflaredOutput = (kind, text) => {
|
|
1674
|
+
if (text.includes("Failed to parse ICMP reply") || text.includes("unknow ip version 0")) {
|
|
1675
|
+
if (logLevel === "debug") console.log(`[cloudflared debug] ${text.trim()}`);
|
|
1676
|
+
return;
|
|
1677
|
+
}
|
|
1678
|
+
logCloudflaredLines(kind, text);
|
|
1679
|
+
if (/registered tunnel connection|connection.*registered/i.test(text)) {
|
|
1680
|
+
activeTunnelProtocol = protocol;
|
|
1681
|
+
if (!tunnelReady) {
|
|
1682
|
+
tunnelReady = true;
|
|
1683
|
+
pluginLog.info(`Tunnel connected for https://${hostname} via ${protocol.toUpperCase()}`);
|
|
1684
|
+
}
|
|
1685
|
+
announceNamedTunnelIfReady();
|
|
1686
|
+
}
|
|
1687
|
+
};
|
|
1688
|
+
spawnedChild.stdout?.on("data", (data) => {
|
|
1689
|
+
handleCloudflaredOutput("stdout", data.toString());
|
|
1690
|
+
});
|
|
1691
|
+
spawnedChild.stderr?.on("data", (data) => {
|
|
1692
|
+
handleCloudflaredOutput("stderr", data.toString());
|
|
1693
|
+
});
|
|
1694
|
+
spawnedChild.on("error", (error) => {
|
|
1695
|
+
console.error(`[unplugin-cloudflare-tunnel] ❌ Failed to start tunnel process: ${error.message}`);
|
|
1696
|
+
if (error.message.includes("ENOENT")) console.error(`[unplugin-cloudflare-tunnel] Hint: cloudflared binary may not be installed correctly`);
|
|
1697
|
+
});
|
|
1698
|
+
spawnedChild.on("exit", (code, signal) => {
|
|
1699
|
+
if (globalState.child !== spawnedChild) return;
|
|
1700
|
+
if (code !== 0 && code !== null) {
|
|
1701
|
+
console.error(`[unplugin-cloudflare-tunnel] ❌ Tunnel process exited with code ${code}`);
|
|
1702
|
+
if (signal) console.error(`[unplugin-cloudflare-tunnel] Process terminated by signal: ${signal}`);
|
|
1703
|
+
} else if (code === 0) console.log(`[unplugin-cloudflare-tunnel] ✅ Tunnel process exited cleanly`);
|
|
1704
|
+
});
|
|
1705
|
+
};
|
|
1706
|
+
spawnNamedTunnelProcess(protocol);
|
|
1707
|
+
registerExitHandler();
|
|
1708
|
+
finalizeNamedTunnelSetup().catch((error) => {
|
|
1709
|
+
console.error(`[unplugin-cloudflare-tunnel] ❌ Post-start setup failed: ${error.message}`);
|
|
1710
|
+
});
|
|
1711
|
+
registerListeningHandler(() => {
|
|
1712
|
+
const { host: actualServerHost, port: actualPort } = normalizeAddress(server.httpServer?.address());
|
|
1713
|
+
localTargetForAnnouncement = getLocalTarget(actualServerHost, actualPort ?? port);
|
|
1714
|
+
announceNamedTunnelIfReady();
|
|
1715
|
+
});
|
|
1716
|
+
server.httpServer?.once("close", () => {
|
|
1717
|
+
killCloudflared("SIGTERM");
|
|
1718
|
+
});
|
|
1719
|
+
registerListeningHandler(async () => {
|
|
1720
|
+
try {
|
|
1721
|
+
const { host: actualServerHost, port: actualPort } = normalizeAddress(server.httpServer?.address());
|
|
1722
|
+
if (server.httpServer && actualPort !== void 0 && actualPort !== port) {
|
|
1723
|
+
pluginLog.warn(`Port conflict detected - server is using port ${actualPort} instead of ${port}`);
|
|
1724
|
+
pluginLog.info("Updating tunnel configuration...");
|
|
1725
|
+
const newLocalTarget = getLocalTarget(actualServerHost, actualPort ?? port);
|
|
1726
|
+
localTargetForAnnouncement = newLocalTarget;
|
|
1727
|
+
debugLog("← Updating local target to", newLocalTarget);
|
|
1728
|
+
await cf(apiToken, "PUT", `/accounts/${accountId}/cfd_tunnel/${tunnelId}/configurations`, { config: { ingress: [{
|
|
1729
|
+
hostname,
|
|
1730
|
+
service: newLocalTarget,
|
|
1731
|
+
...originRequest ? { originRequest: { httpHostHeader: `${actualServerHost}:${actualPort ?? port}` } } : {}
|
|
1732
|
+
}, { service: "http_status:404" }] } });
|
|
1733
|
+
pluginLog.info(`Tunnel configuration updated to use port ${actualPort}`);
|
|
1734
|
+
globalState.configHash = JSON.stringify({
|
|
1735
|
+
hostname,
|
|
1736
|
+
port: actualPort,
|
|
1737
|
+
tunnelName,
|
|
1738
|
+
dnsOption,
|
|
1739
|
+
sslOption,
|
|
1740
|
+
originRequest: server.httpServer ? void 0 : { httpHostHeader: `${actualServerHost}:${actualPort ?? port}` }
|
|
1741
|
+
});
|
|
1742
|
+
if (tunnelReady && activeTunnelProtocol) pluginLog.info(`Tunnel remains connected via ${activeTunnelProtocol.toUpperCase()} after port update`);
|
|
1743
|
+
announceNamedTunnelIfReady();
|
|
1744
|
+
}
|
|
1745
|
+
} catch (error) {
|
|
1746
|
+
console.error(`[unplugin-cloudflare-tunnel] ❌ Failed to update tunnel for port change: ${error.message}`);
|
|
1747
|
+
}
|
|
1748
|
+
});
|
|
1749
|
+
} catch (error) {
|
|
1750
|
+
if (error instanceof Error) {
|
|
1751
|
+
console.error(`[unplugin-cloudflare-tunnel] ❌ Setup failed: ${error.message}`);
|
|
1752
|
+
if (error.message.includes("API token")) {
|
|
1753
|
+
console.error(`[unplugin-cloudflare-tunnel] 💡 Check your API token at: https://dash.cloudflare.com/profile/api-tokens`);
|
|
1754
|
+
console.error(`[unplugin-cloudflare-tunnel] 💡 Required permissions: Zone:Zone:Read, Zone:DNS:Edit, Account:Cloudflare Tunnel:Edit`);
|
|
1755
|
+
} else if (error.message.includes("Zone") && error.message.includes("not found")) console.error(`[unplugin-cloudflare-tunnel] 💡 Make sure '${hostname}' domain is added to your Cloudflare account`);
|
|
1756
|
+
else if (error.message.includes("cloudflared")) console.error(`[unplugin-cloudflare-tunnel] 💡 Try deleting node_modules and reinstalling to get a fresh cloudflared binary`);
|
|
1757
|
+
}
|
|
1758
|
+
throw error;
|
|
1759
|
+
}
|
|
1760
|
+
};
|
|
1761
|
+
const ensureWebpackAllowedHosts = (devServerOptions, bundler) => {
|
|
1762
|
+
if (!devServerOptions) return;
|
|
1763
|
+
const hostToAllow = isQuickMode ? ".trycloudflare.com" : hostname;
|
|
1764
|
+
if (!hostToAllow) return;
|
|
1765
|
+
const label = bundler === "webpack" ? "Webpack" : "Rspack";
|
|
1766
|
+
const normalizeArray = (values) => {
|
|
1767
|
+
const unique = Array.from(new Set(values.filter(Boolean)));
|
|
1768
|
+
devServerOptions.allowedHosts = unique;
|
|
1769
|
+
return unique;
|
|
1770
|
+
};
|
|
1771
|
+
let modified = false;
|
|
1772
|
+
const current = devServerOptions.allowedHosts;
|
|
1773
|
+
if (current === "all") return;
|
|
1774
|
+
if (typeof current === "undefined" || current === "auto") {
|
|
1775
|
+
normalizeArray(["localhost", hostToAllow]);
|
|
1776
|
+
modified = true;
|
|
1777
|
+
} else if (typeof current === "string") {
|
|
1778
|
+
if (current !== hostToAllow) {
|
|
1779
|
+
normalizeArray([current, hostToAllow]);
|
|
1780
|
+
modified = true;
|
|
1781
|
+
}
|
|
1782
|
+
} else if (Array.isArray(current)) {
|
|
1783
|
+
if (!current.includes(hostToAllow)) {
|
|
1784
|
+
current.push(hostToAllow);
|
|
1785
|
+
modified = true;
|
|
1786
|
+
}
|
|
1787
|
+
}
|
|
1788
|
+
if (modified) debugLog(`[unplugin-cloudflare-tunnel] Configured ${label} devServer.allowedHosts to include ${hostToAllow}`);
|
|
1789
|
+
};
|
|
1790
|
+
const ensureViteAllowedHosts = (serverConfig) => {
|
|
1791
|
+
const hostToAllow = isQuickMode ? ".trycloudflare.com" : hostname;
|
|
1792
|
+
if (!hostToAllow) return;
|
|
1793
|
+
const current = serverConfig.allowedHosts;
|
|
1794
|
+
if (current === true) return;
|
|
1795
|
+
if (typeof current === "undefined") serverConfig.allowedHosts = [hostToAllow];
|
|
1796
|
+
else if (typeof current === "string") {
|
|
1797
|
+
if (current !== hostToAllow) serverConfig.allowedHosts = [current, hostToAllow];
|
|
1798
|
+
} else if (Array.isArray(current)) {
|
|
1799
|
+
if (!current.includes(hostToAllow)) current.push(hostToAllow);
|
|
1800
|
+
}
|
|
1801
|
+
};
|
|
1802
|
+
const setupWebpackVirtualScheme = (compiler) => {
|
|
1803
|
+
const plugins = compiler.options.plugins ??= [];
|
|
1804
|
+
if (plugins.some((plugin) => plugin?.__unpluginCloudflareTunnelVirtualSchemePlugin)) return;
|
|
1805
|
+
const context = typeof compiler.options.context === "string" && compiler.options.context.length > 0 ? compiler.options.context : process.cwd();
|
|
1806
|
+
let VirtualUrlPlugin;
|
|
1807
|
+
try {
|
|
1808
|
+
VirtualUrlPlugin = NodeModule.createRequire(`${context}/package.json`)("webpack/lib/schemes/VirtualUrlPlugin");
|
|
1809
|
+
} catch {
|
|
1810
|
+
return;
|
|
1811
|
+
}
|
|
1812
|
+
const virtualSchemePlugin = new VirtualUrlPlugin({ "unplugin-cloudflare-tunnel": {
|
|
1813
|
+
type: ".js",
|
|
1814
|
+
async source() {
|
|
1815
|
+
const url = await globalState.tunnelUrl;
|
|
1816
|
+
return `export function getTunnelUrl() { return ${JSON.stringify(url || "")}; }`;
|
|
1817
|
+
}
|
|
1818
|
+
} }, "virtual");
|
|
1819
|
+
virtualSchemePlugin.__unpluginCloudflareTunnelVirtualSchemePlugin = true;
|
|
1820
|
+
plugins.unshift(virtualSchemePlugin);
|
|
1821
|
+
virtualSchemePlugin.apply(compiler);
|
|
1822
|
+
};
|
|
1823
|
+
const setupWebpackLikeDevServerIntegration = (compiler, bundler) => {
|
|
1824
|
+
if ((compiler?.options?.mode ?? process.env.NODE_ENV) === "production") return;
|
|
1825
|
+
const optionsContainer = compiler.options;
|
|
1826
|
+
if (!optionsContainer.devServer) optionsContainer.devServer = {};
|
|
1827
|
+
const devServerOptions = optionsContainer.devServer;
|
|
1828
|
+
ensureWebpackAllowedHosts(devServerOptions, bundler);
|
|
1829
|
+
let lastHttpServer;
|
|
1830
|
+
let missingServerWarned = false;
|
|
1831
|
+
const runConfiguration = (devServerInstance) => {
|
|
1832
|
+
if (!devServerInstance) {
|
|
1833
|
+
if (!missingServerWarned) {
|
|
1834
|
+
console.warn(`[unplugin-cloudflare-tunnel] ${bundler} dev server instance unavailable; skipping tunnel setup`);
|
|
1835
|
+
missingServerWarned = true;
|
|
1836
|
+
}
|
|
1837
|
+
return;
|
|
1838
|
+
}
|
|
1839
|
+
const httpServer = [
|
|
1840
|
+
devServerInstance.server,
|
|
1841
|
+
devServerInstance.httpServer,
|
|
1842
|
+
devServerInstance.listeningApp,
|
|
1843
|
+
devServerInstance.server?.server
|
|
1844
|
+
].find((candidate) => candidate);
|
|
1845
|
+
if (!httpServer) {
|
|
1846
|
+
if (!missingServerWarned) {
|
|
1847
|
+
console.warn(`[unplugin-cloudflare-tunnel] Unable to locate HTTP server from ${bundler} dev server; tunnel will not start`);
|
|
1848
|
+
missingServerWarned = true;
|
|
1849
|
+
}
|
|
1850
|
+
return;
|
|
1851
|
+
}
|
|
1852
|
+
if (lastHttpServer === httpServer) return;
|
|
1853
|
+
lastHttpServer = httpServer;
|
|
1854
|
+
httpServer.once("close", () => {
|
|
1855
|
+
if (lastHttpServer === httpServer) lastHttpServer = void 0;
|
|
1856
|
+
});
|
|
1857
|
+
const configuredPromise = configureServer({
|
|
1858
|
+
httpServer,
|
|
1859
|
+
config: { server: { port: devServerInstance.options?.port ?? devServerOptions?.port } }
|
|
1860
|
+
});
|
|
1861
|
+
globalState.tunnelUrl = configuredPromise.then(() => tunnelUrl).catch(() => "");
|
|
1862
|
+
configuredPromise.catch(() => {});
|
|
1863
|
+
};
|
|
1864
|
+
const scheduleConfiguration = (devServerInstance) => {
|
|
1865
|
+
const httpServer = devServerInstance?.server || devServerInstance?.httpServer || devServerInstance?.listeningApp;
|
|
1866
|
+
if (httpServer && typeof httpServer.once === "function") if (httpServer.listening) runConfiguration(devServerInstance);
|
|
1867
|
+
else httpServer.once("listening", () => runConfiguration(devServerInstance));
|
|
1868
|
+
else runConfiguration(devServerInstance);
|
|
1869
|
+
};
|
|
1870
|
+
const originalSetupMiddlewares = devServerOptions.setupMiddlewares;
|
|
1871
|
+
devServerOptions.setupMiddlewares = function(middlewares, devServer) {
|
|
1872
|
+
scheduleConfiguration(devServer);
|
|
1873
|
+
if (typeof originalSetupMiddlewares === "function") return originalSetupMiddlewares.call(this, middlewares, devServer);
|
|
1874
|
+
return middlewares;
|
|
1875
|
+
};
|
|
1876
|
+
const originalOnListening = devServerOptions.onListening;
|
|
1877
|
+
devServerOptions.onListening = function(devServer) {
|
|
1878
|
+
scheduleConfiguration(devServer);
|
|
1879
|
+
if (typeof originalOnListening === "function") return originalOnListening.call(this, devServer);
|
|
1880
|
+
};
|
|
1881
|
+
};
|
|
1882
|
+
return {
|
|
1883
|
+
name: PLUGIN_NAME,
|
|
1884
|
+
enforce: "pre",
|
|
1885
|
+
resolveId(id) {
|
|
1886
|
+
if (id === VIRTUAL_MODULE_ID) {
|
|
1887
|
+
debugLog("resolveId called for", id);
|
|
1888
|
+
return id;
|
|
1889
|
+
}
|
|
1890
|
+
},
|
|
1891
|
+
loadInclude(id) {
|
|
1892
|
+
return id === VIRTUAL_MODULE_ID;
|
|
1893
|
+
},
|
|
1894
|
+
async load(id) {
|
|
1895
|
+
if (id === VIRTUAL_MODULE_ID) {
|
|
1896
|
+
const url = await globalState.tunnelUrl;
|
|
1897
|
+
return `export function getTunnelUrl() { return ${JSON.stringify(url || "")}; }`;
|
|
1898
|
+
}
|
|
1899
|
+
},
|
|
1900
|
+
vite: {
|
|
1901
|
+
config: (config) => {
|
|
1902
|
+
announceConnecting();
|
|
1903
|
+
if (!config.server) config.server = {};
|
|
1904
|
+
ensureViteAllowedHosts(config.server);
|
|
1905
|
+
if (!isQuickMode) debugLog(`[unplugin-cloudflare-tunnel] Configured Vite to allow requests from ${hostname}`);
|
|
1906
|
+
},
|
|
1907
|
+
configureServer: (server) => {
|
|
1908
|
+
const configuredPromise = configureServer(server);
|
|
1909
|
+
globalState.tunnelUrl = configuredPromise.then(() => tunnelUrl).catch(() => "");
|
|
1910
|
+
return async () => {
|
|
1911
|
+
await configuredPromise;
|
|
1912
|
+
};
|
|
1913
|
+
}
|
|
1914
|
+
},
|
|
1915
|
+
esbuild: { config() {
|
|
1916
|
+
announceConnecting();
|
|
1917
|
+
if (typeof userProvidedPort === "number" && !Number.isNaN(userProvidedPort)) globalState.tunnelUrl = configureServer({ config: { server: { port: userProvidedPort } } }).then(() => tunnelUrl).catch(() => "");
|
|
1918
|
+
else {
|
|
1919
|
+
globalState.tunnelUrl = Promise.resolve("");
|
|
1920
|
+
console.warn("[unplugin-cloudflare-tunnel] esbuild requires the plugin `port` option to enable tunnel startup");
|
|
1921
|
+
}
|
|
1922
|
+
if (!isQuickMode) debugLog(`[unplugin-cloudflare-tunnel] Configured esbuild tunnel target for ${hostname}`);
|
|
1923
|
+
} },
|
|
1924
|
+
rspack: (compiler) => {
|
|
1925
|
+
setupWebpackLikeDevServerIntegration(compiler, "rspack");
|
|
1926
|
+
},
|
|
1927
|
+
webpack: (compiler) => {
|
|
1928
|
+
setupWebpackVirtualScheme(compiler);
|
|
1929
|
+
setupWebpackLikeDevServerIntegration(compiler, "webpack");
|
|
1930
|
+
},
|
|
1931
|
+
buildStart() {
|
|
1932
|
+
if (!this?.meta?.watchMode) return;
|
|
1933
|
+
if (typeof userProvidedPort !== "number" || Number.isNaN(userProvidedPort)) return;
|
|
1934
|
+
if (globalState.tunnelUrl) return;
|
|
1935
|
+
announceConnecting();
|
|
1936
|
+
globalState.tunnelUrl = configureServer({ config: { server: { port: userProvidedPort } } }).then(() => tunnelUrl).catch(() => "");
|
|
1937
|
+
},
|
|
1938
|
+
closeBundle() {
|
|
1939
|
+
if (this?.meta?.watchMode) return;
|
|
1940
|
+
killCloudflared("SIGTERM");
|
|
1941
|
+
delete globalState.child;
|
|
1942
|
+
delete globalState.configHash;
|
|
1943
|
+
delete globalState.shuttingDown;
|
|
1944
|
+
}
|
|
1945
|
+
};
|
|
1946
|
+
};
|
|
1947
|
+
const CloudflareTunnel = createUnplugin(unpluginFactory);
|
|
1948
|
+
//#endregion
|
|
1949
|
+
export { CloudflareTunnel as t };
|