@zudojs/middleware 0.1.0 → 1.0.1

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.
Files changed (44) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +163 -16
  3. package/dist/middlewareCore/index.d.ts +1 -1
  4. package/dist/middlewareCore/index.js +1 -1
  5. package/dist/middlewareCore/middlewareCore.compose.d.ts +36 -4
  6. package/dist/middlewareCore/middlewareCore.compose.js +53 -14
  7. package/dist/middlewareErrors/index.d.ts +1 -1
  8. package/dist/middlewareErrors/index.js +1 -1
  9. package/dist/middlewareErrors/middlewareError.base.d.ts +30 -0
  10. package/dist/middlewareErrors/middlewareError.base.js +43 -0
  11. package/dist/middlewarePipeline/middlewarePipeline.core.d.ts +3 -1
  12. package/dist/middlewarePipeline/middlewarePipeline.core.js +99 -21
  13. package/dist/middlewareTypes/index.d.ts +1 -1
  14. package/dist/middlewareTypes/middlewareContext.type.d.ts +81 -12
  15. package/dist/middlewareUtils/index.d.ts +1 -1
  16. package/dist/middlewareUtils/index.js +1 -1
  17. package/dist/middlewareUtils/middlewareUtils.builtins.d.ts +87 -8
  18. package/dist/middlewareUtils/middlewareUtils.builtins.js +187 -28
  19. package/package.json +24 -13
  20. package/dist/.tsbuildinfo +0 -1
  21. package/dist/index.d.ts.map +0 -1
  22. package/dist/index.js.map +0 -1
  23. package/dist/middlewareCore/index.d.ts.map +0 -1
  24. package/dist/middlewareCore/index.js.map +0 -1
  25. package/dist/middlewareCore/middlewareCore.compose.d.ts.map +0 -1
  26. package/dist/middlewareCore/middlewareCore.compose.js.map +0 -1
  27. package/dist/middlewareErrors/index.d.ts.map +0 -1
  28. package/dist/middlewareErrors/index.js.map +0 -1
  29. package/dist/middlewareErrors/middlewareError.base.d.ts.map +0 -1
  30. package/dist/middlewareErrors/middlewareError.base.js.map +0 -1
  31. package/dist/middlewarePipeline/index.d.ts.map +0 -1
  32. package/dist/middlewarePipeline/index.js.map +0 -1
  33. package/dist/middlewarePipeline/middlewarePipeline.core.d.ts.map +0 -1
  34. package/dist/middlewarePipeline/middlewarePipeline.core.js.map +0 -1
  35. package/dist/middlewareTypes/index.d.ts.map +0 -1
  36. package/dist/middlewareTypes/index.js.map +0 -1
  37. package/dist/middlewareTypes/middlewareContext.type.d.ts.map +0 -1
  38. package/dist/middlewareTypes/middlewareContext.type.js.map +0 -1
  39. package/dist/middlewareTypes/middlewareDefinition.type.d.ts.map +0 -1
  40. package/dist/middlewareTypes/middlewareDefinition.type.js.map +0 -1
  41. package/dist/middlewareUtils/index.d.ts.map +0 -1
  42. package/dist/middlewareUtils/index.js.map +0 -1
  43. package/dist/middlewareUtils/middlewareUtils.builtins.d.ts.map +0 -1
  44. package/dist/middlewareUtils/middlewareUtils.builtins.js.map +0 -1
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Zudojs Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @zudojs/middleware
2
2
 
3
- Composable middleware pipeline with composition, timing, error handling, and context propagation.
3
+ Composable middleware pipeline with composition, priority ordering, execution tracking, error handling, and built-in middleware.
4
4
 
5
5
  ## Installation
6
6
 
@@ -12,28 +12,175 @@ npm install @zudojs/middleware
12
12
 
13
13
  ```typescript
14
14
  import {
15
- createMiddlewarePipeline,
16
- createTimeoutMiddleware,
15
+ createPipeline,
16
+ timeoutMiddleware,
17
+ loggingMiddleware,
18
+ rateLimitMiddleware,
17
19
  } from "@zudojs/middleware";
18
20
 
19
- const pipeline = createMiddlewarePipeline([
20
- createTimeoutMiddleware(5000),
21
- createLoggingMiddleware(),
22
- createAuthMiddleware(),
23
- ]);
21
+ interface RequestContext {
22
+ readonly method?: string;
23
+ readonly path?: string;
24
+ readonly key?: string;
25
+ }
24
26
 
25
- await pipeline(context, async () => {
26
- return handler(context);
27
+ // The handler runs after every middleware has called next().
28
+ const pipeline = createPipeline<RequestContext, string>(
29
+ [
30
+ timeoutMiddleware(5_000),
31
+ loggingMiddleware(),
32
+ rateLimitMiddleware(100, 60_000),
33
+ ],
34
+ async (context) => `handled ${context.method} ${context.path}`,
35
+ );
36
+
37
+ const outcome = await pipeline({
38
+ method: "GET",
39
+ path: "/users",
40
+ key: "client-1",
27
41
  });
42
+
43
+ if (outcome.success) {
44
+ console.log(outcome.result); // "handled GET /users"
45
+ } else {
46
+ console.error(outcome.error);
47
+ }
48
+ ```
49
+
50
+ `PipelineResult` is a discriminated union: narrowing on `success` gives you a
51
+ non-optional `result`, so no `!` is needed on the happy path.
52
+
53
+ ## Composition without the result wrapper
54
+
55
+ `compose` chains middleware around a handler and returns the handler's value
56
+ directly. Use it when you want the raw function rather than a
57
+ `PipelineResult`.
58
+
59
+ ```typescript
60
+ import { compose } from "@zudojs/middleware";
61
+ import type { Middleware } from "@zudojs/middleware";
62
+
63
+ const auth: Middleware<RequestContext, string> = async (context, next) => {
64
+ if (context.key === undefined) throw new Error("unauthenticated");
65
+ return next();
66
+ };
67
+
68
+ const handle = compose([auth], async (context) => `hello ${context.key}`);
69
+ await handle({ key: "client-1" });
28
70
  ```
29
71
 
30
- ## Features
72
+ ## Priority and toggling
73
+
74
+ `NamedMiddleware` carries a name, a numeric `priority` (lower runs earlier,
75
+ default 100) and an `enabled` flag. `createPipeline` filters and orders them
76
+ for you, and reports which ones ran.
77
+
78
+ ```typescript
79
+ const pipeline = createPipeline(
80
+ [
81
+ { name: "auth", handler: auth, priority: 10 },
82
+ { name: "audit", handler: audit, priority: 90, enabled: false },
83
+ ],
84
+ handler,
85
+ );
86
+
87
+ const outcome = await pipeline(context);
88
+ outcome.executedMiddleware; // ["auth"] — "audit" is disabled
89
+ ```
90
+
91
+ Ordering is stable, so middleware sharing a priority keeps its declared order.
92
+
93
+ ## Error handling
94
+
95
+ `errorMode` decides what a failure does:
96
+
97
+ | Mode | Behaviour |
98
+ | --------------------- | ----------------------------------------------------------------------------------------------------- |
99
+ | `"capture"` (default) | Stop and return `{ success: false, error }`. |
100
+ | `"throw"` | Stop and let the error propagate to the caller. |
101
+ | `"continue"` | Record the failure, skip past the failing middleware, keep going. A handler failure is never skipped. |
102
+
103
+ Every failure is also collected in `outcome.errors`, each tagged with the name
104
+ of the middleware that threw (or `"handler"`).
105
+
106
+ > **`"continue"` is not for security middleware.** Stepping past a middleware
107
+ > that threw means an authentication or authorization step that failed is
108
+ > stepped past too, and the handler still runs. A run can come back
109
+ > `success: true` with entries in `outcome.errors`, so under this mode check
110
+ > `outcome.errors` as well as `outcome.success`. Use `"capture"` (the default)
111
+ > or `"throw"` for any chain where a failing step must stop the request.
112
+
113
+ A middleware that catches a downstream failure and throws its own error in its
114
+ place ends the run: there is no downstream result left to keep, so the
115
+ pipeline reports the failure rather than a result that never existed.
116
+
117
+ ```typescript
118
+ const pipeline = createPipeline(list, handler, { errorMode: "continue" });
119
+ const outcome = await pipeline(context);
120
+ outcome.errors; // [{ name: "audit", error: … }]
121
+ ```
122
+
123
+ ## Cancellation
124
+
125
+ Pass an `AbortSignal` to stop a pipeline between steps. The signal is checked
126
+ before each middleware and before the handler; an aborted run fails with a
127
+ `MiddlewareAbortedError`.
128
+
129
+ ```typescript
130
+ const controller = new AbortController();
131
+ const pipeline = createPipeline(list, handler, { signal: controller.signal });
132
+ ```
133
+
134
+ ## Built-in middleware
135
+
136
+ - **`loggingMiddleware(logger?, options?)`** — logs start and completion.
137
+ Every interpolated field is escaped, so a path containing newlines cannot
138
+ forge log lines. Error messages are omitted unless you opt in with
139
+ `includeErrorMessage`.
140
+ - **`errorMiddleware(onError?, onReporterError?)`** — reports errors and
141
+ rethrows them. A reporter that throws cannot replace the original error.
142
+ - **`timeoutMiddleware(timeoutMs, options?)`** — fails with
143
+ `MiddlewareTimeoutError`. The timer is always cleared, so a fast request
144
+ leaves nothing pending on the event loop. `options.name` names the
145
+ middleware itself, so two timeouts in one pipeline are distinguishable in
146
+ `executedMiddleware` and in `outcome.errors`.
147
+ - **`rateLimitMiddleware(maxRequests, windowMs, options?)`** — a true sliding
148
+ window keyed on `context.key`, with key eviction and a configurable cap.
149
+ Rejections throw `MiddlewareRateLimitError`, which carries `retryAfterMs`
150
+ for a `Retry-After` header.
151
+
152
+ ```typescript
153
+ import { MiddlewareRateLimitError } from "@zudojs/middleware";
154
+
155
+ if (outcome.error instanceof MiddlewareRateLimitError) {
156
+ respond(429, { retryAfterMs: outcome.error.retryAfterMs });
157
+ }
158
+ ```
159
+
160
+ Rate-limit state is per-instance and in-process: behind more than one replica,
161
+ each process enforces its own limit.
162
+
163
+ ## Timing
164
+
165
+ `withTiming` wraps any middleware and reports slow executions. It is
166
+ transparent — the return value and any error pass through unchanged.
167
+
168
+ ```typescript
169
+ const timed = withTiming("db-lookup", lookup, {
170
+ thresholdMs: 50,
171
+ logger: (message) => logger.warn(message),
172
+ });
173
+ ```
174
+
175
+ ## Errors
176
+
177
+ All errors extend `MiddlewareError` (itself a `BaseError` from
178
+ `@zudojs/errors`), so a single `instanceof` catches everything from this
179
+ package:
31
180
 
32
- - Composable middleware pipeline
33
- - Error handling middleware
34
- - Timing and metrics middleware
35
- - Context propagation
36
- - Early termination support
181
+ `MiddlewareTimeoutError` · `MiddlewareNextCalledMultipleTimesError` ·
182
+ `MiddlewareLimitExceededError` · `MiddlewareDepthExceededError` ·
183
+ `MiddlewareRateLimitError` · `MiddlewareAbortedError`
37
184
 
38
185
  ## Use Cases
39
186
 
@@ -3,5 +3,5 @@
3
3
  *
4
4
  * @module middlewareCore
5
5
  */
6
- export { compose, resolveMiddleware, withTiming, } from "./middlewareCore.compose.js";
6
+ export { compose, resolveMiddleware, resolveNamedMiddleware, withTiming, MAX_DEPTH, type ComposeOptions, type TimingOptions, } from "./middlewareCore.compose.js";
7
7
  //# sourceMappingURL=index.d.ts.map
@@ -3,5 +3,5 @@
3
3
  *
4
4
  * @module middlewareCore
5
5
  */
6
- export { compose, resolveMiddleware, withTiming, } from "./middlewareCore.compose.js";
6
+ export { compose, resolveMiddleware, resolveNamedMiddleware, withTiming, MAX_DEPTH, } from "./middlewareCore.compose.js";
7
7
  //# sourceMappingURL=index.js.map
@@ -7,6 +7,13 @@
7
7
  * Each middleware calls `next()` to proceed to the next one.
8
8
  */
9
9
  import type { Middleware, NamedMiddleware } from "../middlewareTypes/middlewareDefinition.type.js";
10
+ /** Default ceiling on how deeply a composed chain may nest. */
11
+ export declare const MAX_DEPTH = 100;
12
+ /** Options for {@link compose}. */
13
+ export interface ComposeOptions {
14
+ /** Maximum chain depth. Default: {@link MAX_DEPTH}. */
15
+ readonly maxDepth?: number;
16
+ }
10
17
  /**
11
18
  * Compose an array of middleware into a single function.
12
19
  *
@@ -15,18 +22,43 @@ import type { Middleware, NamedMiddleware } from "../middlewareTypes/middlewareD
15
22
  *
16
23
  * @param middlewareList - Array of middleware functions
17
24
  * @param handler - The final handler to execute after all middleware
25
+ * @param options - Composition limits
18
26
  * @returns Composed function
27
+ * @throws MiddlewareDepthExceededError if the chain is longer than `maxDepth`
19
28
  */
20
- export declare function compose<TContext, TResult>(middlewareList: readonly Middleware<TContext, TResult>[], handler: (context: TContext) => Promise<TResult>): (context: TContext) => Promise<TResult>;
29
+ export declare function compose<TContext, TResult>(middlewareList: readonly Middleware<TContext, TResult>[], handler: (context: TContext) => Promise<TResult>, options?: ComposeOptions): (context: TContext) => Promise<TResult>;
21
30
  /**
22
- * Sort and filter named middleware by priority.
31
+ * Filter disabled middleware and sort the rest by priority.
32
+ *
33
+ * Ordering is stable, so middleware sharing a priority keeps its input order.
34
+ *
35
+ * @param middlewareList - Array of named middleware
36
+ * @returns Enabled middleware, in execution order, with names intact
37
+ */
38
+ export declare function resolveNamedMiddleware<TContext, TResult>(middlewareList: readonly NamedMiddleware<TContext, TResult>[]): NamedMiddleware<TContext, TResult>[];
39
+ /**
40
+ * Sort and filter named middleware by priority, returning bare handlers.
41
+ *
42
+ * Prefer {@link resolveNamedMiddleware} when the names are needed — this is a
43
+ * thin projection of it.
23
44
  *
24
45
  * @param middlewareList - Array of named middleware
25
46
  * @returns Sorted and filtered array of middleware handler functions
26
47
  */
27
48
  export declare function resolveMiddleware<TContext, TResult>(middlewareList: readonly NamedMiddleware<TContext, TResult>[]): Middleware<TContext, TResult>[];
49
+ /** Options for {@link withTiming}. */
50
+ export interface TimingOptions {
51
+ /** Log only when the middleware takes at least this long. Default: 100ms. */
52
+ readonly thresholdMs?: number;
53
+ /** Where to report slow middleware. Default: `console.warn`. */
54
+ readonly logger?: (message: string) => void;
55
+ }
28
56
  /**
29
- * Create a middleware that wraps another with timing.
57
+ * Wrap a middleware so that slow executions are reported.
58
+ *
59
+ * The wrapper is transparent: the inner middleware's return value and any
60
+ * error it throws pass through unchanged, and the timing is reported either
61
+ * way.
30
62
  */
31
- export declare function withTiming<TContext>(name: string, middleware: Middleware<TContext, void>): NamedMiddleware<TContext, void>;
63
+ export declare function withTiming<TContext, TResult = void>(name: string, middleware: Middleware<TContext, TResult>, options?: TimingOptions): NamedMiddleware<TContext, TResult>;
32
64
  //# sourceMappingURL=middlewareCore.compose.d.ts.map
@@ -6,7 +6,9 @@
6
6
  * Middleware executes in order (first added = first executed).
7
7
  * Each middleware calls `next()` to proceed to the next one.
8
8
  */
9
- const MAX_DEPTH = 100;
9
+ import { MiddlewareDepthExceededError, MiddlewareNextCalledMultipleTimesError, } from "../middlewareErrors/middlewareError.base.js";
10
+ /** Default ceiling on how deeply a composed chain may nest. */
11
+ export const MAX_DEPTH = 100;
10
12
  /**
11
13
  * Compose an array of middleware into a single function.
12
14
  *
@@ -15,9 +17,15 @@ const MAX_DEPTH = 100;
15
17
  *
16
18
  * @param middlewareList - Array of middleware functions
17
19
  * @param handler - The final handler to execute after all middleware
20
+ * @param options - Composition limits
18
21
  * @returns Composed function
22
+ * @throws MiddlewareDepthExceededError if the chain is longer than `maxDepth`
19
23
  */
20
- export function compose(middlewareList, handler) {
24
+ export function compose(middlewareList, handler, options) {
25
+ const maxDepth = options?.maxDepth ?? MAX_DEPTH;
26
+ if (middlewareList.length > maxDepth) {
27
+ throw new MiddlewareDepthExceededError(maxDepth);
28
+ }
21
29
  if (middlewareList.length === 0) {
22
30
  return handler;
23
31
  }
@@ -25,7 +33,12 @@ export function compose(middlewareList, handler) {
25
33
  let index = -1;
26
34
  async function dispatch(i) {
27
35
  if (i <= index) {
28
- throw new Error("next() called multiple times");
36
+ // dispatch(i) is invoked by the middleware at i - 1, so that is the
37
+ // one that called next() again.
38
+ throw new MiddlewareNextCalledMultipleTimesError(`middleware[${i - 1}]`);
39
+ }
40
+ if (i > maxDepth) {
41
+ throw new MiddlewareDepthExceededError(maxDepth);
29
42
  }
30
43
  index = i;
31
44
  if (i < middlewareList.length) {
@@ -38,29 +51,55 @@ export function compose(middlewareList, handler) {
38
51
  };
39
52
  }
40
53
  /**
41
- * Sort and filter named middleware by priority.
54
+ * Filter disabled middleware and sort the rest by priority.
55
+ *
56
+ * Ordering is stable, so middleware sharing a priority keeps its input order.
42
57
  *
43
58
  * @param middlewareList - Array of named middleware
44
- * @returns Sorted and filtered array of middleware handler functions
59
+ * @returns Enabled middleware, in execution order, with names intact
45
60
  */
46
- export function resolveMiddleware(middlewareList) {
61
+ export function resolveNamedMiddleware(middlewareList) {
47
62
  return middlewareList
48
63
  .filter((mw) => mw.enabled !== false)
49
- .sort((a, b) => (a.priority ?? 100) - (b.priority ?? 100))
50
- .map((mw) => mw.handler);
64
+ .sort((a, b) => (a.priority ?? 100) - (b.priority ?? 100));
51
65
  }
52
66
  /**
53
- * Create a middleware that wraps another with timing.
67
+ * Sort and filter named middleware by priority, returning bare handlers.
68
+ *
69
+ * Prefer {@link resolveNamedMiddleware} when the names are needed — this is a
70
+ * thin projection of it.
71
+ *
72
+ * @param middlewareList - Array of named middleware
73
+ * @returns Sorted and filtered array of middleware handler functions
54
74
  */
55
- export function withTiming(name, middleware) {
75
+ export function resolveMiddleware(middlewareList) {
76
+ return resolveNamedMiddleware(middlewareList).map((mw) => mw.handler);
77
+ }
78
+ /**
79
+ * Wrap a middleware so that slow executions are reported.
80
+ *
81
+ * The wrapper is transparent: the inner middleware's return value and any
82
+ * error it throws pass through unchanged, and the timing is reported either
83
+ * way.
84
+ */
85
+ export function withTiming(name, middleware, options) {
86
+ const thresholdMs = options?.thresholdMs ?? 100;
87
+ const log = options?.logger ??
88
+ ((message) => {
89
+ console.warn(message);
90
+ });
56
91
  return {
57
92
  name,
58
93
  handler: async (ctx, next) => {
59
94
  const start = performance.now();
60
- await middleware(ctx, next);
61
- const duration = performance.now() - start;
62
- if (duration > 100) {
63
- console.warn(`[middleware] ${name} took ${duration.toFixed(1)}ms`);
95
+ try {
96
+ return await middleware(ctx, next);
97
+ }
98
+ finally {
99
+ const duration = performance.now() - start;
100
+ if (duration >= thresholdMs) {
101
+ log(`[middleware] ${name} took ${duration.toFixed(1)}ms`);
102
+ }
64
103
  }
65
104
  },
66
105
  };
@@ -3,5 +3,5 @@
3
3
  *
4
4
  * @module middlewareErrors
5
5
  */
6
- export { MiddlewareError, MiddlewareTimeoutError, MiddlewareNextCalledMultipleTimesError, } from "./middlewareError.base.js";
6
+ export { MiddlewareError, MiddlewareTimeoutError, MiddlewareNextCalledMultipleTimesError, MiddlewareLimitExceededError, MiddlewareDepthExceededError, MiddlewareRateLimitError, MiddlewareAbortedError, } from "./middlewareError.base.js";
7
7
  //# sourceMappingURL=index.d.ts.map
@@ -3,5 +3,5 @@
3
3
  *
4
4
  * @module middlewareErrors
5
5
  */
6
- export { MiddlewareError, MiddlewareTimeoutError, MiddlewareNextCalledMultipleTimesError, } from "./middlewareError.base.js";
6
+ export { MiddlewareError, MiddlewareTimeoutError, MiddlewareNextCalledMultipleTimesError, MiddlewareLimitExceededError, MiddlewareDepthExceededError, MiddlewareRateLimitError, MiddlewareAbortedError, } from "./middlewareError.base.js";
7
7
  //# sourceMappingURL=index.js.map
@@ -25,4 +25,34 @@ export declare class MiddlewareTimeoutError extends MiddlewareError {
25
25
  export declare class MiddlewareNextCalledMultipleTimesError extends MiddlewareError {
26
26
  constructor(middlewareName: string);
27
27
  }
28
+ /**
29
+ * Error thrown when a pipeline is configured with more middleware than allowed.
30
+ */
31
+ export declare class MiddlewareLimitExceededError extends MiddlewareError {
32
+ constructor(count: number, maximum: number);
33
+ }
34
+ /**
35
+ * Error thrown when the middleware chain nests deeper than the allowed limit.
36
+ */
37
+ export declare class MiddlewareDepthExceededError extends MiddlewareError {
38
+ constructor(maxDepth: number);
39
+ }
40
+ /**
41
+ * Error thrown when a rate limit is exceeded.
42
+ *
43
+ * `retryAfterMs` tells the caller how long to wait before retrying, which is
44
+ * what an HTTP adapter needs to emit a `Retry-After` header alongside a 429.
45
+ */
46
+ export declare class MiddlewareRateLimitError extends MiddlewareError {
47
+ readonly retryAfterMs: number;
48
+ readonly limit: number;
49
+ readonly windowMs: number;
50
+ constructor(limit: number, windowMs: number, retryAfterMs: number);
51
+ }
52
+ /**
53
+ * Error thrown when a pipeline is aborted through its `AbortSignal`.
54
+ */
55
+ export declare class MiddlewareAbortedError extends MiddlewareError {
56
+ constructor(reason?: unknown);
57
+ }
28
58
  //# sourceMappingURL=middlewareError.base.d.ts.map
@@ -40,4 +40,47 @@ export class MiddlewareNextCalledMultipleTimesError extends MiddlewareError {
40
40
  });
41
41
  }
42
42
  }
43
+ /**
44
+ * Error thrown when a pipeline is configured with more middleware than allowed.
45
+ */
46
+ export class MiddlewareLimitExceededError extends MiddlewareError {
47
+ constructor(count, maximum) {
48
+ super(`Pipeline has ${count} middleware, exceeding the maximum of ${maximum}`);
49
+ }
50
+ }
51
+ /**
52
+ * Error thrown when the middleware chain nests deeper than the allowed limit.
53
+ */
54
+ export class MiddlewareDepthExceededError extends MiddlewareError {
55
+ constructor(maxDepth) {
56
+ super(`Middleware chain exceeded the maximum depth of ${maxDepth}`);
57
+ }
58
+ }
59
+ /**
60
+ * Error thrown when a rate limit is exceeded.
61
+ *
62
+ * `retryAfterMs` tells the caller how long to wait before retrying, which is
63
+ * what an HTTP adapter needs to emit a `Retry-After` header alongside a 429.
64
+ */
65
+ export class MiddlewareRateLimitError extends MiddlewareError {
66
+ retryAfterMs;
67
+ limit;
68
+ windowMs;
69
+ constructor(limit, windowMs, retryAfterMs) {
70
+ super(`Rate limit exceeded: ${limit} requests per ${windowMs}ms`, {
71
+ middlewareName: "rate-limit",
72
+ });
73
+ this.retryAfterMs = retryAfterMs;
74
+ this.limit = limit;
75
+ this.windowMs = windowMs;
76
+ }
77
+ }
78
+ /**
79
+ * Error thrown when a pipeline is aborted through its `AbortSignal`.
80
+ */
81
+ export class MiddlewareAbortedError extends MiddlewareError {
82
+ constructor(reason) {
83
+ super("Middleware pipeline aborted", { cause: reason });
84
+ }
85
+ }
43
86
  //# sourceMappingURL=middlewareError.base.js.map
@@ -3,8 +3,8 @@
3
3
  *
4
4
  * @module middlewarePipeline/middlewarePipeline
5
5
  */
6
- import type { NamedMiddleware } from "../middlewareTypes/middlewareDefinition.type.js";
7
6
  import type { PipelineResult, PipelineOptions } from "../middlewareTypes/middlewareContext.type.js";
7
+ import type { NamedMiddleware } from "../middlewareTypes/middlewareDefinition.type.js";
8
8
  /**
9
9
  * Create a middleware pipeline that tracks execution.
10
10
  *
@@ -12,6 +12,8 @@ import type { PipelineResult, PipelineOptions } from "../middlewareTypes/middlew
12
12
  * @param handler - Final handler function
13
13
  * @param options - Pipeline configuration
14
14
  * @returns Pipeline execution function
15
+ * @throws MiddlewareLimitExceededError if more middleware are enabled than
16
+ * `maxMiddleware` allows
15
17
  */
16
18
  export declare function createPipeline<TContext, TResult>(middlewareList: readonly NamedMiddleware<TContext, TResult>[], handler: (context: TContext) => Promise<TResult>, options?: PipelineOptions): (context: TContext) => Promise<PipelineResult<TResult>>;
17
19
  //# sourceMappingURL=middlewarePipeline.core.d.ts.map