@arikajs/middleware 0.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/LICENSE +21 -0
- package/README.md +250 -0
- package/dist/Compose.d.ts +6 -0
- package/dist/Compose.d.ts.map +1 -0
- package/dist/Compose.js +15 -0
- package/dist/Compose.js.map +1 -0
- package/dist/Contracts/Container.d.ts +5 -0
- package/dist/Contracts/Container.d.ts.map +1 -0
- package/dist/Contracts/Container.js +3 -0
- package/dist/Contracts/Container.js.map +1 -0
- package/dist/Middleware.d.ts +14 -0
- package/dist/Middleware.d.ts.map +1 -0
- package/dist/Middleware.js +3 -0
- package/dist/Middleware.js.map +1 -0
- package/dist/Pipeline.d.ts +43 -0
- package/dist/Pipeline.d.ts.map +1 -0
- package/dist/Pipeline.js +118 -0
- package/dist/Pipeline.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -0
- package/package.json +46 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 ArikaJs
|
|
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
ADDED
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
## Arika Middleware
|
|
2
|
+
|
|
3
|
+
`@arikajs/middleware` provides a flexible, composable middleware system for the ArikaJS framework.
|
|
4
|
+
|
|
5
|
+
Middleware allows developers to inspect, modify, or short-circuit the request/response lifecycle before the final route handler is executed.
|
|
6
|
+
|
|
7
|
+
This package is framework-agnostic and is used by both the HTTP Kernel and the Dispatcher.
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
const pipeline = new Pipeline();
|
|
11
|
+
|
|
12
|
+
pipeline.pipe(async (req, next) => {
|
|
13
|
+
console.log('Before');
|
|
14
|
+
const res = await next(req);
|
|
15
|
+
console.log('After');
|
|
16
|
+
return res;
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
const response = await pipeline.handle(request, (req) => {
|
|
20
|
+
return new Response('Hello World');
|
|
21
|
+
});
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Arika Middleware follows the **onion-style execution model**, ensuring a predictable flow for request and response modification.
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
### Status
|
|
29
|
+
|
|
30
|
+
- **Stage**: Experimental / v0.x
|
|
31
|
+
- **Scope (v0.x)**:
|
|
32
|
+
- Onion-style pipeline execution
|
|
33
|
+
- Middleware contracts (interface & types)
|
|
34
|
+
- Composable middleware stacks (Compose utility)
|
|
35
|
+
- Support for functional and class-based middleware
|
|
36
|
+
- **Out of scope (for this package)**:
|
|
37
|
+
- Route matching (handled by `@arikajs/router`)
|
|
38
|
+
- Controller resolution (handled by `@arikajs/dispatcher`)
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## 🎯 Purpose
|
|
43
|
+
|
|
44
|
+
Middleware sits between the incoming request and the final handler.
|
|
45
|
+
|
|
46
|
+
Typical use cases:
|
|
47
|
+
- Authentication & authorization
|
|
48
|
+
- Logging & metrics
|
|
49
|
+
- Request transformation
|
|
50
|
+
- Response modification
|
|
51
|
+
- Rate limiting
|
|
52
|
+
- CORS handling
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## 🧠 Responsibility
|
|
57
|
+
|
|
58
|
+
### ✅ What Middleware Does
|
|
59
|
+
- Execute logic before and/or after the route handler
|
|
60
|
+
- Control the request flow using `next()`
|
|
61
|
+
- Modify request or response objects
|
|
62
|
+
- Short-circuit execution by returning a response early
|
|
63
|
+
- Support asynchronous operations
|
|
64
|
+
|
|
65
|
+
### ❌ What Middleware Does NOT Do
|
|
66
|
+
- Match routes
|
|
67
|
+
- Resolve controllers
|
|
68
|
+
- Render templates
|
|
69
|
+
- Handle business logic
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## 🧬 Execution Flow
|
|
74
|
+
|
|
75
|
+
```
|
|
76
|
+
Request
|
|
77
|
+
↓
|
|
78
|
+
Middleware A
|
|
79
|
+
↓
|
|
80
|
+
Middleware B
|
|
81
|
+
↓
|
|
82
|
+
Route Handler
|
|
83
|
+
↓
|
|
84
|
+
Middleware B (after)
|
|
85
|
+
↓
|
|
86
|
+
Middleware A (after)
|
|
87
|
+
↓
|
|
88
|
+
Response
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## Features
|
|
94
|
+
|
|
95
|
+
- **Onion-style pipeline execution**
|
|
96
|
+
- Execute logic before and after the handler.
|
|
97
|
+
- Symmetrical execution flow.
|
|
98
|
+
|
|
99
|
+
- **Async middleware support**
|
|
100
|
+
- Full support for `async/await`.
|
|
101
|
+
- Seamless handling of asynchronous operations.
|
|
102
|
+
|
|
103
|
+
- **Early response termination**
|
|
104
|
+
- Short-circuit execution by returning a response without calling `next()`.
|
|
105
|
+
- Useful for authentication and validation.
|
|
106
|
+
|
|
107
|
+
- **Composable middleware stacks**
|
|
108
|
+
- Group multiple middleware into a single unit using `compose()`.
|
|
109
|
+
- Highly reusable and easy to organize.
|
|
110
|
+
|
|
111
|
+
- **Framework-level & route-level compatibility**
|
|
112
|
+
- Works globally via kernels or specifically via route definitions.
|
|
113
|
+
|
|
114
|
+
- **Minimal, predictable API**
|
|
115
|
+
- Small surface area for maximum stability.
|
|
116
|
+
- Zero dependencies on other logic besides `@arikajs/http`.
|
|
117
|
+
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
## Installation
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
npm install @arikajs/middleware
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
This package is written in TypeScript and ships with type definitions.
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## Quick Start
|
|
131
|
+
|
|
132
|
+
### 1. Create a middleware
|
|
133
|
+
|
|
134
|
+
```ts
|
|
135
|
+
export const logger = async (request, next) => {
|
|
136
|
+
console.log(`${request.method} ${request.path}`);
|
|
137
|
+
const response = await next(request);
|
|
138
|
+
return response;
|
|
139
|
+
};
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### 2. Run through a Pipeline
|
|
143
|
+
|
|
144
|
+
```ts
|
|
145
|
+
import { Pipeline } from '@arikajs/middleware';
|
|
146
|
+
|
|
147
|
+
const pipeline = new Pipeline().pipe(logger);
|
|
148
|
+
|
|
149
|
+
const response = await pipeline.handle(request, (req) => {
|
|
150
|
+
return new Response('Handled');
|
|
151
|
+
});
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### 3. Applying to Routes (via @arikajs/router)
|
|
155
|
+
|
|
156
|
+
```ts
|
|
157
|
+
Route.get('/dashboard', handler)
|
|
158
|
+
.middleware([authMiddleware, logger]);
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### 4. Global Middleware (via HTTP Kernel)
|
|
162
|
+
|
|
163
|
+
```ts
|
|
164
|
+
kernel.use(logger);
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
## Middleware Pipeline
|
|
170
|
+
|
|
171
|
+
The `Pipeline` class is the central engine of the middleware system. It manages a stack of middleware and executes them in the order they were added.
|
|
172
|
+
|
|
173
|
+
### API
|
|
174
|
+
|
|
175
|
+
```ts
|
|
176
|
+
class Pipeline<TRequest = any, TResponse = any> {
|
|
177
|
+
constructor(container?: Container);
|
|
178
|
+
pipe(middleware: MiddlewareHandler<TRequest, TResponse> | MiddlewareHandler<TRequest, TResponse>[]): this;
|
|
179
|
+
handle(
|
|
180
|
+
request: TRequest,
|
|
181
|
+
destination: (request: TRequest, response?: TResponse) => Promise<TResponse> | TResponse,
|
|
182
|
+
response?: TResponse
|
|
183
|
+
): Promise<TResponse>;
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
## Composing Middleware
|
|
190
|
+
|
|
191
|
+
The `compose` utility allows you to merge multiple middleware handlers into a single function.
|
|
192
|
+
|
|
193
|
+
```ts
|
|
194
|
+
import { compose } from '@arikajs/middleware';
|
|
195
|
+
|
|
196
|
+
const authStack = compose([
|
|
197
|
+
validateToken,
|
|
198
|
+
checkPermissions
|
|
199
|
+
]);
|
|
200
|
+
|
|
201
|
+
pipeline.pipe(authStack);
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
## Project Structure
|
|
207
|
+
|
|
208
|
+
- `src/`
|
|
209
|
+
- `Middleware.ts` – Middleware contract and types
|
|
210
|
+
- `Pipeline.ts` – Core execution logic
|
|
211
|
+
- `Compose.ts` – Middleware composition utility
|
|
212
|
+
- `index.ts` – Public exports
|
|
213
|
+
- `tests/`
|
|
214
|
+
- `Pipeline.test.ts` – Integration tests for pipeline execution and order
|
|
215
|
+
- `package.json`
|
|
216
|
+
- `tsconfig.json`
|
|
217
|
+
- `tsconfig.test.json`
|
|
218
|
+
- `README.md`
|
|
219
|
+
- `LICENSE`
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
## 🧪 Versioning & Stability
|
|
224
|
+
|
|
225
|
+
- Currently in **v0.x** (experimental).
|
|
226
|
+
- Public API may evolve.
|
|
227
|
+
- Will stabilize in **v1.0** once execution semantics are finalized.
|
|
228
|
+
|
|
229
|
+
---
|
|
230
|
+
|
|
231
|
+
## 📜 License
|
|
232
|
+
|
|
233
|
+
`@arikajs/middleware` is open-sourced software licensed under the **MIT license**.
|
|
234
|
+
|
|
235
|
+
---
|
|
236
|
+
|
|
237
|
+
## 🧠 Philosophy
|
|
238
|
+
|
|
239
|
+
> “Middleware is not logic — it is flow control.”
|
|
240
|
+
|
|
241
|
+
---
|
|
242
|
+
|
|
243
|
+
## 🚀 Next Packages (Recommended Order)
|
|
244
|
+
|
|
245
|
+
✅ Dispatcher
|
|
246
|
+
✅ Middleware
|
|
247
|
+
🔜 View Engine
|
|
248
|
+
🔜 Validation
|
|
249
|
+
🔜 Authentication
|
|
250
|
+
🔜 CLI
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Compose.d.ts","sourceRoot":"","sources":["../src/Compose.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAGjD;;GAEG;AACH,wBAAgB,OAAO,CAAC,UAAU,EAAE,iBAAiB,EAAE,GAAG,iBAAiB,CAM1E"}
|
package/dist/Compose.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.compose = compose;
|
|
4
|
+
const Pipeline_1 = require("./Pipeline");
|
|
5
|
+
/**
|
|
6
|
+
* Compose multiple middleware handlers into a single middleware handler.
|
|
7
|
+
*/
|
|
8
|
+
function compose(middleware) {
|
|
9
|
+
return async (request, next) => {
|
|
10
|
+
return new Pipeline_1.Pipeline()
|
|
11
|
+
.pipe(middleware)
|
|
12
|
+
.handle(request, next);
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=Compose.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Compose.js","sourceRoot":"","sources":["../src/Compose.ts"],"names":[],"mappings":";;AAOA,0BAMC;AAXD,yCAAsC;AAEtC;;GAEG;AACH,SAAgB,OAAO,CAAC,UAA+B;IACnD,OAAO,KAAK,EAAE,OAAgB,EAAE,IAAwD,EAAqB,EAAE;QAC3G,OAAO,IAAI,mBAAQ,EAAE;aAChB,IAAI,CAAC,UAAU,CAAC;aAChB,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IAC/B,CAAC,CAAC;AACN,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Container.d.ts","sourceRoot":"","sources":["../../src/Contracts/Container.ts"],"names":[],"mappings":"AACA,MAAM,WAAW,SAAS;IACtB,IAAI,CAAC,CAAC,GAAG,GAAG,EAAE,KAAK,EAAE,GAAG,GAAG,CAAC,CAAC;IAC7B,GAAG,CAAC,KAAK,EAAE,GAAG,GAAG,OAAO,CAAC;CAC5B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Container.js","sourceRoot":"","sources":["../../src/Contracts/Container.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Middleware contract for ArikaJS.
|
|
3
|
+
*/
|
|
4
|
+
export interface Middleware<TRequest = any, TResponse = any> {
|
|
5
|
+
/**
|
|
6
|
+
* Handle an incoming request.
|
|
7
|
+
*/
|
|
8
|
+
handle(request: TRequest, next: (request: TRequest) => Promise<TResponse> | TResponse, response?: TResponse): Promise<TResponse> | TResponse;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Type for middleware that can be either a class, a function, or a string key.
|
|
12
|
+
*/
|
|
13
|
+
export type MiddlewareHandler<TRequest = any, TResponse = any> = Middleware<TRequest, TResponse> | ((request: TRequest, next: (request: TRequest) => Promise<TResponse> | TResponse, response?: TResponse) => Promise<TResponse> | TResponse) | string | any;
|
|
14
|
+
//# sourceMappingURL=Middleware.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Middleware.d.ts","sourceRoot":"","sources":["../src/Middleware.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,UAAU,CAAC,QAAQ,GAAG,GAAG,EAAE,SAAS,GAAG,GAAG;IACvD;;OAEG;IACH,MAAM,CACF,OAAO,EAAE,QAAQ,EACjB,IAAI,EAAE,CAAC,OAAO,EAAE,QAAQ,KAAK,OAAO,CAAC,SAAS,CAAC,GAAG,SAAS,EAC3D,QAAQ,CAAC,EAAE,SAAS,GACrB,OAAO,CAAC,SAAS,CAAC,GAAG,SAAS,CAAC;CACrC;AAED;;GAEG;AACH,MAAM,MAAM,iBAAiB,CAAC,QAAQ,GAAG,GAAG,EAAE,SAAS,GAAG,GAAG,IACvD,UAAU,CAAC,QAAQ,EAAE,SAAS,CAAC,GAC/B,CAAC,CAAC,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,OAAO,EAAE,QAAQ,KAAK,OAAO,CAAC,SAAS,CAAC,GAAG,SAAS,EAAE,QAAQ,CAAC,EAAE,SAAS,KAAK,OAAO,CAAC,SAAS,CAAC,GAAG,SAAS,CAAC,GAC1I,MAAM,GACN,GAAG,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Middleware.js","sourceRoot":"","sources":["../src/Middleware.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { Container } from './Contracts/Container';
|
|
2
|
+
import { MiddlewareHandler } from './Middleware';
|
|
3
|
+
/**
|
|
4
|
+
* Pipeline executes a stack of middleware in an onion-style model.
|
|
5
|
+
*/
|
|
6
|
+
export declare class Pipeline<TRequest = any, TResponse = any> {
|
|
7
|
+
private readonly container?;
|
|
8
|
+
/**
|
|
9
|
+
* The stack of middleware handlers.
|
|
10
|
+
*/
|
|
11
|
+
private handlers;
|
|
12
|
+
private middlewareGroups;
|
|
13
|
+
private aliases;
|
|
14
|
+
/**
|
|
15
|
+
* Create a new Pipeline instance.
|
|
16
|
+
*/
|
|
17
|
+
constructor(container?: Container | undefined);
|
|
18
|
+
/**
|
|
19
|
+
* Set the middleware groups.
|
|
20
|
+
*/
|
|
21
|
+
setMiddlewareGroups(groups: Record<string, any[]>): this;
|
|
22
|
+
/**
|
|
23
|
+
* Set the middleware aliases.
|
|
24
|
+
*/
|
|
25
|
+
setAliases(aliases: Record<string, any>): this;
|
|
26
|
+
/**
|
|
27
|
+
* Add middleware to the pipeline.
|
|
28
|
+
*/
|
|
29
|
+
pipe(middleware: MiddlewareHandler<TRequest, TResponse> | MiddlewareHandler<TRequest, TResponse>[]): this;
|
|
30
|
+
/**
|
|
31
|
+
* Run the pipeline through the given destination.
|
|
32
|
+
*/
|
|
33
|
+
handle(request: TRequest, destination: (request: TRequest, response?: TResponse) => Promise<TResponse> | TResponse, response?: TResponse): Promise<TResponse>;
|
|
34
|
+
/**
|
|
35
|
+
* Resolve the middleware handler.
|
|
36
|
+
*/
|
|
37
|
+
private resolve;
|
|
38
|
+
/**
|
|
39
|
+
* Flatten handlers by resolving groups and aliases.
|
|
40
|
+
*/
|
|
41
|
+
private flattenHandlers;
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=Pipeline.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Pipeline.d.ts","sourceRoot":"","sources":["../src/Pipeline.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAAc,MAAM,cAAc,CAAC;AAG7D;;GAEG;AACH,qBAAa,QAAQ,CAAC,QAAQ,GAAG,GAAG,EAAE,SAAS,GAAG,GAAG;IAWrC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC;IAVvC;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAgD;IAChE,OAAO,CAAC,gBAAgB,CAA6B;IACrD,OAAO,CAAC,OAAO,CAA2B;IAE1C;;OAEG;gBAC0B,SAAS,CAAC,EAAE,SAAS,YAAA;IAElD;;OAEG;IACI,mBAAmB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,GAAG,IAAI;IAK/D;;OAEG;IACI,UAAU,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI;IAKrD;;OAEG;IACI,IAAI,CAAC,UAAU,EAAE,iBAAiB,CAAC,QAAQ,EAAE,SAAS,CAAC,GAAG,iBAAiB,CAAC,QAAQ,EAAE,SAAS,CAAC,EAAE,GAAG,IAAI;IAShH;;OAEG;IACU,MAAM,CACf,OAAO,EAAE,QAAQ,EACjB,WAAW,EAAE,CAAC,OAAO,EAAE,QAAQ,EAAE,QAAQ,CAAC,EAAE,SAAS,KAAK,OAAO,CAAC,SAAS,CAAC,GAAG,SAAS,EACxF,QAAQ,CAAC,EAAE,SAAS,GACrB,OAAO,CAAC,SAAS,CAAC;IAwBrB;;OAEG;IACH,OAAO,CAAC,OAAO;IAyBf;;OAEG;IACH,OAAO,CAAC,eAAe;CA0B1B"}
|
package/dist/Pipeline.js
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Pipeline = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Pipeline executes a stack of middleware in an onion-style model.
|
|
6
|
+
*/
|
|
7
|
+
class Pipeline {
|
|
8
|
+
/**
|
|
9
|
+
* Create a new Pipeline instance.
|
|
10
|
+
*/
|
|
11
|
+
constructor(container) {
|
|
12
|
+
this.container = container;
|
|
13
|
+
/**
|
|
14
|
+
* The stack of middleware handlers.
|
|
15
|
+
*/
|
|
16
|
+
this.handlers = [];
|
|
17
|
+
this.middlewareGroups = {};
|
|
18
|
+
this.aliases = {};
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Set the middleware groups.
|
|
22
|
+
*/
|
|
23
|
+
setMiddlewareGroups(groups) {
|
|
24
|
+
this.middlewareGroups = groups;
|
|
25
|
+
return this;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Set the middleware aliases.
|
|
29
|
+
*/
|
|
30
|
+
setAliases(aliases) {
|
|
31
|
+
this.aliases = aliases;
|
|
32
|
+
return this;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Add middleware to the pipeline.
|
|
36
|
+
*/
|
|
37
|
+
pipe(middleware) {
|
|
38
|
+
if (Array.isArray(middleware)) {
|
|
39
|
+
this.handlers.push(...middleware);
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
this.handlers.push(middleware);
|
|
43
|
+
}
|
|
44
|
+
return this;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Run the pipeline through the given destination.
|
|
48
|
+
*/
|
|
49
|
+
async handle(request, destination, response) {
|
|
50
|
+
const flattened = this.flattenHandlers(this.handlers);
|
|
51
|
+
const invoke = async (index, req) => {
|
|
52
|
+
if (index >= flattened.length) {
|
|
53
|
+
return destination(req, response);
|
|
54
|
+
}
|
|
55
|
+
const handler = this.resolve(flattened[index]);
|
|
56
|
+
if (typeof handler === 'function') {
|
|
57
|
+
return handler(req, (nextReq) => invoke(index + 1, nextReq), response);
|
|
58
|
+
}
|
|
59
|
+
if (typeof handler === 'object' && 'handle' in handler && typeof handler.handle === 'function') {
|
|
60
|
+
return handler.handle(req, (nextReq) => invoke(index + 1, nextReq), response);
|
|
61
|
+
}
|
|
62
|
+
throw new Error(`Invalid middleware handler: ${typeof handler}`);
|
|
63
|
+
};
|
|
64
|
+
return invoke(0, request);
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Resolve the middleware handler.
|
|
68
|
+
*/
|
|
69
|
+
resolve(handler) {
|
|
70
|
+
// If it's a string, try resolving from container first
|
|
71
|
+
if (typeof handler === 'string') {
|
|
72
|
+
if (this.container && this.container.has(handler)) {
|
|
73
|
+
return this.container.make(handler);
|
|
74
|
+
}
|
|
75
|
+
return handler;
|
|
76
|
+
}
|
|
77
|
+
// If it's a class/constructor (has handle on prototype), instantiate it
|
|
78
|
+
if (typeof handler === 'function') {
|
|
79
|
+
const isClass = /^\s*class\s+/.test(handler.toString()) ||
|
|
80
|
+
(handler.prototype && typeof handler.prototype.handle === 'function');
|
|
81
|
+
if (isClass) {
|
|
82
|
+
if (this.container) {
|
|
83
|
+
return this.container.make(handler);
|
|
84
|
+
}
|
|
85
|
+
return new handler();
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return handler;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Flatten handlers by resolving groups and aliases.
|
|
92
|
+
*/
|
|
93
|
+
flattenHandlers(handlers) {
|
|
94
|
+
let flattened = [];
|
|
95
|
+
for (const handler of handlers) {
|
|
96
|
+
if (typeof handler === 'string') {
|
|
97
|
+
if (this.middlewareGroups[handler]) {
|
|
98
|
+
flattened.push(...this.flattenHandlers(this.middlewareGroups[handler]));
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
if (this.aliases[handler]) {
|
|
102
|
+
const resolved = this.aliases[handler];
|
|
103
|
+
if (Array.isArray(resolved)) {
|
|
104
|
+
flattened.push(...this.flattenHandlers(resolved));
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
flattened.push(...this.flattenHandlers([resolved]));
|
|
108
|
+
}
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
flattened.push(handler);
|
|
113
|
+
}
|
|
114
|
+
return flattened;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
exports.Pipeline = Pipeline;
|
|
118
|
+
//# sourceMappingURL=Pipeline.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Pipeline.js","sourceRoot":"","sources":["../src/Pipeline.ts"],"names":[],"mappings":";;;AAIA;;GAEG;AACH,MAAa,QAAQ;IAQjB;;OAEG;IACH,YAA6B,SAAqB;QAArB,cAAS,GAAT,SAAS,CAAY;QAVlD;;WAEG;QACK,aAAQ,GAA6C,EAAE,CAAC;QACxD,qBAAgB,GAA0B,EAAE,CAAC;QAC7C,YAAO,GAAwB,EAAE,CAAC;IAKY,CAAC;IAEvD;;OAEG;IACI,mBAAmB,CAAC,MAA6B;QACpD,IAAI,CAAC,gBAAgB,GAAG,MAAM,CAAC;QAC/B,OAAO,IAAI,CAAC;IAChB,CAAC;IAED;;OAEG;IACI,UAAU,CAAC,OAA4B;QAC1C,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,OAAO,IAAI,CAAC;IAChB,CAAC;IAED;;OAEG;IACI,IAAI,CAAC,UAA6F;QACrG,IAAI,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC;YAC5B,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,UAAU,CAAC,CAAC;QACtC,CAAC;aAAM,CAAC;YACJ,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACnC,CAAC;QACD,OAAO,IAAI,CAAC;IAChB,CAAC;IAED;;OAEG;IACI,KAAK,CAAC,MAAM,CACf,OAAiB,EACjB,WAAwF,EACxF,QAAoB;QAEpB,MAAM,SAAS,GAAG,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAEtD,MAAM,MAAM,GAAG,KAAK,EAAE,KAAa,EAAE,GAAa,EAAsB,EAAE;YACtE,IAAI,KAAK,IAAI,SAAS,CAAC,MAAM,EAAE,CAAC;gBAC5B,OAAO,WAAW,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;YACtC,CAAC;YAED,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC;YAE/C,IAAI,OAAO,OAAO,KAAK,UAAU,EAAE,CAAC;gBAChC,OAAO,OAAO,CAAC,GAAG,EAAE,CAAC,OAAiB,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,GAAG,CAAC,EAAE,OAAO,CAAC,EAAE,QAAQ,CAAC,CAAC;YACrF,CAAC;YAED,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,QAAQ,IAAI,OAAO,IAAI,OAAO,OAAO,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;gBAC7F,OAAQ,OAAe,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,OAAiB,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,GAAG,CAAC,EAAE,OAAO,CAAC,EAAE,QAAQ,CAAC,CAAC;YACrG,CAAC;YAED,MAAM,IAAI,KAAK,CAAC,+BAA+B,OAAO,OAAO,EAAE,CAAC,CAAC;QACrE,CAAC,CAAC;QAEF,OAAO,MAAM,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;IAC9B,CAAC;IAED;;OAEG;IACK,OAAO,CAAC,OAAY;QACxB,uDAAuD;QACvD,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;YAC9B,IAAI,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;gBAChD,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACxC,CAAC;YACD,OAAO,OAAO,CAAC;QACnB,CAAC;QAED,wEAAwE;QACxE,IAAI,OAAO,OAAO,KAAK,UAAU,EAAE,CAAC;YAChC,MAAM,OAAO,GAAG,cAAc,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC;gBACnD,CAAC,OAAO,CAAC,SAAS,IAAI,OAAO,OAAO,CAAC,SAAS,CAAC,MAAM,KAAK,UAAU,CAAC,CAAC;YAE1E,IAAI,OAAO,EAAE,CAAC;gBACV,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;oBACjB,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;gBACxC,CAAC;gBACD,OAAO,IAAK,OAAe,EAAE,CAAC;YAClC,CAAC;QACL,CAAC;QAED,OAAO,OAAO,CAAC;IACnB,CAAC;IAED;;OAEG;IACK,eAAe,CAAC,QAAe;QACnC,IAAI,SAAS,GAAU,EAAE,CAAC;QAE1B,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;YAC7B,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;gBAC9B,IAAI,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,EAAE,CAAC;oBACjC,SAAS,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;oBACxE,SAAS;gBACb,CAAC;gBAED,IAAI,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;oBACxB,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;oBACvC,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;wBAC1B,SAAS,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC,CAAC;oBACtD,CAAC;yBAAM,CAAC;wBACJ,SAAS,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,eAAe,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;oBACxD,CAAC;oBACD,SAAS;gBACb,CAAC;YACL,CAAC;YAED,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC5B,CAAC;QAED,OAAO,SAAS,CAAC;IACrB,CAAC;CACJ;AAjID,4BAiIC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,YAAY,CAAC;AAC3B,cAAc,WAAW,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./Middleware"), exports);
|
|
18
|
+
__exportStar(require("./Pipeline"), exports);
|
|
19
|
+
__exportStar(require("./Compose"), exports);
|
|
20
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,+CAA6B;AAC7B,6CAA2B;AAC3B,4CAA0B"}
|
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@arikajs/middleware",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Flexible, composable middleware system for the ArikaJS framework.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"scripts": {
|
|
9
|
+
"build": "tsc -p tsconfig.json",
|
|
10
|
+
"build:tests": "tsc -p tsconfig.test.json",
|
|
11
|
+
"clean": "rm -rf dist",
|
|
12
|
+
"prepare": "echo skip",
|
|
13
|
+
"test": "npm run build && npm run build:tests && node scripts/fix-test-imports.js && node --test 'dist/tests/**/*.test.js'",
|
|
14
|
+
"test:watch": "npm run build && npm run build:tests && node --test --watch 'dist/tests/**/*.test.js'"
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist"
|
|
18
|
+
],
|
|
19
|
+
"keywords": [
|
|
20
|
+
"arika",
|
|
21
|
+
"arika-js",
|
|
22
|
+
"framework",
|
|
23
|
+
"middleware",
|
|
24
|
+
"pipeline",
|
|
25
|
+
"onion"
|
|
26
|
+
],
|
|
27
|
+
"engines": {
|
|
28
|
+
"node": ">=20.0.0"
|
|
29
|
+
},
|
|
30
|
+
"repository": {
|
|
31
|
+
"type": "git",
|
|
32
|
+
"url": "git+https://github.com/arikajs/middleware.git"
|
|
33
|
+
},
|
|
34
|
+
"bugs": {
|
|
35
|
+
"url": "https://github.com/arikajs/middleware/issues"
|
|
36
|
+
},
|
|
37
|
+
"homepage": "https://github.com/arikajs/middleware#readme",
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"@arikajs/http": "file:../http"
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"@types/node": "^20.11.24",
|
|
43
|
+
"typescript": "^5.3.3"
|
|
44
|
+
},
|
|
45
|
+
"author": "Prakash Tank"
|
|
46
|
+
}
|