@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/dist/index.d.cts CHANGED
@@ -4,10 +4,6 @@ import { NextRequest, NextFetchEvent, NextResponse } from 'next/server';
4
4
  * Unique symbol identifying an explicit continue action in the proxy chain pipeline.
5
5
  */
6
6
  declare const NEXT: unique symbol;
7
- /**
8
- * Protected request headers that cannot be rewritten unless explicitly permitted by policy.
9
- */
10
- declare const DEFAULT_BLOCKED_REQUEST_HEADERS: readonly string[];
11
7
 
12
8
  /**
13
9
  * Configuration options for chain continuation.
@@ -15,7 +11,7 @@ declare const DEFAULT_BLOCKED_REQUEST_HEADERS: readonly string[];
15
11
  type NextOptions = {
16
12
  /** Request header overrides visible to downstream rules and handlers. */
17
13
  request?: HeadersInit;
18
- /** Response headers merged into the final outgoing response. */
14
+ /** Response headers merged into the final outgoing response. `set-cookie` is extracted as cookies. */
19
15
  headers?: HeadersInit;
20
16
  };
21
17
  /**
@@ -29,12 +25,7 @@ type NextResult = NextOptions & {
29
25
  * Backed by Map to eliminate prototype-pollution risks.
30
26
  */
31
27
  type ProxyContext = Map<string, unknown>;
32
- type ProxyResult<TResponse = NextResponse | Response> = TResponse | NextResult | undefined | void;
33
28
  type PathMatcher = RegExp | string;
34
- type PathOptions = {
35
- /** Optional locale prefixes for path matching. */
36
- locales?: readonly string[];
37
- };
38
29
  type HostMatcher = string | RegExp | readonly (string | RegExp)[];
39
30
  /**
40
31
  * Scoping configuration for rule inclusion or exclusion.
@@ -62,7 +53,6 @@ type ProxyPathFilter = {
62
53
  include?: RouteScopeList;
63
54
  exclude?: RouteScopeList;
64
55
  name?: string;
65
- pathOptions?: PathOptions;
66
56
  };
67
57
  /**
68
58
  * A single proxy execution function.
@@ -72,39 +62,40 @@ type ProxyRule<TContext = ProxyContext> = BaseProxyRule<ProxyFn<TContext>>;
72
62
  type DefinedProxy<TContext = ProxyContext> = ProxyFn<TContext> & ((filter: ProxyPathFilter) => ProxyRule<TContext>);
73
63
  type Entry<TContext = ProxyContext> = ProxyFn<TContext> | ProxyRule<TContext>;
74
64
  type MergeStrategy = "last-write-wins" | "first-write-wins" | ((key: string, existing: string, incoming: string) => string | null);
75
- interface EntryWrite {
76
- ruleIndex: number;
77
- ruleName: string;
78
- items: Map<string, string>;
79
- }
80
- type LogLevel = "debug" | "info" | "warn" | "error";
81
65
  interface ChainLogger {
82
66
  debug: (metaOrMsg: unknown, maybeMsg?: string) => void;
83
67
  info: (metaOrMsg: unknown, maybeMsg?: string) => void;
84
68
  warn: (metaOrMsg: unknown, maybeMsg?: string) => void;
85
69
  error: (metaOrMsg: unknown, maybeMsg?: string) => void;
86
70
  }
87
- type PipelineOutcome = {
88
- kind: "passed";
89
- duration: number;
90
- } | {
91
- kind: "next";
92
- duration: number;
93
- headers: number;
94
- } | {
95
- kind: "stop";
96
- duration: number;
97
- status: number;
98
- };
99
71
  interface RequestHeaderPolicy {
100
72
  blocked?: readonly string[];
101
73
  allowed?: readonly string[];
102
74
  }
75
+ /**
76
+ * Value returned from `onError`.
77
+ *
78
+ * - `Response` — stop the pipeline and return it
79
+ * - `NextResult` (`next()`) — continue to the next rule (rule-level errors only)
80
+ * - `undefined` / `void` / `null` — fail closed (`500`)
81
+ */
82
+ type OnErrorResult = NextResponse | Response | NextResult | undefined | void | null;
83
+ type OnErrorHandler<TContext = ProxyContext> = (err: unknown,
84
+ /**
85
+ * 0-based index of the rule that threw.
86
+ * `-1` means the error originated in the pipeline engine after context creation.
87
+ * Engine-level errors cannot continue; only a `Response` is honored.
88
+ */
89
+ ruleIndex: number, req: NextRequest, ctx: TContext) => OnErrorResult | Promise<OnErrorResult>;
103
90
  interface ChainConfig<TContext = ProxyContext> {
104
91
  createContext: (req: NextRequest, event: NextFetchEvent) => TContext;
105
92
  cookieMergeStrategy: MergeStrategy;
93
+ /**
94
+ * How conflicting **response** headers from different rules are resolved.
95
+ * Request header overrides always use last-write-wins and ignore this option.
96
+ */
106
97
  headerMergeStrategy: MergeStrategy;
107
- onError?: (err: unknown, ruleIndex: number, req: NextRequest, ctx: TContext) => NextResponse | Response | undefined | void | Promise<NextResponse | Response | undefined | void>;
98
+ onError?: OnErrorHandler<TContext>;
108
99
  debug: boolean;
109
100
  logger: ChainLogger;
110
101
  /** Maximum wall-clock execution time per rule in milliseconds. 0 disables timeout. */
@@ -112,101 +103,41 @@ interface ChainConfig<TContext = ProxyContext> {
112
103
  requestHeaderPolicy: RequestHeaderPolicy;
113
104
  /** Throw an error on startup if the runtime platform does not support request header overrides. */
114
105
  strictOverrideCheck?: boolean;
106
+ /**
107
+ * Request header name that prefixes rewrites with a physical host folder
108
+ * (multi-tenant `app/(sites)/shop` layouts). Unset = disabled.
109
+ */
110
+ hostFolderHeader?: string;
115
111
  }
116
112
  type ProxyChainOptions<TContext = ProxyContext> = Partial<ChainConfig<TContext>>;
117
113
 
118
114
  /**
119
- * Creates an isolated per-request context instance.
120
- * Backed by Map to eliminate prototype pollution risks.
121
- */
122
- declare function createProxyContext(): ProxyContext;
123
-
124
- /**
125
- * Strips sticky and global flags (g, y) from RegExp instances.
126
- * On Edge runtimes, compiled regex instances can be shared across requests;
127
- * sticky and global flags mutate stateful indices, causing non-deterministic matching.
128
- */
129
- declare function toStatelessRegExp(re: RegExp): RegExp;
130
- /**
131
- * Builds a compiled Host matcher RegExp from domain names, wildcards, or regex patterns.
132
- */
133
- declare function host(matcher: HostMatcher): RegExp;
134
- /**
135
- * Compiles a path pattern (glob string, param pattern, or RegExp) into a stateless regular expression.
136
- */
137
- declare function path(pattern: string | RegExp, options?: PathOptions): RegExp;
138
- declare function toPathRegex(matcher: PathMatcher | PathMatcher[], options?: PathOptions): RegExp;
139
- /**
140
- * Compiles route scoping declarations into normalized regex clauses.
141
- */
142
- declare function compileScopes(input: RouteScopeList | undefined, pathOptions?: PathOptions): CompiledScope[] | undefined;
143
- declare function toRule<TFn>(entry: TFn | BaseProxyRule<TFn>): BaseProxyRule<TFn>;
144
- declare function ruleLabel<TFn>(rule: BaseProxyRule<TFn>, index: number): string;
145
- /**
146
- * Decorates a proxy entry with declarative path and host inclusion/exclusion filters.
147
- */
148
- declare function withPaths<TFn>(entry: TFn | BaseProxyRule<TFn>, filter: ProxyPathFilter): BaseProxyRule<TFn>;
149
- /**
150
- * Determines whether a given request matches a rule's scoping constraints.
151
- */
152
- declare function ruleMatches<TFn>(pathname: string, hostname: string | null, rule: BaseProxyRule<TFn>): boolean;
153
- declare function pathMatches<TFn>(pathname: string, rule: BaseProxyRule<TFn>): boolean;
154
- /**
155
- * Normalizes Host or X-Forwarded-Host header values to lower-case hostname without port.
156
- */
157
- declare function normalizeHost(raw: string | null | undefined): string | null;
158
- /**
159
- * Validates that an identical scope is not declared simultaneously in include and exclude.
160
- */
161
- declare function assertIncludeExcludeNoOverlap(include: CompiledScope[] | undefined, exclude: CompiledScope[] | undefined, label: string): void;
162
-
163
- /**
164
- * Converts HeadersInit or undefined to a standard Web Headers instance.
165
- */
166
- declare function headersInitToHeaders(init?: HeadersInit): Headers;
167
- /**
168
- * Compares two Headers instances to determine if overrides contain differences.
169
- */
170
- declare function headersDiffer(base: Headers, overrides: Headers): boolean;
171
- /**
172
- * Checks whether a request header is permitted to be mutated under the configured policy.
173
- */
174
- declare function isRequestHeaderAllowed(name: string, policy?: RequestHeaderPolicy): boolean;
175
- /**
176
- * Merges new request header overrides into the target Headers instance, filtering prohibited headers.
177
- */
178
- declare function mergeRequestHeaderOverrides(target: Headers, overrides: Headers, policy?: RequestHeaderPolicy): {
179
- applied: number;
180
- dropped: string[];
181
- };
182
- /**
183
- * Extracts cookie name from a raw Set-Cookie directive.
184
- */
185
- declare function parseCookieName(setCookie: string): string;
186
- /**
187
- * Extracts all Set-Cookie directives using standard getSetCookie() when available.
188
- */
189
- declare function listSetCookie(headers: Headers): string[];
190
- /**
191
- * Maps cookie name to Set-Cookie header value from a Headers instance.
192
- */
193
- declare function cookieItemsFromHeaders(headers: Headers): Map<string, string>;
194
- /**
195
- * Filters out Set-Cookie and internal transport headers (x-middleware-*) from response headers.
196
- */
197
- declare function responseHeaderItems(headers: Headers): Map<string, string>;
198
- /**
199
- * Decodes Next.js request header overrides encoded into response headers.
200
- */
201
- declare function decodeOverriddenRequestHeaders(headers: Headers): Headers;
202
- /**
203
- * Deterministically merges writes across rules based on configured strategy.
115
+ * Creates a reusable, scope-aware proxy rule function.
116
+ *
117
+ * @example
118
+ * const authRule = defineProxy("auth", async (req, ctx) => next())
119
+ * const scopedAuthRule = authRule({ include: path("/admin/*") })
204
120
  */
205
- declare function mergeWrites(writes: EntryWrite[], strategy: MergeStrategy, onConflict?: (key: string, winner: string, loser: string) => void): Map<string, string>;
121
+ declare function defineProxy<TContext = ProxyContext>(run: ProxyFn<TContext>): DefinedProxy<TContext>;
122
+ declare function defineProxy<TContext = ProxyContext>(name: string, run: ProxyFn<TContext>): DefinedProxy<TContext>;
123
+ type ProxyHandler = (req: NextRequest, event: NextFetchEvent) => Promise<NextResponse | Response>;
206
124
  /**
207
- * Applies merged headers and deduplicated cookies onto an outgoing response.
125
+ * Composes independent proxy rules into a single pipeline for Next.js 15 (middleware.ts) and Next.js 16 (proxy.ts).
126
+ *
127
+ * Custom `TContext` requires `createContext`. Without it, context is `ProxyContext` (`Map`).
128
+ *
129
+ * @example
130
+ * export default proxyChain({ debug: true }, [
131
+ * requestIdRule,
132
+ * authRule({ include: path("/dashboard/*") }),
133
+ * i18nRule,
134
+ * ])
208
135
  */
209
- declare function applyMergedToResponse(res: Response, headers: Map<string, string>, cookies: Map<string, string>): void;
136
+ declare function proxyChain(entries: Entry<ProxyContext>[]): ProxyHandler;
137
+ declare function proxyChain(options: ProxyChainOptions<ProxyContext>, entries: Entry<ProxyContext>[]): ProxyHandler;
138
+ declare function proxyChain<TContext>(options: ProxyChainOptions<TContext> & {
139
+ createContext: (req: NextRequest, event: NextFetchEvent) => TContext;
140
+ }, entries: Entry<TContext>[]): ProxyHandler;
210
141
 
211
142
  /**
212
143
  * Creates a continuation action instructing the proxy chain to proceed to subsequent rules.
@@ -223,63 +154,28 @@ declare function next(options?: NextOptions): NextResult;
223
154
  */
224
155
  declare function isNextResult(value: unknown): value is NextResult;
225
156
 
226
- declare function createConsoleLogger(minLevel?: LogLevel): ChainLogger;
227
157
  /**
228
- * Formats a single structured log line for an executed proxy rule.
158
+ * Builds a compiled Host matcher RegExp from domain names, `*.example.com` wildcards, or regex patterns.
159
+ */
160
+ declare function host(matcher: HostMatcher): RegExp;
161
+ /**
162
+ * Compiles a path pattern (glob string, param pattern, or RegExp) into a stateless regular expression.
163
+ *
164
+ * - `*` — exactly one path segment
165
+ * - `**` — zero or more subsequent segments
166
+ */
167
+ declare function path(pattern: string | RegExp): RegExp;
168
+
169
+ /**
170
+ * Creates an isolated per-request context instance.
171
+ * Backed by Map to eliminate prototype pollution risks.
229
172
  */
230
- declare function formatPipelineLine(input: {
231
- method: string;
232
- path: string;
233
- name: string;
234
- traceId?: string;
235
- outcome: PipelineOutcome;
236
- }): string;
173
+ declare function createProxyContext(): ProxyContext;
237
174
 
238
175
  declare class RuleTimeoutError extends Error {
239
176
  readonly ruleName: string;
240
177
  readonly timeoutMs: number;
241
178
  constructor(ruleName: string, timeoutMs: number);
242
179
  }
243
- /**
244
- * Enforces a strict execution time budget on an asynchronous rule operation.
245
- */
246
- declare function withRuleTimeout<T>(promise: Promise<T>, timeoutMs: number | undefined, ruleName: string): Promise<T>;
247
-
248
- declare function safeInternalError(): NextResponse;
249
- declare function assertOverrideMechanismSupported(strict?: boolean): boolean;
250
- type ResolvedOutcome = {
251
- kind: "continue";
252
- request?: Headers;
253
- responseHeaders: Map<string, string>;
254
- cookies: Map<string, string>;
255
- rewriteUrl?: string;
256
- } | {
257
- kind: "stop";
258
- response: NextResponse | Response;
259
- };
260
- declare function resolveRuleResult(res: NextResponse | Response | NextResult | undefined | void, requestHeaderPolicy: RequestHeaderPolicy, logger: ChainLogger, debug: boolean): ResolvedOutcome;
261
- declare function finalizeResponse(res: NextResponse | Response, headerWrites: EntryWrite[], cookieWrites: EntryWrite[], headerStrategy: MergeStrategy, cookieStrategy: MergeStrategy, logger: ChainLogger, debug: boolean): NextResponse | Response;
262
-
263
- /**
264
- * Creates a reusable, scope-aware proxy rule function.
265
- *
266
- * @example
267
- * const authRule = defineProxy("auth", async (req, ctx) => next())
268
- * const scopedAuthRule = authRule({ include: path("/admin/*") })
269
- */
270
- declare function defineProxy<TContext = ProxyContext>(run: ProxyFn<TContext>): DefinedProxy<TContext>;
271
- declare function defineProxy<TContext = ProxyContext>(name: string, run: ProxyFn<TContext>): DefinedProxy<TContext>;
272
- /**
273
- * Composes independent proxy rules into a single pipeline for Next.js 15 (middleware.ts) and Next.js 16 (proxy.ts).
274
- *
275
- * @example
276
- * export default proxyChain({ debug: true }, [
277
- * requestIdRule,
278
- * authRule({ include: path("/dashboard/*") }),
279
- * i18nRule,
280
- * ])
281
- */
282
- declare function proxyChain<TContext = ProxyContext>(entries: Entry<TContext>[]): (req: NextRequest, event: NextFetchEvent) => Promise<NextResponse | Response>;
283
- declare function proxyChain<TContext = ProxyContext>(options: ProxyChainOptions<TContext>, entries: Entry<TContext>[]): (req: NextRequest, event: NextFetchEvent) => Promise<NextResponse | Response>;
284
180
 
285
- export { type BaseProxyRule, type ChainConfig, type ChainLogger, type CompiledScope, DEFAULT_BLOCKED_REQUEST_HEADERS, type DefinedProxy, type Entry, type EntryWrite, type HostMatcher, type LogLevel, type MergeStrategy, NEXT, type NextOptions, type NextResult, type PathMatcher, type PathOptions, type PipelineOutcome, type ProxyChainOptions, type ProxyContext, type ProxyFn, type ProxyPathFilter, type ProxyResult, type ProxyRule, type RequestHeaderPolicy, type ResolvedOutcome, type RouteScopeInput, type RouteScopeList, RuleTimeoutError, applyMergedToResponse, assertIncludeExcludeNoOverlap, assertOverrideMechanismSupported, compileScopes, cookieItemsFromHeaders, createConsoleLogger, createProxyContext, decodeOverriddenRequestHeaders, defineProxy, finalizeResponse, formatPipelineLine, headersDiffer, headersInitToHeaders, host, isNextResult, isRequestHeaderAllowed, listSetCookie, mergeRequestHeaderOverrides, mergeWrites, next, normalizeHost, parseCookieName, path, pathMatches, proxyChain, resolveRuleResult, responseHeaderItems, ruleLabel, ruleMatches, safeInternalError, toPathRegex, toRule, toStatelessRegExp, withPaths, withRuleTimeout };
181
+ export { type ChainLogger, type DefinedProxy, type Entry, type HostMatcher, type MergeStrategy, type NextOptions, type NextResult, type OnErrorHandler, type OnErrorResult, type PathMatcher, type ProxyChainOptions, type ProxyContext, type ProxyFn, type ProxyPathFilter, type ProxyRule, type RequestHeaderPolicy, RuleTimeoutError, createProxyContext, defineProxy, host, isNextResult, next, path, proxyChain };
package/dist/index.d.ts CHANGED
@@ -4,10 +4,6 @@ import { NextRequest, NextFetchEvent, NextResponse } from 'next/server';
4
4
  * Unique symbol identifying an explicit continue action in the proxy chain pipeline.
5
5
  */
6
6
  declare const NEXT: unique symbol;
7
- /**
8
- * Protected request headers that cannot be rewritten unless explicitly permitted by policy.
9
- */
10
- declare const DEFAULT_BLOCKED_REQUEST_HEADERS: readonly string[];
11
7
 
12
8
  /**
13
9
  * Configuration options for chain continuation.
@@ -15,7 +11,7 @@ declare const DEFAULT_BLOCKED_REQUEST_HEADERS: readonly string[];
15
11
  type NextOptions = {
16
12
  /** Request header overrides visible to downstream rules and handlers. */
17
13
  request?: HeadersInit;
18
- /** Response headers merged into the final outgoing response. */
14
+ /** Response headers merged into the final outgoing response. `set-cookie` is extracted as cookies. */
19
15
  headers?: HeadersInit;
20
16
  };
21
17
  /**
@@ -29,12 +25,7 @@ type NextResult = NextOptions & {
29
25
  * Backed by Map to eliminate prototype-pollution risks.
30
26
  */
31
27
  type ProxyContext = Map<string, unknown>;
32
- type ProxyResult<TResponse = NextResponse | Response> = TResponse | NextResult | undefined | void;
33
28
  type PathMatcher = RegExp | string;
34
- type PathOptions = {
35
- /** Optional locale prefixes for path matching. */
36
- locales?: readonly string[];
37
- };
38
29
  type HostMatcher = string | RegExp | readonly (string | RegExp)[];
39
30
  /**
40
31
  * Scoping configuration for rule inclusion or exclusion.
@@ -62,7 +53,6 @@ type ProxyPathFilter = {
62
53
  include?: RouteScopeList;
63
54
  exclude?: RouteScopeList;
64
55
  name?: string;
65
- pathOptions?: PathOptions;
66
56
  };
67
57
  /**
68
58
  * A single proxy execution function.
@@ -72,39 +62,40 @@ type ProxyRule<TContext = ProxyContext> = BaseProxyRule<ProxyFn<TContext>>;
72
62
  type DefinedProxy<TContext = ProxyContext> = ProxyFn<TContext> & ((filter: ProxyPathFilter) => ProxyRule<TContext>);
73
63
  type Entry<TContext = ProxyContext> = ProxyFn<TContext> | ProxyRule<TContext>;
74
64
  type MergeStrategy = "last-write-wins" | "first-write-wins" | ((key: string, existing: string, incoming: string) => string | null);
75
- interface EntryWrite {
76
- ruleIndex: number;
77
- ruleName: string;
78
- items: Map<string, string>;
79
- }
80
- type LogLevel = "debug" | "info" | "warn" | "error";
81
65
  interface ChainLogger {
82
66
  debug: (metaOrMsg: unknown, maybeMsg?: string) => void;
83
67
  info: (metaOrMsg: unknown, maybeMsg?: string) => void;
84
68
  warn: (metaOrMsg: unknown, maybeMsg?: string) => void;
85
69
  error: (metaOrMsg: unknown, maybeMsg?: string) => void;
86
70
  }
87
- type PipelineOutcome = {
88
- kind: "passed";
89
- duration: number;
90
- } | {
91
- kind: "next";
92
- duration: number;
93
- headers: number;
94
- } | {
95
- kind: "stop";
96
- duration: number;
97
- status: number;
98
- };
99
71
  interface RequestHeaderPolicy {
100
72
  blocked?: readonly string[];
101
73
  allowed?: readonly string[];
102
74
  }
75
+ /**
76
+ * Value returned from `onError`.
77
+ *
78
+ * - `Response` — stop the pipeline and return it
79
+ * - `NextResult` (`next()`) — continue to the next rule (rule-level errors only)
80
+ * - `undefined` / `void` / `null` — fail closed (`500`)
81
+ */
82
+ type OnErrorResult = NextResponse | Response | NextResult | undefined | void | null;
83
+ type OnErrorHandler<TContext = ProxyContext> = (err: unknown,
84
+ /**
85
+ * 0-based index of the rule that threw.
86
+ * `-1` means the error originated in the pipeline engine after context creation.
87
+ * Engine-level errors cannot continue; only a `Response` is honored.
88
+ */
89
+ ruleIndex: number, req: NextRequest, ctx: TContext) => OnErrorResult | Promise<OnErrorResult>;
103
90
  interface ChainConfig<TContext = ProxyContext> {
104
91
  createContext: (req: NextRequest, event: NextFetchEvent) => TContext;
105
92
  cookieMergeStrategy: MergeStrategy;
93
+ /**
94
+ * How conflicting **response** headers from different rules are resolved.
95
+ * Request header overrides always use last-write-wins and ignore this option.
96
+ */
106
97
  headerMergeStrategy: MergeStrategy;
107
- onError?: (err: unknown, ruleIndex: number, req: NextRequest, ctx: TContext) => NextResponse | Response | undefined | void | Promise<NextResponse | Response | undefined | void>;
98
+ onError?: OnErrorHandler<TContext>;
108
99
  debug: boolean;
109
100
  logger: ChainLogger;
110
101
  /** Maximum wall-clock execution time per rule in milliseconds. 0 disables timeout. */
@@ -112,101 +103,41 @@ interface ChainConfig<TContext = ProxyContext> {
112
103
  requestHeaderPolicy: RequestHeaderPolicy;
113
104
  /** Throw an error on startup if the runtime platform does not support request header overrides. */
114
105
  strictOverrideCheck?: boolean;
106
+ /**
107
+ * Request header name that prefixes rewrites with a physical host folder
108
+ * (multi-tenant `app/(sites)/shop` layouts). Unset = disabled.
109
+ */
110
+ hostFolderHeader?: string;
115
111
  }
116
112
  type ProxyChainOptions<TContext = ProxyContext> = Partial<ChainConfig<TContext>>;
117
113
 
118
114
  /**
119
- * Creates an isolated per-request context instance.
120
- * Backed by Map to eliminate prototype pollution risks.
121
- */
122
- declare function createProxyContext(): ProxyContext;
123
-
124
- /**
125
- * Strips sticky and global flags (g, y) from RegExp instances.
126
- * On Edge runtimes, compiled regex instances can be shared across requests;
127
- * sticky and global flags mutate stateful indices, causing non-deterministic matching.
128
- */
129
- declare function toStatelessRegExp(re: RegExp): RegExp;
130
- /**
131
- * Builds a compiled Host matcher RegExp from domain names, wildcards, or regex patterns.
132
- */
133
- declare function host(matcher: HostMatcher): RegExp;
134
- /**
135
- * Compiles a path pattern (glob string, param pattern, or RegExp) into a stateless regular expression.
136
- */
137
- declare function path(pattern: string | RegExp, options?: PathOptions): RegExp;
138
- declare function toPathRegex(matcher: PathMatcher | PathMatcher[], options?: PathOptions): RegExp;
139
- /**
140
- * Compiles route scoping declarations into normalized regex clauses.
141
- */
142
- declare function compileScopes(input: RouteScopeList | undefined, pathOptions?: PathOptions): CompiledScope[] | undefined;
143
- declare function toRule<TFn>(entry: TFn | BaseProxyRule<TFn>): BaseProxyRule<TFn>;
144
- declare function ruleLabel<TFn>(rule: BaseProxyRule<TFn>, index: number): string;
145
- /**
146
- * Decorates a proxy entry with declarative path and host inclusion/exclusion filters.
147
- */
148
- declare function withPaths<TFn>(entry: TFn | BaseProxyRule<TFn>, filter: ProxyPathFilter): BaseProxyRule<TFn>;
149
- /**
150
- * Determines whether a given request matches a rule's scoping constraints.
151
- */
152
- declare function ruleMatches<TFn>(pathname: string, hostname: string | null, rule: BaseProxyRule<TFn>): boolean;
153
- declare function pathMatches<TFn>(pathname: string, rule: BaseProxyRule<TFn>): boolean;
154
- /**
155
- * Normalizes Host or X-Forwarded-Host header values to lower-case hostname without port.
156
- */
157
- declare function normalizeHost(raw: string | null | undefined): string | null;
158
- /**
159
- * Validates that an identical scope is not declared simultaneously in include and exclude.
160
- */
161
- declare function assertIncludeExcludeNoOverlap(include: CompiledScope[] | undefined, exclude: CompiledScope[] | undefined, label: string): void;
162
-
163
- /**
164
- * Converts HeadersInit or undefined to a standard Web Headers instance.
165
- */
166
- declare function headersInitToHeaders(init?: HeadersInit): Headers;
167
- /**
168
- * Compares two Headers instances to determine if overrides contain differences.
169
- */
170
- declare function headersDiffer(base: Headers, overrides: Headers): boolean;
171
- /**
172
- * Checks whether a request header is permitted to be mutated under the configured policy.
173
- */
174
- declare function isRequestHeaderAllowed(name: string, policy?: RequestHeaderPolicy): boolean;
175
- /**
176
- * Merges new request header overrides into the target Headers instance, filtering prohibited headers.
177
- */
178
- declare function mergeRequestHeaderOverrides(target: Headers, overrides: Headers, policy?: RequestHeaderPolicy): {
179
- applied: number;
180
- dropped: string[];
181
- };
182
- /**
183
- * Extracts cookie name from a raw Set-Cookie directive.
184
- */
185
- declare function parseCookieName(setCookie: string): string;
186
- /**
187
- * Extracts all Set-Cookie directives using standard getSetCookie() when available.
188
- */
189
- declare function listSetCookie(headers: Headers): string[];
190
- /**
191
- * Maps cookie name to Set-Cookie header value from a Headers instance.
192
- */
193
- declare function cookieItemsFromHeaders(headers: Headers): Map<string, string>;
194
- /**
195
- * Filters out Set-Cookie and internal transport headers (x-middleware-*) from response headers.
196
- */
197
- declare function responseHeaderItems(headers: Headers): Map<string, string>;
198
- /**
199
- * Decodes Next.js request header overrides encoded into response headers.
200
- */
201
- declare function decodeOverriddenRequestHeaders(headers: Headers): Headers;
202
- /**
203
- * Deterministically merges writes across rules based on configured strategy.
115
+ * Creates a reusable, scope-aware proxy rule function.
116
+ *
117
+ * @example
118
+ * const authRule = defineProxy("auth", async (req, ctx) => next())
119
+ * const scopedAuthRule = authRule({ include: path("/admin/*") })
204
120
  */
205
- declare function mergeWrites(writes: EntryWrite[], strategy: MergeStrategy, onConflict?: (key: string, winner: string, loser: string) => void): Map<string, string>;
121
+ declare function defineProxy<TContext = ProxyContext>(run: ProxyFn<TContext>): DefinedProxy<TContext>;
122
+ declare function defineProxy<TContext = ProxyContext>(name: string, run: ProxyFn<TContext>): DefinedProxy<TContext>;
123
+ type ProxyHandler = (req: NextRequest, event: NextFetchEvent) => Promise<NextResponse | Response>;
206
124
  /**
207
- * Applies merged headers and deduplicated cookies onto an outgoing response.
125
+ * Composes independent proxy rules into a single pipeline for Next.js 15 (middleware.ts) and Next.js 16 (proxy.ts).
126
+ *
127
+ * Custom `TContext` requires `createContext`. Without it, context is `ProxyContext` (`Map`).
128
+ *
129
+ * @example
130
+ * export default proxyChain({ debug: true }, [
131
+ * requestIdRule,
132
+ * authRule({ include: path("/dashboard/*") }),
133
+ * i18nRule,
134
+ * ])
208
135
  */
209
- declare function applyMergedToResponse(res: Response, headers: Map<string, string>, cookies: Map<string, string>): void;
136
+ declare function proxyChain(entries: Entry<ProxyContext>[]): ProxyHandler;
137
+ declare function proxyChain(options: ProxyChainOptions<ProxyContext>, entries: Entry<ProxyContext>[]): ProxyHandler;
138
+ declare function proxyChain<TContext>(options: ProxyChainOptions<TContext> & {
139
+ createContext: (req: NextRequest, event: NextFetchEvent) => TContext;
140
+ }, entries: Entry<TContext>[]): ProxyHandler;
210
141
 
211
142
  /**
212
143
  * Creates a continuation action instructing the proxy chain to proceed to subsequent rules.
@@ -223,63 +154,28 @@ declare function next(options?: NextOptions): NextResult;
223
154
  */
224
155
  declare function isNextResult(value: unknown): value is NextResult;
225
156
 
226
- declare function createConsoleLogger(minLevel?: LogLevel): ChainLogger;
227
157
  /**
228
- * Formats a single structured log line for an executed proxy rule.
158
+ * Builds a compiled Host matcher RegExp from domain names, `*.example.com` wildcards, or regex patterns.
159
+ */
160
+ declare function host(matcher: HostMatcher): RegExp;
161
+ /**
162
+ * Compiles a path pattern (glob string, param pattern, or RegExp) into a stateless regular expression.
163
+ *
164
+ * - `*` — exactly one path segment
165
+ * - `**` — zero or more subsequent segments
166
+ */
167
+ declare function path(pattern: string | RegExp): RegExp;
168
+
169
+ /**
170
+ * Creates an isolated per-request context instance.
171
+ * Backed by Map to eliminate prototype pollution risks.
229
172
  */
230
- declare function formatPipelineLine(input: {
231
- method: string;
232
- path: string;
233
- name: string;
234
- traceId?: string;
235
- outcome: PipelineOutcome;
236
- }): string;
173
+ declare function createProxyContext(): ProxyContext;
237
174
 
238
175
  declare class RuleTimeoutError extends Error {
239
176
  readonly ruleName: string;
240
177
  readonly timeoutMs: number;
241
178
  constructor(ruleName: string, timeoutMs: number);
242
179
  }
243
- /**
244
- * Enforces a strict execution time budget on an asynchronous rule operation.
245
- */
246
- declare function withRuleTimeout<T>(promise: Promise<T>, timeoutMs: number | undefined, ruleName: string): Promise<T>;
247
-
248
- declare function safeInternalError(): NextResponse;
249
- declare function assertOverrideMechanismSupported(strict?: boolean): boolean;
250
- type ResolvedOutcome = {
251
- kind: "continue";
252
- request?: Headers;
253
- responseHeaders: Map<string, string>;
254
- cookies: Map<string, string>;
255
- rewriteUrl?: string;
256
- } | {
257
- kind: "stop";
258
- response: NextResponse | Response;
259
- };
260
- declare function resolveRuleResult(res: NextResponse | Response | NextResult | undefined | void, requestHeaderPolicy: RequestHeaderPolicy, logger: ChainLogger, debug: boolean): ResolvedOutcome;
261
- declare function finalizeResponse(res: NextResponse | Response, headerWrites: EntryWrite[], cookieWrites: EntryWrite[], headerStrategy: MergeStrategy, cookieStrategy: MergeStrategy, logger: ChainLogger, debug: boolean): NextResponse | Response;
262
-
263
- /**
264
- * Creates a reusable, scope-aware proxy rule function.
265
- *
266
- * @example
267
- * const authRule = defineProxy("auth", async (req, ctx) => next())
268
- * const scopedAuthRule = authRule({ include: path("/admin/*") })
269
- */
270
- declare function defineProxy<TContext = ProxyContext>(run: ProxyFn<TContext>): DefinedProxy<TContext>;
271
- declare function defineProxy<TContext = ProxyContext>(name: string, run: ProxyFn<TContext>): DefinedProxy<TContext>;
272
- /**
273
- * Composes independent proxy rules into a single pipeline for Next.js 15 (middleware.ts) and Next.js 16 (proxy.ts).
274
- *
275
- * @example
276
- * export default proxyChain({ debug: true }, [
277
- * requestIdRule,
278
- * authRule({ include: path("/dashboard/*") }),
279
- * i18nRule,
280
- * ])
281
- */
282
- declare function proxyChain<TContext = ProxyContext>(entries: Entry<TContext>[]): (req: NextRequest, event: NextFetchEvent) => Promise<NextResponse | Response>;
283
- declare function proxyChain<TContext = ProxyContext>(options: ProxyChainOptions<TContext>, entries: Entry<TContext>[]): (req: NextRequest, event: NextFetchEvent) => Promise<NextResponse | Response>;
284
180
 
285
- export { type BaseProxyRule, type ChainConfig, type ChainLogger, type CompiledScope, DEFAULT_BLOCKED_REQUEST_HEADERS, type DefinedProxy, type Entry, type EntryWrite, type HostMatcher, type LogLevel, type MergeStrategy, NEXT, type NextOptions, type NextResult, type PathMatcher, type PathOptions, type PipelineOutcome, type ProxyChainOptions, type ProxyContext, type ProxyFn, type ProxyPathFilter, type ProxyResult, type ProxyRule, type RequestHeaderPolicy, type ResolvedOutcome, type RouteScopeInput, type RouteScopeList, RuleTimeoutError, applyMergedToResponse, assertIncludeExcludeNoOverlap, assertOverrideMechanismSupported, compileScopes, cookieItemsFromHeaders, createConsoleLogger, createProxyContext, decodeOverriddenRequestHeaders, defineProxy, finalizeResponse, formatPipelineLine, headersDiffer, headersInitToHeaders, host, isNextResult, isRequestHeaderAllowed, listSetCookie, mergeRequestHeaderOverrides, mergeWrites, next, normalizeHost, parseCookieName, path, pathMatches, proxyChain, resolveRuleResult, responseHeaderItems, ruleLabel, ruleMatches, safeInternalError, toPathRegex, toRule, toStatelessRegExp, withPaths, withRuleTimeout };
181
+ export { type ChainLogger, type DefinedProxy, type Entry, type HostMatcher, type MergeStrategy, type NextOptions, type NextResult, type OnErrorHandler, type OnErrorResult, type PathMatcher, type ProxyChainOptions, type ProxyContext, type ProxyFn, type ProxyPathFilter, type ProxyRule, type RequestHeaderPolicy, RuleTimeoutError, createProxyContext, defineProxy, host, isNextResult, next, path, proxyChain };