nextjs-middleware-stack 1.0.2 โ†’ 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # ๐Ÿšฃ๏ธ `middlewareStack` โ€“ A Lightweight Middleware Router for Next.js
2
2
 
3
- A composable middleware stack for Next.js, supporting both `string`-based route patterns (with dynamic parameters and wildcards) and raw `RegExp` objects.
3
+ A composable middleware stack for Next.js, supporting `string`-based route patterns (with dynamic parameters and wildcards), raw `RegExp` objects, and custom sync/async predicate functions.
4
4
 
5
5
  Perfect for building layered request logic like authentication, logging, redirects, or feature flags in Next.js Edge or Node middlewares.
6
6
 
@@ -12,6 +12,7 @@ Perfect for building layered request logic like authentication, logging, redirec
12
12
  - `:param` dynamic segments
13
13
  - `**` wildcards (greedy)
14
14
  - โœ… `RegExp` support
15
+ - โœ… Custom `PatternFn` support: `(req) => boolean | Promise<boolean>`
15
16
  - โœ… Middleware short-circuiting (first matching response stops the stack)
16
17
  - โœ… Fully compatible with `next/server` and middleware in `apps/<name>/src/middleware.ts`
17
18
 
@@ -27,14 +28,22 @@ npm install compare-path
27
28
 
28
29
  ## ๐Ÿง  API
29
30
 
30
- ### `middlewareStack(routes: [string | RegExp, MiddlewareHandler][])`
31
+ ### `middlewareStack(routes: [Pattern, MiddlewareHandler][])`
31
32
 
32
33
  Creates a Next.js-compatible middleware handler from an ordered list of route matchers and handler functions.
33
34
 
35
+ ```ts
36
+ export type PatternFn = (req: Request) => boolean | Promise<boolean>
37
+ export type Pattern = PatternFn | string | RegExp
38
+ ```
39
+
34
40
  #### Parameters:
35
41
 
36
42
  - `routes`: An array of tuples where:
37
- - The first item is a string pattern (e.g., `/users/:id`) or a RegExp.
43
+ - The first item is a `Pattern`:
44
+ - a string pattern (e.g., `/users/:id`)
45
+ - a `RegExp`
46
+ - a function/async function `(req) => boolean | Promise<boolean>`
38
47
  - The second item is a handler function `(req: NextRequest) => Response | void | Promise<Response | void>`.
39
48
 
40
49
  #### Returns:
@@ -45,7 +54,7 @@ Creates a Next.js-compatible middleware handler from an ordered list of route ma
45
54
 
46
55
  ## ๐Ÿ“Š Supported Path Shapes
47
56
 
48
- You can use either `string`-based shape patterns (powered by `compare-path`) or `RegExp`.
57
+ You can use `string`-based shape patterns (powered by `compare-path`), `RegExp`, or predicate functions.
49
58
 
50
59
  | Shape | Matches Path Example |
51
60
  | --------------- | --------------------------- |
@@ -56,6 +65,8 @@ You can use either `string`-based shape patterns (powered by `compare-path`) or
56
65
 
57
66
  > Use RegExp when you need full regex control.
58
67
 
68
+ Use a predicate function when matching depends on request headers, cookies, or any custom runtime logic.
69
+
59
70
  ---
60
71
 
61
72
  ## ๐Ÿงช Example Usage (Auth Middleware)
@@ -116,6 +127,26 @@ export default middlewareStack([
116
127
 
117
128
  ---
118
129
 
130
+ ## ๐Ÿงช Example with `PatternFn`
131
+
132
+ ```ts
133
+ import { middlewareStack } from './utils/middleware-stack'
134
+
135
+ export default middlewareStack([
136
+ [
137
+ async (req) => {
138
+ // Match only API requests that include an auth header
139
+ return req.url.includes('/api/') && !!req.headers.get('authorization')
140
+ },
141
+ async (req) => {
142
+ // Custom logic for authenticated API requests
143
+ },
144
+ ],
145
+ ])
146
+ ```
147
+
148
+ ---
149
+
119
150
  ## ๐Ÿงน Integration in Next.js
120
151
 
121
152
  You must also export the `config` to ensure the middleware applies to your desired routes:
@@ -136,7 +167,7 @@ export const config = {
136
167
 
137
168
  Internally, `middlewareStack` will iterate through your routes and:
138
169
 
139
- 1. Compare the current path to each route (using `compare-path` or RegExp).
170
+ 1. Compare the current request to each route pattern (`compare-path`, `RegExp`, or `PatternFn`).
140
171
  2. If matched, execute the handler.
141
172
  3. If a `Response` is returned from the handler, it stops further execution and returns immediately.
142
173
 
@@ -147,7 +178,8 @@ Internally, `middlewareStack` will iterate through your routes and:
147
178
  - Middleware order matters! First match wins.
148
179
  - Use RegExp for more complex or legacy patterns.
149
180
  - Use string shapes for clean, readable routes with parameters.
181
+ - Use `PatternFn` for request-aware matching (cookies, headers, auth, geo, etc).
150
182
 
151
183
  ---
152
184
 
153
- Islam Yamor.
185
+ Islam Yamor.
package/dist/main.d.ts CHANGED
@@ -1,3 +1,5 @@
1
1
  export type MiddlewareHandler<T = Request, R = Response> = (req: T) => R | void | Promise<R | void>;
2
- export declare function middlewareStack<T = Request, R = Response>(routes: [string | RegExp, MiddlewareHandler<T, R>][]): (req: T) => Promise<R | void>;
2
+ export type PatternFn = (req: Request) => boolean | Promise<boolean>;
3
+ export type Pattern = PatternFn | string | RegExp;
4
+ export declare function middlewareStack<T = Request, R = Response>(routes: [Pattern, MiddlewareHandler<T, R>][]): (req: T) => Promise<R | void>;
3
5
  //# sourceMappingURL=main.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,iBAAiB,CAAC,CAAC,GAAG,OAAO,EAAE,CAAC,GAAG,QAAQ,IAAI,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,GAAG,IAAI,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAAA;AAEnG,wBAAgB,eAAe,CAAC,CAAC,GAAG,OAAO,EAAE,CAAC,GAAG,QAAQ,EACvD,MAAM,EAAE,CAAC,MAAM,GAAG,MAAM,EAAE,iBAAiB,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAEtC,KAAK,CAAC,KAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAkBzC"}
1
+ {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,iBAAiB,CAAC,CAAC,GAAG,OAAO,EAAE,CAAC,GAAG,QAAQ,IAAI,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,GAAG,IAAI,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAAA;AACnG,MAAM,MAAM,SAAS,GAAG,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;AACpE,MAAM,MAAM,OAAO,GAAG,SAAS,GAAG,MAAM,GAAG,MAAM,CAAA;AAEjD,wBAAgB,eAAe,CAAC,CAAC,GAAG,OAAO,EAAE,CAAC,GAAG,QAAQ,EACvD,MAAM,EAAE,CAAC,OAAO,EAAE,iBAAiB,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAE9B,KAAK,CAAC,KAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAoBzC"}
package/dist/main.js CHANGED
@@ -20,7 +20,9 @@ function middlewareStack(routes) {
20
20
  ? (0, compare_path_1.comparePath)(pattern, url)
21
21
  : pattern instanceof RegExp
22
22
  ? pattern.test(url)
23
- : false;
23
+ : typeof pattern === 'function'
24
+ ? yield pattern(req)
25
+ : false;
24
26
  if (isMatch) {
25
27
  const result = yield handler(req);
26
28
  if (result)
package/dist/main.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":";;;;;;;;;;;AAIA,0CAqBC;AAzBD,+CAA0C;AAI1C,SAAgB,eAAe,CAC7B,MAAoD;IAEpD,OAAO,CAAO,GAAM,EAAqB,EAAE;;QAEzC,MAAM,GAAG,GAAG,MAAA,MAAC,GAAwB,CAAC,OAAO,0CAAE,QAAQ,mCAAK,GAAe,CAAC,GAAG,CAAA;QAE/E,KAAK,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC,IAAI,MAAM,EAAE,CAAC;YACxC,MAAM,OAAO,GACX,OAAO,OAAO,KAAK,QAAQ;gBACzB,CAAC,CAAC,IAAA,0BAAW,EAAC,OAAO,EAAE,GAAG,CAAC;gBAC3B,CAAC,CAAC,OAAO,YAAY,MAAM;oBAC3B,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC;oBACnB,CAAC,CAAC,KAAK,CAAA;YAEX,IAAI,OAAO,EAAE,CAAC;gBACZ,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,CAAA;gBACjC,IAAI,MAAM;oBAAE,OAAO,MAAM,CAAA,CAAC,gDAAgD;YAC5E,CAAC;QACH,CAAC;IACH,CAAC,CAAA,CAAA;AACH,CAAC"}
1
+ {"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":";;;;;;;;;;;AAMA,0CAuBC;AA7BD,+CAA0C;AAM1C,SAAgB,eAAe,CAC7B,MAA4C;IAE5C,OAAO,CAAO,GAAM,EAAqB,EAAE;;QAEzC,MAAM,GAAG,GAAG,MAAA,MAAC,GAAwB,CAAC,OAAO,0CAAE,QAAQ,mCAAK,GAAe,CAAC,GAAG,CAAA;QAE/E,KAAK,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC,IAAI,MAAM,EAAE,CAAC;YACxC,MAAM,OAAO,GACX,OAAO,OAAO,KAAK,QAAQ;gBACzB,CAAC,CAAC,IAAA,0BAAW,EAAC,OAAO,EAAE,GAAG,CAAC;gBAC3B,CAAC,CAAC,OAAO,YAAY,MAAM;oBAC3B,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC;oBACnB,CAAC,CAAC,OAAO,OAAO,KAAK,UAAU;wBAC/B,CAAC,CAAC,MAAM,OAAO,CAAC,GAAc,CAAC;wBAC/B,CAAC,CAAC,KAAK,CAAA;YAEX,IAAI,OAAO,EAAE,CAAC;gBACZ,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,CAAA;gBACjC,IAAI,MAAM;oBAAE,OAAO,MAAM,CAAA,CAAC,gDAAgD;YAC5E,CAAC;QACH,CAAC;IACH,CAAC,CAAA,CAAA;AACH,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nextjs-middleware-stack",
3
- "version": "1.0.2",
3
+ "version": "1.1.0",
4
4
  "description": "Composable route-based middleware for Next.js Middleware.",
5
5
  "author": "Islam Yamor",
6
6
  "license": "Apache-2.0",