@klnap/next-proxy-chain 1.0.2 → 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +55 -0
- package/LICENSE +21 -0
- package/README.md +165 -146
- package/dist/index.cjs +335 -320
- package/dist/index.d.cts +65 -169
- package/dist/index.d.ts +65 -169
- package/dist/index.js +334 -289
- package/package.json +19 -12
package/dist/index.cjs
CHANGED
|
@@ -20,47 +20,20 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/index.ts
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
|
-
DEFAULT_BLOCKED_REQUEST_HEADERS: () => DEFAULT_BLOCKED_REQUEST_HEADERS,
|
|
24
|
-
NEXT: () => NEXT,
|
|
25
23
|
RuleTimeoutError: () => RuleTimeoutError,
|
|
26
|
-
applyMergedToResponse: () => applyMergedToResponse,
|
|
27
|
-
assertIncludeExcludeNoOverlap: () => assertIncludeExcludeNoOverlap,
|
|
28
|
-
assertOverrideMechanismSupported: () => assertOverrideMechanismSupported,
|
|
29
|
-
compileScopes: () => compileScopes,
|
|
30
|
-
cookieItemsFromHeaders: () => cookieItemsFromHeaders,
|
|
31
|
-
createConsoleLogger: () => createConsoleLogger,
|
|
32
24
|
createProxyContext: () => createProxyContext,
|
|
33
|
-
decodeOverriddenRequestHeaders: () => decodeOverriddenRequestHeaders,
|
|
34
25
|
defineProxy: () => defineProxy,
|
|
35
|
-
finalizeResponse: () => finalizeResponse,
|
|
36
|
-
formatPipelineLine: () => formatPipelineLine,
|
|
37
|
-
headersDiffer: () => headersDiffer,
|
|
38
|
-
headersInitToHeaders: () => headersInitToHeaders,
|
|
39
26
|
host: () => host,
|
|
40
27
|
isNextResult: () => isNextResult,
|
|
41
|
-
isRequestHeaderAllowed: () => isRequestHeaderAllowed,
|
|
42
|
-
listSetCookie: () => listSetCookie,
|
|
43
|
-
mergeRequestHeaderOverrides: () => mergeRequestHeaderOverrides,
|
|
44
|
-
mergeWrites: () => mergeWrites,
|
|
45
28
|
next: () => next,
|
|
46
|
-
normalizeHost: () => normalizeHost,
|
|
47
|
-
parseCookieName: () => parseCookieName,
|
|
48
29
|
path: () => path,
|
|
49
|
-
|
|
50
|
-
proxyChain: () => proxyChain,
|
|
51
|
-
resolveRuleResult: () => resolveRuleResult,
|
|
52
|
-
responseHeaderItems: () => responseHeaderItems,
|
|
53
|
-
ruleLabel: () => ruleLabel,
|
|
54
|
-
ruleMatches: () => ruleMatches,
|
|
55
|
-
safeInternalError: () => safeInternalError,
|
|
56
|
-
toPathRegex: () => toPathRegex,
|
|
57
|
-
toRule: () => toRule,
|
|
58
|
-
toStatelessRegExp: () => toStatelessRegExp,
|
|
59
|
-
withPaths: () => withPaths,
|
|
60
|
-
withRuleTimeout: () => withRuleTimeout
|
|
30
|
+
proxyChain: () => proxyChain
|
|
61
31
|
});
|
|
62
32
|
module.exports = __toCommonJS(index_exports);
|
|
63
33
|
|
|
34
|
+
// src/core/engine.ts
|
|
35
|
+
var import_server2 = require("next/server");
|
|
36
|
+
|
|
64
37
|
// src/core/constants.ts
|
|
65
38
|
var NEXT = /* @__PURE__ */ Symbol.for("proxy-chain.next");
|
|
66
39
|
var DEFAULT_BLOCKED_REQUEST_HEADERS = Object.freeze([
|
|
@@ -84,178 +57,19 @@ var DEFAULT_BLOCKED_REQUEST_HEADERS = Object.freeze([
|
|
|
84
57
|
"x-middleware-override-headers"
|
|
85
58
|
]);
|
|
86
59
|
|
|
60
|
+
// src/core/actions.ts
|
|
61
|
+
function next(options = {}) {
|
|
62
|
+
return { [NEXT]: true, ...options };
|
|
63
|
+
}
|
|
64
|
+
function isNextResult(value) {
|
|
65
|
+
return typeof value === "object" && value !== null && NEXT in value;
|
|
66
|
+
}
|
|
67
|
+
|
|
87
68
|
// src/core/context.ts
|
|
88
69
|
function createProxyContext() {
|
|
89
70
|
return /* @__PURE__ */ new Map();
|
|
90
71
|
}
|
|
91
72
|
|
|
92
|
-
// src/core/matching.ts
|
|
93
|
-
var RESERVED_FN_NAMES = /* @__PURE__ */ new Set(["", "proxy", "anonymous", "run", "next"]);
|
|
94
|
-
function extractMeaningfulName(value) {
|
|
95
|
-
if (!value || RESERVED_FN_NAMES.has(value)) return void 0;
|
|
96
|
-
return value;
|
|
97
|
-
}
|
|
98
|
-
function toStatelessRegExp(re) {
|
|
99
|
-
const flags = re.flags.replace(/[gy]/g, "");
|
|
100
|
-
return flags === re.flags ? re : new RegExp(re.source, flags);
|
|
101
|
-
}
|
|
102
|
-
function escapeRegex(value) {
|
|
103
|
-
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
104
|
-
}
|
|
105
|
-
function host(matcher) {
|
|
106
|
-
const list = Array.isArray(matcher) ? matcher : [matcher];
|
|
107
|
-
const parts = list.map((m) => {
|
|
108
|
-
if (m instanceof RegExp) return `(?:${toStatelessRegExp(m).source})`;
|
|
109
|
-
return `(?:${escapeRegex(m.toLowerCase())})`;
|
|
110
|
-
});
|
|
111
|
-
return toStatelessRegExp(new RegExp(`^(?:${parts.join("|")})$`, "i"));
|
|
112
|
-
}
|
|
113
|
-
function isScopeObject(value) {
|
|
114
|
-
return "host" in value || "path" in value;
|
|
115
|
-
}
|
|
116
|
-
function segmentToRegex(segment) {
|
|
117
|
-
if (segment === "**") return "(?:.*)";
|
|
118
|
-
if (segment === "*") return "[^/]+";
|
|
119
|
-
if (segment.startsWith(":")) return "[^/]+";
|
|
120
|
-
return escapeRegex(segment);
|
|
121
|
-
}
|
|
122
|
-
function path(pattern, options = {}) {
|
|
123
|
-
const { locales = [] } = options;
|
|
124
|
-
const localePrefix = locales.length > 0 ? `(?:(?:${locales.map(escapeRegex).join("|")})\\/)?` : "";
|
|
125
|
-
if (pattern instanceof RegExp) {
|
|
126
|
-
const body2 = pattern.source.replace(/^\^/, "").replace(/\$$/, "");
|
|
127
|
-
const needsStart = !pattern.source.startsWith("^");
|
|
128
|
-
const needsEnd = !pattern.source.endsWith("$");
|
|
129
|
-
return toStatelessRegExp(
|
|
130
|
-
new RegExp(
|
|
131
|
-
`${needsStart ? "^" : ""}${localePrefix ? `/${localePrefix}` : ""}${body2}${needsEnd ? "$" : ""}`,
|
|
132
|
-
pattern.flags
|
|
133
|
-
)
|
|
134
|
-
);
|
|
135
|
-
}
|
|
136
|
-
const normalized = (pattern.startsWith("/") ? pattern : `/${pattern}`).replace(/\/$/, "") || "/";
|
|
137
|
-
const segments = normalized.slice(1).split("/");
|
|
138
|
-
const trailingStar = segments.length > 0 && segments[segments.length - 1] === "*";
|
|
139
|
-
const suffix = trailingStar ? "(?:\\/.*)?$" : "$";
|
|
140
|
-
const body = trailingStar ? segments.slice(0, -1).map(segmentToRegex).concat("[^/]+").join("\\/") : segments.map(segmentToRegex).join("\\/");
|
|
141
|
-
return new RegExp(`^/${localePrefix}${body}${suffix}`);
|
|
142
|
-
}
|
|
143
|
-
function toPathRegex(matcher, options) {
|
|
144
|
-
const list = Array.isArray(matcher) ? matcher : [matcher];
|
|
145
|
-
const regexes = list.map((m) => path(m, options));
|
|
146
|
-
if (regexes.length === 1) return toStatelessRegExp(regexes[0]);
|
|
147
|
-
return toStatelessRegExp(new RegExp(`(?:${regexes.map((r) => `(?:${r.source})`).join("|")})`));
|
|
148
|
-
}
|
|
149
|
-
function compileScopes(input, pathOptions) {
|
|
150
|
-
if (input == null) return void 0;
|
|
151
|
-
const list = Array.isArray(input) ? input : [input];
|
|
152
|
-
const compilePath = (matcher) => {
|
|
153
|
-
if (Array.isArray(matcher)) {
|
|
154
|
-
const parts = matcher.map(
|
|
155
|
-
(m) => typeof m === "string" ? path(m, pathOptions) : toStatelessRegExp(m)
|
|
156
|
-
);
|
|
157
|
-
if (parts.length === 1) return parts[0];
|
|
158
|
-
return toStatelessRegExp(new RegExp(`(?:${parts.map((r) => `(?:${r.source})`).join("|")})`));
|
|
159
|
-
}
|
|
160
|
-
return typeof matcher === "string" ? path(matcher, pathOptions) : toStatelessRegExp(matcher);
|
|
161
|
-
};
|
|
162
|
-
const compiled = [];
|
|
163
|
-
for (const item of list) {
|
|
164
|
-
if (typeof item === "string" || item instanceof RegExp) {
|
|
165
|
-
compiled.push({ path: compilePath(item) });
|
|
166
|
-
continue;
|
|
167
|
-
}
|
|
168
|
-
if (item && typeof item === "object" && isScopeObject(item)) {
|
|
169
|
-
if (item.host == null && item.path == null) {
|
|
170
|
-
throw new Error("[proxy-chain] scope needs at least `host` or `path`");
|
|
171
|
-
}
|
|
172
|
-
compiled.push({
|
|
173
|
-
host: item.host != null ? host(item.host) : void 0,
|
|
174
|
-
path: item.path != null ? compilePath(item.path) : void 0
|
|
175
|
-
});
|
|
176
|
-
continue;
|
|
177
|
-
}
|
|
178
|
-
throw new Error("[proxy-chain] invalid include/exclude scope");
|
|
179
|
-
}
|
|
180
|
-
return compiled;
|
|
181
|
-
}
|
|
182
|
-
function scopeMatches(pathname, hostname, scope) {
|
|
183
|
-
if (scope.host) {
|
|
184
|
-
if (!hostname || !scope.host.test(hostname)) return false;
|
|
185
|
-
}
|
|
186
|
-
if (scope.path) {
|
|
187
|
-
if (!scope.path.test(pathname)) return false;
|
|
188
|
-
}
|
|
189
|
-
return true;
|
|
190
|
-
}
|
|
191
|
-
function toRule(entry) {
|
|
192
|
-
if (typeof entry === "function") {
|
|
193
|
-
const name2 = extractMeaningfulName(entry.name);
|
|
194
|
-
return name2 ? { run: entry, name: name2 } : { run: entry };
|
|
195
|
-
}
|
|
196
|
-
const rule = entry;
|
|
197
|
-
const runName = typeof rule.run === "function" ? extractMeaningfulName(rule.run.name) : void 0;
|
|
198
|
-
const name = extractMeaningfulName(rule.name) ?? runName;
|
|
199
|
-
const harden = (scopes) => scopes?.map((s) => ({
|
|
200
|
-
host: s.host ? toStatelessRegExp(s.host) : void 0,
|
|
201
|
-
path: s.path ? toStatelessRegExp(s.path) : void 0
|
|
202
|
-
}));
|
|
203
|
-
return {
|
|
204
|
-
...rule,
|
|
205
|
-
name: name ?? void 0,
|
|
206
|
-
include: harden(rule.include),
|
|
207
|
-
exclude: harden(rule.exclude)
|
|
208
|
-
};
|
|
209
|
-
}
|
|
210
|
-
function ruleLabel(rule, index) {
|
|
211
|
-
const runName = typeof rule.run === "function" ? extractMeaningfulName(rule.run.name) : void 0;
|
|
212
|
-
return extractMeaningfulName(rule.name) ?? runName ?? `rule#${index}`;
|
|
213
|
-
}
|
|
214
|
-
function withPaths(entry, filter) {
|
|
215
|
-
const base = toRule(entry);
|
|
216
|
-
const opts = filter.pathOptions;
|
|
217
|
-
const include = compileScopes(filter.include, opts);
|
|
218
|
-
const exclude = compileScopes(filter.exclude, opts);
|
|
219
|
-
const name = filter.name ?? base.name;
|
|
220
|
-
assertIncludeExcludeNoOverlap(include, exclude, name ?? "proxy");
|
|
221
|
-
return { run: base.run, include, exclude, name };
|
|
222
|
-
}
|
|
223
|
-
function ruleMatches(pathname, hostname, rule) {
|
|
224
|
-
if (rule.exclude?.some((scope) => scopeMatches(pathname, hostname, scope))) return false;
|
|
225
|
-
if (rule.include && !rule.include.some((scope) => scopeMatches(pathname, hostname, scope))) {
|
|
226
|
-
return false;
|
|
227
|
-
}
|
|
228
|
-
return true;
|
|
229
|
-
}
|
|
230
|
-
function pathMatches(pathname, rule) {
|
|
231
|
-
return ruleMatches(pathname, null, rule);
|
|
232
|
-
}
|
|
233
|
-
function normalizeHost(raw) {
|
|
234
|
-
if (!raw) return null;
|
|
235
|
-
const first = raw.split(",")[0]?.trim().toLowerCase();
|
|
236
|
-
if (!first) return null;
|
|
237
|
-
if (first.startsWith("[")) {
|
|
238
|
-
const end = first.indexOf("]");
|
|
239
|
-
return end === -1 ? first : first.slice(1, end);
|
|
240
|
-
}
|
|
241
|
-
const withoutPort = first.replace(/:\d+$/, "");
|
|
242
|
-
return withoutPort || null;
|
|
243
|
-
}
|
|
244
|
-
function scopeKey(scope) {
|
|
245
|
-
return `${scope.host?.source ?? "*"}::${scope.host?.flags ?? ""}|${scope.path?.source ?? "*"}::${scope.path?.flags ?? ""}`;
|
|
246
|
-
}
|
|
247
|
-
function assertIncludeExcludeNoOverlap(include, exclude, label) {
|
|
248
|
-
if (!include?.length || !exclude?.length) return;
|
|
249
|
-
const excluded = new Set(exclude.map(scopeKey));
|
|
250
|
-
for (const scope of include) {
|
|
251
|
-
if (excluded.has(scopeKey(scope))) {
|
|
252
|
-
throw new Error(
|
|
253
|
-
`[proxy-chain] ${label}: include and exclude share an identical scope. Remove one.`
|
|
254
|
-
);
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
|
|
259
73
|
// src/core/headers.ts
|
|
260
74
|
function normalizeHeaderName(name) {
|
|
261
75
|
return name.toLowerCase();
|
|
@@ -298,15 +112,32 @@ function parseCookieName(setCookie) {
|
|
|
298
112
|
return (eq === -1 ? setCookie : setCookie.slice(0, eq)).trim();
|
|
299
113
|
}
|
|
300
114
|
function listSetCookie(headers) {
|
|
301
|
-
|
|
302
|
-
if (typeof extended.getSetCookie === "function") return extended.getSetCookie();
|
|
115
|
+
if (typeof headers.getSetCookie === "function") return headers.getSetCookie();
|
|
303
116
|
const single = headers.get("set-cookie");
|
|
304
117
|
return single ? [single] : [];
|
|
305
118
|
}
|
|
119
|
+
function cookieAttribute(setCookie, name) {
|
|
120
|
+
const parts = setCookie.split(";");
|
|
121
|
+
for (let i = 1; i < parts.length; i++) {
|
|
122
|
+
const piece = parts[i];
|
|
123
|
+
if (!piece) continue;
|
|
124
|
+
const eq = piece.indexOf("=");
|
|
125
|
+
const key = (eq === -1 ? piece : piece.slice(0, eq)).trim().toLowerCase();
|
|
126
|
+
if (key !== name) continue;
|
|
127
|
+
return (eq === -1 ? "" : piece.slice(eq + 1)).trim();
|
|
128
|
+
}
|
|
129
|
+
return "";
|
|
130
|
+
}
|
|
131
|
+
function cookieIdentityKey(setCookie) {
|
|
132
|
+
const name = parseCookieName(setCookie);
|
|
133
|
+
const path2 = cookieAttribute(setCookie, "path");
|
|
134
|
+
const domain = cookieAttribute(setCookie, "domain").toLowerCase();
|
|
135
|
+
return `${name};domain=${domain};path=${path2}`;
|
|
136
|
+
}
|
|
306
137
|
function cookieItemsFromHeaders(headers) {
|
|
307
138
|
const map = /* @__PURE__ */ new Map();
|
|
308
139
|
for (const value of listSetCookie(headers)) {
|
|
309
|
-
map.set(
|
|
140
|
+
map.set(cookieIdentityKey(value), value);
|
|
310
141
|
}
|
|
311
142
|
return map;
|
|
312
143
|
}
|
|
@@ -366,7 +197,12 @@ function mergeWrites(writes, strategy, onConflict) {
|
|
|
366
197
|
}
|
|
367
198
|
return resolved;
|
|
368
199
|
}
|
|
369
|
-
function applyMergedToResponse(res, headers, cookies) {
|
|
200
|
+
function applyMergedToResponse(res, headers, cookies, dropHeaders) {
|
|
201
|
+
if (dropHeaders) {
|
|
202
|
+
for (const key of dropHeaders) {
|
|
203
|
+
if (!headers.has(key)) res.headers.delete(key);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
370
206
|
for (const [key, value] of headers) {
|
|
371
207
|
res.headers.set(key, value);
|
|
372
208
|
}
|
|
@@ -376,14 +212,6 @@ function applyMergedToResponse(res, headers, cookies) {
|
|
|
376
212
|
}
|
|
377
213
|
}
|
|
378
214
|
|
|
379
|
-
// src/core/actions.ts
|
|
380
|
-
function next(options = {}) {
|
|
381
|
-
return { [NEXT]: true, ...options };
|
|
382
|
-
}
|
|
383
|
-
function isNextResult(value) {
|
|
384
|
-
return typeof value === "object" && value !== null && NEXT in value;
|
|
385
|
-
}
|
|
386
|
-
|
|
387
215
|
// src/core/logger.ts
|
|
388
216
|
var LEVEL_RANK = {
|
|
389
217
|
debug: 10,
|
|
@@ -427,27 +255,180 @@ function formatPipelineLine(input) {
|
|
|
427
255
|
}
|
|
428
256
|
}
|
|
429
257
|
|
|
430
|
-
// src/core/
|
|
431
|
-
var
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
258
|
+
// src/core/matching.ts
|
|
259
|
+
var RESERVED_FN_NAMES = /* @__PURE__ */ new Set(["", "proxy", "anonymous", "run", "next"]);
|
|
260
|
+
function extractMeaningfulName(value) {
|
|
261
|
+
if (!value || RESERVED_FN_NAMES.has(value)) return void 0;
|
|
262
|
+
return value;
|
|
263
|
+
}
|
|
264
|
+
function toStatelessRegExp(re) {
|
|
265
|
+
const flags = re.flags.replace(/[gy]/g, "");
|
|
266
|
+
return flags === re.flags ? re : new RegExp(re.source, flags);
|
|
267
|
+
}
|
|
268
|
+
function escapeRegex(value) {
|
|
269
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
270
|
+
}
|
|
271
|
+
function hostGlobToRegex(value) {
|
|
272
|
+
return escapeRegex(value.toLowerCase()).replace(/\\\*/g, "[^.]+");
|
|
273
|
+
}
|
|
274
|
+
function host(matcher) {
|
|
275
|
+
const list = Array.isArray(matcher) ? matcher : [matcher];
|
|
276
|
+
const parts = list.map((m) => {
|
|
277
|
+
if (m instanceof RegExp) return `(?:${toStatelessRegExp(m).source})`;
|
|
278
|
+
return `(?:${hostGlobToRegex(m)})`;
|
|
446
279
|
});
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
280
|
+
return toStatelessRegExp(new RegExp(`^(?:${parts.join("|")})$`, "i"));
|
|
281
|
+
}
|
|
282
|
+
function isScopeObject(value) {
|
|
283
|
+
return "host" in value || "path" in value;
|
|
284
|
+
}
|
|
285
|
+
function segmentToRegex(segment) {
|
|
286
|
+
if (segment === "**") return "(?:.*)";
|
|
287
|
+
if (segment === "*") return "[^/]+";
|
|
288
|
+
if (segment.startsWith(":")) return "[^/]+";
|
|
289
|
+
return escapeRegex(segment);
|
|
290
|
+
}
|
|
291
|
+
function hasEndAnchor(source) {
|
|
292
|
+
if (!source.endsWith("$")) return false;
|
|
293
|
+
let slashes = 0;
|
|
294
|
+
for (let i = source.length - 2; i >= 0 && source[i] === "\\"; i--) slashes++;
|
|
295
|
+
return slashes % 2 === 0;
|
|
296
|
+
}
|
|
297
|
+
function compileRegexPath(pattern) {
|
|
298
|
+
let source = pattern.source;
|
|
299
|
+
const hasStart = source.startsWith("^");
|
|
300
|
+
const hasEnd = hasEndAnchor(source);
|
|
301
|
+
if (hasStart) source = source.slice(1);
|
|
302
|
+
if (hasEnd) source = source.slice(0, -1);
|
|
303
|
+
const wrapFull = !hasStart && !hasEnd;
|
|
304
|
+
const start = hasStart || wrapFull ? "^" : "";
|
|
305
|
+
const end = hasEnd || wrapFull ? "$" : "";
|
|
306
|
+
return toStatelessRegExp(new RegExp(`${start}${source}${end}`, pattern.flags));
|
|
307
|
+
}
|
|
308
|
+
function compileStringPath(pattern) {
|
|
309
|
+
const normalized = (pattern.startsWith("/") ? pattern : `/${pattern}`).replace(/\/$/, "") || "/";
|
|
310
|
+
const segments = normalized === "/" ? [] : normalized.slice(1).split("/");
|
|
311
|
+
const last = segments[segments.length - 1];
|
|
312
|
+
const trailingStar = last === "*";
|
|
313
|
+
const trailingGlobstar = last === "**";
|
|
314
|
+
let pathPattern;
|
|
315
|
+
if (normalized === "/") {
|
|
316
|
+
pathPattern = "/";
|
|
317
|
+
} else if (trailingStar) {
|
|
318
|
+
const prefix = segments.slice(0, -1).map(segmentToRegex).join("/");
|
|
319
|
+
pathPattern = prefix ? `/${prefix}/[^/]+` : `/[^/]+`;
|
|
320
|
+
} else if (trailingGlobstar) {
|
|
321
|
+
const prefix = segments.slice(0, -1).map(segmentToRegex).join("/");
|
|
322
|
+
pathPattern = prefix ? `/${prefix}(?:/.*)?` : `/(?:.*)?`;
|
|
323
|
+
} else {
|
|
324
|
+
pathPattern = `/${segments.map(segmentToRegex).join("/")}`;
|
|
325
|
+
}
|
|
326
|
+
return new RegExp(`^${pathPattern}$`);
|
|
327
|
+
}
|
|
328
|
+
function path(pattern) {
|
|
329
|
+
if (pattern instanceof RegExp) return compileRegexPath(pattern);
|
|
330
|
+
return compileStringPath(pattern);
|
|
331
|
+
}
|
|
332
|
+
function toPathRegex(matcher) {
|
|
333
|
+
const list = Array.isArray(matcher) ? matcher : [matcher];
|
|
334
|
+
const regexes = list.map((m) => path(m));
|
|
335
|
+
if (regexes.length === 1) return toStatelessRegExp(regexes[0]);
|
|
336
|
+
return toStatelessRegExp(new RegExp(`(?:${regexes.map((r) => `(?:${r.source})`).join("|")})`));
|
|
337
|
+
}
|
|
338
|
+
function compileScopes(input) {
|
|
339
|
+
if (input == null) return void 0;
|
|
340
|
+
const list = Array.isArray(input) ? input : [input];
|
|
341
|
+
const compilePath = (matcher) => toPathRegex(matcher);
|
|
342
|
+
const compiled = [];
|
|
343
|
+
for (const item of list) {
|
|
344
|
+
if (typeof item === "string" || item instanceof RegExp) {
|
|
345
|
+
compiled.push({ path: compilePath(item) });
|
|
346
|
+
continue;
|
|
347
|
+
}
|
|
348
|
+
if (item && typeof item === "object" && isScopeObject(item)) {
|
|
349
|
+
if (item.host == null && item.path == null) {
|
|
350
|
+
throw new Error("[proxy-chain] scope needs at least `host` or `path`");
|
|
351
|
+
}
|
|
352
|
+
compiled.push({
|
|
353
|
+
host: item.host != null ? host(item.host) : void 0,
|
|
354
|
+
path: item.path != null ? compilePath(item.path) : void 0
|
|
355
|
+
});
|
|
356
|
+
continue;
|
|
357
|
+
}
|
|
358
|
+
throw new Error("[proxy-chain] invalid include/exclude scope");
|
|
359
|
+
}
|
|
360
|
+
return compiled;
|
|
361
|
+
}
|
|
362
|
+
function scopeMatches(pathname, hostname, scope) {
|
|
363
|
+
if (scope.host) {
|
|
364
|
+
if (!hostname || !scope.host.test(hostname)) return false;
|
|
365
|
+
}
|
|
366
|
+
if (scope.path) {
|
|
367
|
+
if (!scope.path.test(pathname)) return false;
|
|
368
|
+
}
|
|
369
|
+
return true;
|
|
370
|
+
}
|
|
371
|
+
function toRule(entry) {
|
|
372
|
+
if (typeof entry === "function") {
|
|
373
|
+
const name2 = extractMeaningfulName(entry.name);
|
|
374
|
+
return name2 ? { run: entry, name: name2 } : { run: entry };
|
|
375
|
+
}
|
|
376
|
+
const rule = entry;
|
|
377
|
+
const runName = typeof rule.run === "function" ? extractMeaningfulName(rule.run.name) : void 0;
|
|
378
|
+
const name = extractMeaningfulName(rule.name) ?? runName;
|
|
379
|
+
const harden = (scopes) => scopes?.map((s) => ({
|
|
380
|
+
host: s.host ? toStatelessRegExp(s.host) : void 0,
|
|
381
|
+
path: s.path ? toStatelessRegExp(s.path) : void 0
|
|
382
|
+
}));
|
|
383
|
+
return {
|
|
384
|
+
...rule,
|
|
385
|
+
name: name ?? void 0,
|
|
386
|
+
include: harden(rule.include),
|
|
387
|
+
exclude: harden(rule.exclude)
|
|
388
|
+
};
|
|
389
|
+
}
|
|
390
|
+
function ruleLabel(rule, index) {
|
|
391
|
+
const runName = typeof rule.run === "function" ? extractMeaningfulName(rule.run.name) : void 0;
|
|
392
|
+
return extractMeaningfulName(rule.name) ?? runName ?? `rule#${index}`;
|
|
393
|
+
}
|
|
394
|
+
function withPaths(entry, filter) {
|
|
395
|
+
const base = toRule(entry);
|
|
396
|
+
const include = compileScopes(filter.include);
|
|
397
|
+
const exclude = compileScopes(filter.exclude);
|
|
398
|
+
const name = filter.name ?? base.name;
|
|
399
|
+
assertIncludeExcludeNoOverlap(include, exclude, name ?? "proxy");
|
|
400
|
+
return { run: base.run, include, exclude, name };
|
|
401
|
+
}
|
|
402
|
+
function ruleMatches(pathname, hostname, rule) {
|
|
403
|
+
if (rule.exclude?.some((scope) => scopeMatches(pathname, hostname, scope))) return false;
|
|
404
|
+
if (rule.include && !rule.include.some((scope) => scopeMatches(pathname, hostname, scope))) {
|
|
405
|
+
return false;
|
|
406
|
+
}
|
|
407
|
+
return true;
|
|
408
|
+
}
|
|
409
|
+
function normalizeHost(raw) {
|
|
410
|
+
if (!raw) return null;
|
|
411
|
+
const first = raw.split(",")[0]?.trim().toLowerCase();
|
|
412
|
+
if (!first) return null;
|
|
413
|
+
if (first.startsWith("[")) {
|
|
414
|
+
const end = first.indexOf("]");
|
|
415
|
+
return end === -1 ? first : first.slice(1, end);
|
|
416
|
+
}
|
|
417
|
+
const withoutPort = first.replace(/:\d+$/, "");
|
|
418
|
+
return withoutPort || null;
|
|
419
|
+
}
|
|
420
|
+
function scopeKey(scope) {
|
|
421
|
+
return `${scope.host?.source ?? "*"}::${scope.host?.flags ?? ""}|${scope.path?.source ?? "*"}::${scope.path?.flags ?? ""}`;
|
|
422
|
+
}
|
|
423
|
+
function assertIncludeExcludeNoOverlap(include, exclude, label) {
|
|
424
|
+
if (!include?.length || !exclude?.length) return;
|
|
425
|
+
const excluded = new Set(exclude.map(scopeKey));
|
|
426
|
+
for (const scope of include) {
|
|
427
|
+
if (excluded.has(scopeKey(scope))) {
|
|
428
|
+
throw new Error(
|
|
429
|
+
`[proxy-chain] ${label}: include and exclude share an identical scope. Remove one.`
|
|
430
|
+
);
|
|
431
|
+
}
|
|
451
432
|
}
|
|
452
433
|
}
|
|
453
434
|
|
|
@@ -459,26 +440,42 @@ function safeInternalError() {
|
|
|
459
440
|
headers: { "content-type": "text/plain; charset=utf-8" }
|
|
460
441
|
});
|
|
461
442
|
}
|
|
462
|
-
var
|
|
443
|
+
var UNSUPPORTED_OVERRIDE_MSG = "[proxy-chain] Warning: platform NextResponse.next() does not support x-middleware-next header overrides.";
|
|
444
|
+
var VERIFY_OVERRIDE_MSG = "[proxy-chain] Warning: unable to verify NextResponse request override mechanism.";
|
|
445
|
+
var cachedOverrideProbe = null;
|
|
446
|
+
var overrideProbeForTests = null;
|
|
447
|
+
function runOverrideProbe() {
|
|
448
|
+
if (overrideProbeForTests) return overrideProbeForTests();
|
|
449
|
+
const testRes = import_server.NextResponse.next({
|
|
450
|
+
request: { headers: new Headers({ "x-proxy-chain-probe": "1" }) }
|
|
451
|
+
});
|
|
452
|
+
return testRes.headers.get("x-middleware-next") === "1";
|
|
453
|
+
}
|
|
454
|
+
function throwForCachedProbe(probe) {
|
|
455
|
+
if (probe.kind === "unsupported") throw new Error(UNSUPPORTED_OVERRIDE_MSG);
|
|
456
|
+
throw probe.err instanceof Error ? probe.err : new Error(VERIFY_OVERRIDE_MSG);
|
|
457
|
+
}
|
|
458
|
+
function resolveCachedProbe(probe, strict) {
|
|
459
|
+
if (probe.kind === "supported") return true;
|
|
460
|
+
if (strict) throwForCachedProbe(probe);
|
|
461
|
+
return false;
|
|
462
|
+
}
|
|
463
463
|
function assertOverrideMechanismSupported(strict = false) {
|
|
464
|
-
if (
|
|
464
|
+
if (cachedOverrideProbe !== null) return resolveCachedProbe(cachedOverrideProbe, strict);
|
|
465
465
|
try {
|
|
466
|
-
const
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
cachedOverrideSupported = isSupported;
|
|
471
|
-
if (!isSupported) {
|
|
472
|
-
const msg = "[proxy-chain] Warning: platform NextResponse.next() does not support x-middleware-next header overrides.";
|
|
473
|
-
if (strict) throw new Error(msg);
|
|
474
|
-
console.warn(msg);
|
|
466
|
+
const isSupported = runOverrideProbe();
|
|
467
|
+
if (isSupported) {
|
|
468
|
+
cachedOverrideProbe = { kind: "supported" };
|
|
469
|
+
return true;
|
|
475
470
|
}
|
|
476
|
-
|
|
471
|
+
cachedOverrideProbe = { kind: "unsupported" };
|
|
472
|
+
if (strict) throw new Error(UNSUPPORTED_OVERRIDE_MSG);
|
|
473
|
+
console.warn(UNSUPPORTED_OVERRIDE_MSG);
|
|
474
|
+
return false;
|
|
477
475
|
} catch (err) {
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
console.warn(msg, err);
|
|
476
|
+
cachedOverrideProbe = { kind: "error", err };
|
|
477
|
+
if (strict) throw err instanceof Error ? err : new Error(VERIFY_OVERRIDE_MSG);
|
|
478
|
+
console.warn(VERIFY_OVERRIDE_MSG, err);
|
|
482
479
|
return false;
|
|
483
480
|
}
|
|
484
481
|
}
|
|
@@ -500,11 +497,12 @@ function resolveRuleResult(res, requestHeaderPolicy, logger, debug) {
|
|
|
500
497
|
}
|
|
501
498
|
if ([...filtered.keys()].length) request = filtered;
|
|
502
499
|
}
|
|
500
|
+
const headerInit = res.headers ? headersInitToHeaders(res.headers) : void 0;
|
|
503
501
|
return {
|
|
504
502
|
kind: "continue",
|
|
505
503
|
request,
|
|
506
|
-
responseHeaders:
|
|
507
|
-
cookies: /* @__PURE__ */ new Map()
|
|
504
|
+
responseHeaders: headerInit ? responseHeaderItems(headerInit) : /* @__PURE__ */ new Map(),
|
|
505
|
+
cookies: headerInit ? cookieItemsFromHeaders(headerInit) : /* @__PURE__ */ new Map()
|
|
508
506
|
};
|
|
509
507
|
}
|
|
510
508
|
if (res.headers.get("x-middleware-next") === "1") {
|
|
@@ -548,16 +546,57 @@ function finalizeResponse(res, headerWrites, cookieWrites, headerStrategy, cooki
|
|
|
548
546
|
const cookies = mergeWrites(cookieWrites, cookieStrategy, (key, winner, loser) => {
|
|
549
547
|
if (debug) logger.debug({ cookie: key, winner, loser }, "cookie conflict resolved");
|
|
550
548
|
});
|
|
551
|
-
|
|
549
|
+
const seenHeaders = /* @__PURE__ */ new Set();
|
|
550
|
+
for (const write of headerWrites) {
|
|
551
|
+
for (const key of write.items.keys()) seenHeaders.add(key);
|
|
552
|
+
}
|
|
553
|
+
const dropHeaders = [];
|
|
554
|
+
for (const key of seenHeaders) {
|
|
555
|
+
if (!headers.has(key)) dropHeaders.push(key);
|
|
556
|
+
}
|
|
557
|
+
applyMergedToResponse(res, headers, cookies, dropHeaders);
|
|
552
558
|
return res;
|
|
553
559
|
}
|
|
554
560
|
|
|
561
|
+
// src/core/timeout.ts
|
|
562
|
+
var RuleTimeoutError = class extends Error {
|
|
563
|
+
ruleName;
|
|
564
|
+
timeoutMs;
|
|
565
|
+
constructor(ruleName, timeoutMs) {
|
|
566
|
+
super(`[proxy-chain] ${ruleName} timed out after ${timeoutMs}ms`);
|
|
567
|
+
this.name = "RuleTimeoutError";
|
|
568
|
+
this.ruleName = ruleName;
|
|
569
|
+
this.timeoutMs = timeoutMs;
|
|
570
|
+
}
|
|
571
|
+
};
|
|
572
|
+
function assertFiniteRuleTimeoutMs(ruleTimeoutMs) {
|
|
573
|
+
if (ruleTimeoutMs != null && !Number.isFinite(ruleTimeoutMs)) {
|
|
574
|
+
throw new RangeError(
|
|
575
|
+
`[proxy-chain] ruleTimeoutMs must be a finite positive number, got ${ruleTimeoutMs}`
|
|
576
|
+
);
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
async function withRuleTimeout(promise, timeoutMs, ruleName) {
|
|
580
|
+
assertFiniteRuleTimeoutMs(timeoutMs);
|
|
581
|
+
if (timeoutMs == null || timeoutMs <= 0) return promise;
|
|
582
|
+
let timer;
|
|
583
|
+
const timeout = new Promise((_, reject) => {
|
|
584
|
+
timer = setTimeout(() => reject(new RuleTimeoutError(ruleName, timeoutMs)), timeoutMs);
|
|
585
|
+
});
|
|
586
|
+
try {
|
|
587
|
+
return await Promise.race([promise, timeout]);
|
|
588
|
+
} finally {
|
|
589
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
590
|
+
void promise.catch(() => {
|
|
591
|
+
});
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
|
|
555
595
|
// src/core/engine.ts
|
|
556
|
-
var import_server2 = require("next/server");
|
|
557
596
|
function isPathFilter(value) {
|
|
558
597
|
if (value === null || typeof value !== "object") return false;
|
|
559
598
|
if ("nextUrl" in value) return false;
|
|
560
|
-
return "include" in value || "exclude" in value || "name" in value
|
|
599
|
+
return "include" in value || "exclude" in value || "name" in value;
|
|
561
600
|
}
|
|
562
601
|
function defineProxy(nameOrRun, maybeRun) {
|
|
563
602
|
const defaultName = typeof nameOrRun === "string" ? nameOrRun : void 0;
|
|
@@ -577,25 +616,47 @@ function defineProxy(nameOrRun, maybeRun) {
|
|
|
577
616
|
});
|
|
578
617
|
return proxy;
|
|
579
618
|
}
|
|
580
|
-
function resolveConfig(overrides
|
|
581
|
-
const { logger, debug, ...rest } = overrides;
|
|
582
|
-
|
|
583
|
-
createContext:
|
|
619
|
+
function resolveConfig(overrides, fallbackCreateContext) {
|
|
620
|
+
const { logger, debug, createContext, ...rest } = overrides;
|
|
621
|
+
const config = {
|
|
622
|
+
createContext: createContext ?? fallbackCreateContext,
|
|
584
623
|
cookieMergeStrategy: "last-write-wins",
|
|
585
624
|
headerMergeStrategy: "last-write-wins",
|
|
586
625
|
debug: false,
|
|
587
626
|
ruleTimeoutMs: 0,
|
|
588
627
|
requestHeaderPolicy: {},
|
|
589
628
|
strictOverrideCheck: false,
|
|
629
|
+
hostFolderHeader: void 0,
|
|
590
630
|
...rest,
|
|
591
631
|
...debug !== void 0 ? { debug } : {},
|
|
592
632
|
logger: logger ?? createConsoleLogger(debug ? "debug" : "info")
|
|
593
633
|
};
|
|
634
|
+
assertFiniteRuleTimeoutMs(config.ruleTimeoutMs);
|
|
635
|
+
return config;
|
|
636
|
+
}
|
|
637
|
+
function physicalFolderPrefix(raw) {
|
|
638
|
+
return "/" + raw.replace(/^\/+|\/+$/g, "").split("/").filter((seg) => !/^\(.*\)$/.test(seg)).join("/");
|
|
639
|
+
}
|
|
640
|
+
function applyFolderPrefix(rewriteUrl, folder, baseUrl) {
|
|
641
|
+
try {
|
|
642
|
+
const parsed = new URL(rewriteUrl, baseUrl);
|
|
643
|
+
if (!parsed.pathname.startsWith(folder)) {
|
|
644
|
+
parsed.pathname = folder + (parsed.pathname === "/" ? "" : parsed.pathname);
|
|
645
|
+
return parsed.toString();
|
|
646
|
+
}
|
|
647
|
+
return rewriteUrl;
|
|
648
|
+
} catch {
|
|
649
|
+
if (!rewriteUrl.startsWith(folder)) {
|
|
650
|
+
return folder + (rewriteUrl === "/" ? "" : rewriteUrl);
|
|
651
|
+
}
|
|
652
|
+
return rewriteUrl;
|
|
653
|
+
}
|
|
594
654
|
}
|
|
595
655
|
function proxyChain(optionsOrEntries, maybeEntries) {
|
|
596
656
|
const options = Array.isArray(optionsOrEntries) ? {} : optionsOrEntries;
|
|
597
|
-
const entries = Array.isArray(optionsOrEntries) ? optionsOrEntries : maybeEntries;
|
|
598
|
-
const
|
|
657
|
+
const entries = (Array.isArray(optionsOrEntries) ? optionsOrEntries : maybeEntries) ?? [];
|
|
658
|
+
const fallbackCreateContext = createProxyContext;
|
|
659
|
+
const config = resolveConfig(options, fallbackCreateContext);
|
|
599
660
|
const rules = entries.map(toRule);
|
|
600
661
|
const {
|
|
601
662
|
logger,
|
|
@@ -604,7 +665,8 @@ function proxyChain(optionsOrEntries, maybeEntries) {
|
|
|
604
665
|
headerMergeStrategy,
|
|
605
666
|
ruleTimeoutMs,
|
|
606
667
|
requestHeaderPolicy,
|
|
607
|
-
strictOverrideCheck
|
|
668
|
+
strictOverrideCheck,
|
|
669
|
+
hostFolderHeader
|
|
608
670
|
} = config;
|
|
609
671
|
assertOverrideMechanismSupported(strictOverrideCheck);
|
|
610
672
|
for (let i = 0; i < rules.length; i++) {
|
|
@@ -670,7 +732,7 @@ function proxyChain(optionsOrEntries, maybeEntries) {
|
|
|
670
732
|
if (config.onError) {
|
|
671
733
|
try {
|
|
672
734
|
const recovered = await config.onError(err, i, activeReq, ctx);
|
|
673
|
-
if (recovered == null)
|
|
735
|
+
if (recovered == null) return safeInternalError();
|
|
674
736
|
if (isNextResult(recovered)) {
|
|
675
737
|
raw = recovered;
|
|
676
738
|
} else if (recovered instanceof Response) {
|
|
@@ -709,7 +771,7 @@ function proxyChain(optionsOrEntries, maybeEntries) {
|
|
|
709
771
|
debug
|
|
710
772
|
);
|
|
711
773
|
} else {
|
|
712
|
-
|
|
774
|
+
return safeInternalError();
|
|
713
775
|
}
|
|
714
776
|
} catch (onErrorErr) {
|
|
715
777
|
logger.error({ rule: label, err: onErrorErr }, "onError handler threw");
|
|
@@ -725,6 +787,9 @@ function proxyChain(optionsOrEntries, maybeEntries) {
|
|
|
725
787
|
if (outcome.kind === "continue") {
|
|
726
788
|
if (outcome.rewriteUrl) {
|
|
727
789
|
pendingRewriteUrl = outcome.rewriteUrl;
|
|
790
|
+
if (currentReq === req) {
|
|
791
|
+
currentReq = new import_server2.NextRequest(currentReq);
|
|
792
|
+
}
|
|
728
793
|
try {
|
|
729
794
|
const parsed = new URL(outcome.rewriteUrl);
|
|
730
795
|
currentReq.nextUrl.pathname = parsed.pathname;
|
|
@@ -777,24 +842,14 @@ function proxyChain(optionsOrEntries, maybeEntries) {
|
|
|
777
842
|
})
|
|
778
843
|
);
|
|
779
844
|
}
|
|
780
|
-
const internalFolder = appliedRequestOverrides.get(
|
|
845
|
+
const internalFolder = hostFolderHeader ? appliedRequestOverrides.get(hostFolderHeader) : null;
|
|
781
846
|
if (internalFolder && outcome.response.headers.has("x-middleware-rewrite")) {
|
|
782
847
|
const rawRewrite = outcome.response.headers.get("x-middleware-rewrite");
|
|
783
|
-
const cleanFolder =
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
outcome.response.headers.set("x-middleware-rewrite", parsed.toString());
|
|
789
|
-
}
|
|
790
|
-
} catch {
|
|
791
|
-
if (!rawRewrite.startsWith(cleanFolder)) {
|
|
792
|
-
outcome.response.headers.set(
|
|
793
|
-
"x-middleware-rewrite",
|
|
794
|
-
cleanFolder + (rawRewrite === "/" ? "" : rawRewrite)
|
|
795
|
-
);
|
|
796
|
-
}
|
|
797
|
-
}
|
|
848
|
+
const cleanFolder = physicalFolderPrefix(internalFolder);
|
|
849
|
+
outcome.response.headers.set(
|
|
850
|
+
"x-middleware-rewrite",
|
|
851
|
+
applyFolderPrefix(rawRewrite, cleanFolder, currentReq.url)
|
|
852
|
+
);
|
|
798
853
|
}
|
|
799
854
|
return finalizeResponse(
|
|
800
855
|
outcome.response,
|
|
@@ -807,22 +862,12 @@ function proxyChain(optionsOrEntries, maybeEntries) {
|
|
|
807
862
|
);
|
|
808
863
|
}
|
|
809
864
|
const finalReq = materializeRequest();
|
|
810
|
-
const internalHostFolder = appliedRequestOverrides.get(
|
|
865
|
+
const internalHostFolder = hostFolderHeader ? appliedRequestOverrides.get(hostFolderHeader) : null;
|
|
811
866
|
let finalRewriteUrl = pendingRewriteUrl;
|
|
812
867
|
if (internalHostFolder) {
|
|
813
|
-
const cleanFolder =
|
|
868
|
+
const cleanFolder = physicalFolderPrefix(internalHostFolder);
|
|
814
869
|
if (finalRewriteUrl) {
|
|
815
|
-
|
|
816
|
-
const parsed = new URL(finalRewriteUrl, finalReq.url);
|
|
817
|
-
if (!parsed.pathname.startsWith(cleanFolder)) {
|
|
818
|
-
parsed.pathname = cleanFolder + (parsed.pathname === "/" ? "" : parsed.pathname);
|
|
819
|
-
finalRewriteUrl = parsed.toString();
|
|
820
|
-
}
|
|
821
|
-
} catch {
|
|
822
|
-
if (!finalRewriteUrl.startsWith(cleanFolder)) {
|
|
823
|
-
finalRewriteUrl = cleanFolder + (finalRewriteUrl === "/" ? "" : finalRewriteUrl);
|
|
824
|
-
}
|
|
825
|
-
}
|
|
870
|
+
finalRewriteUrl = applyFolderPrefix(finalRewriteUrl, cleanFolder, finalReq.url);
|
|
826
871
|
} else {
|
|
827
872
|
const currentPath = finalReq.nextUrl.pathname;
|
|
828
873
|
if (!currentPath.startsWith(cleanFolder)) {
|
|
@@ -863,42 +908,12 @@ function proxyChain(optionsOrEntries, maybeEntries) {
|
|
|
863
908
|
}
|
|
864
909
|
// Annotate the CommonJS export names for ESM import in node:
|
|
865
910
|
0 && (module.exports = {
|
|
866
|
-
DEFAULT_BLOCKED_REQUEST_HEADERS,
|
|
867
|
-
NEXT,
|
|
868
911
|
RuleTimeoutError,
|
|
869
|
-
applyMergedToResponse,
|
|
870
|
-
assertIncludeExcludeNoOverlap,
|
|
871
|
-
assertOverrideMechanismSupported,
|
|
872
|
-
compileScopes,
|
|
873
|
-
cookieItemsFromHeaders,
|
|
874
|
-
createConsoleLogger,
|
|
875
912
|
createProxyContext,
|
|
876
|
-
decodeOverriddenRequestHeaders,
|
|
877
913
|
defineProxy,
|
|
878
|
-
finalizeResponse,
|
|
879
|
-
formatPipelineLine,
|
|
880
|
-
headersDiffer,
|
|
881
|
-
headersInitToHeaders,
|
|
882
914
|
host,
|
|
883
915
|
isNextResult,
|
|
884
|
-
isRequestHeaderAllowed,
|
|
885
|
-
listSetCookie,
|
|
886
|
-
mergeRequestHeaderOverrides,
|
|
887
|
-
mergeWrites,
|
|
888
916
|
next,
|
|
889
|
-
normalizeHost,
|
|
890
|
-
parseCookieName,
|
|
891
917
|
path,
|
|
892
|
-
|
|
893
|
-
proxyChain,
|
|
894
|
-
resolveRuleResult,
|
|
895
|
-
responseHeaderItems,
|
|
896
|
-
ruleLabel,
|
|
897
|
-
ruleMatches,
|
|
898
|
-
safeInternalError,
|
|
899
|
-
toPathRegex,
|
|
900
|
-
toRule,
|
|
901
|
-
toStatelessRegExp,
|
|
902
|
-
withPaths,
|
|
903
|
-
withRuleTimeout
|
|
918
|
+
proxyChain
|
|
904
919
|
});
|