@aetherframework/middleware 1.0.2
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/.env.example +88 -0
- package/LICENSE +21 -0
- package/README.md +693 -0
- package/docs/readme/README.md +679 -0
- package/docs/readme/README_zh.md +680 -0
- package/examples/advanced-router-demo.js +119 -0
- package/examples/advanced-server.js +272 -0
- package/examples/basic-server.js +134 -0
- package/examples/benchmark.js +85 -0
- package/examples/router-demo.js +369 -0
- package/index.js +67 -0
- package/package.json +59 -0
- package/src/core/AetherCompiler.js +118 -0
- package/src/core/AetherContext.js +242 -0
- package/src/core/AetherPipeline.js +375 -0
- package/src/core/AetherRouter.js +347 -0
- package/src/core/AetherStore.js +204 -0
- package/src/middleware/body-parser.js +299 -0
- package/src/middleware/compression.js +248 -0
- package/src/middleware/cors.js +162 -0
- package/src/middleware/json.js +214 -0
- package/src/middleware/jwt.js +929 -0
- package/src/middleware/params.js +227 -0
- package/src/middleware/rate-limit.js +167 -0
- package/src/middleware/router.js +36 -0
- package/src/middleware/security.js +116 -0
- package/src/middleware/session.js +167 -0
- package/src/utils/atomic-ops.js +127 -0
- package/src/utils/env-loader.js +128 -0
- package/src/utils/memory-pool.js +93 -0
|
@@ -0,0 +1,369 @@
|
|
|
1
|
+
// examples/router-demo.js
|
|
2
|
+
import { AetherPipeline, middleware } from '../index.js';
|
|
3
|
+
|
|
4
|
+
// Create application instance
|
|
5
|
+
const app = new AetherPipeline();
|
|
6
|
+
|
|
7
|
+
// Use global middlewares
|
|
8
|
+
app.use(middleware.cors());
|
|
9
|
+
app.use(middleware.security());
|
|
10
|
+
app.use(middleware.bodyParser());
|
|
11
|
+
app.use(middleware.json());
|
|
12
|
+
|
|
13
|
+
// DEBUG: Check what middleware.router contains
|
|
14
|
+
console.log('Debug: middleware.router type:', typeof middleware.router);
|
|
15
|
+
console.log('Debug: middleware.router keys:', Object.keys(middleware.router || {}));
|
|
16
|
+
|
|
17
|
+
// IMPORTANT FIX: The issue is that middleware.router is the createRouterMiddleware function
|
|
18
|
+
// According to router.js, it exports both createRouterMiddleware and AetherRouter
|
|
19
|
+
// We need to access the Router class from the exported object
|
|
20
|
+
|
|
21
|
+
// Create router instance - CORRECT APPROACH
|
|
22
|
+
let router;
|
|
23
|
+
|
|
24
|
+
// Approach 1: Check if AetherRouter is available as a property
|
|
25
|
+
if (middleware.router && middleware.router.AetherRouter) {
|
|
26
|
+
// Use the AetherRouter class from the exported object
|
|
27
|
+
const AetherRouter = middleware.router.AetherRouter;
|
|
28
|
+
router = new AetherRouter();
|
|
29
|
+
console.log('Router created using middleware.router.AetherRouter constructor');
|
|
30
|
+
}
|
|
31
|
+
// Approach 2: Check if createRouterMiddleware has Router property
|
|
32
|
+
else if (middleware.router && middleware.router.Router) {
|
|
33
|
+
// Use the Router property attached to createRouterMiddleware
|
|
34
|
+
router = new middleware.router.Router();
|
|
35
|
+
console.log('Router created using middleware.router.Router()');
|
|
36
|
+
}
|
|
37
|
+
// Approach 3: Check if middleware.router itself is the AetherRouter class
|
|
38
|
+
else if (typeof middleware.router === 'function' && middleware.router.prototype && middleware.router.prototype.get) {
|
|
39
|
+
// middleware.router is the AetherRouter class itself
|
|
40
|
+
router = new middleware.router();
|
|
41
|
+
console.log('Router created using middleware.router() as constructor');
|
|
42
|
+
}
|
|
43
|
+
// Approach 4: Last resort - check the actual exports
|
|
44
|
+
else {
|
|
45
|
+
console.error('Cannot create router instance. Checking exports...');
|
|
46
|
+
|
|
47
|
+
// Try to import AetherRouter directly if possible
|
|
48
|
+
try {
|
|
49
|
+
// Based on router.js exports, we should have access to AetherRouter
|
|
50
|
+
// Let's check if it's available in the middleware.router object
|
|
51
|
+
if (middleware.router && typeof middleware.router === 'object') {
|
|
52
|
+
// The exports might be structured differently
|
|
53
|
+
for (const key in middleware.router) {
|
|
54
|
+
console.log(`Export key: ${key}, type: ${typeof middleware.router[key]}`);
|
|
55
|
+
if (key === 'AetherRouter' || key === 'Router') {
|
|
56
|
+
const RouterClass = middleware.router[key];
|
|
57
|
+
if (typeof RouterClass === 'function') {
|
|
58
|
+
router = new RouterClass();
|
|
59
|
+
console.log(`Router created using middleware.router.${key}`);
|
|
60
|
+
break;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// If still no router, create a fallback
|
|
67
|
+
if (!router) {
|
|
68
|
+
console.error('Creating fallback router');
|
|
69
|
+
router = {
|
|
70
|
+
routes: new Map(),
|
|
71
|
+
get: function(path, handler) {
|
|
72
|
+
this.routes.set(`GET:${path}`, handler);
|
|
73
|
+
return this;
|
|
74
|
+
},
|
|
75
|
+
post: function(path, handler) {
|
|
76
|
+
this.routes.set(`POST:${path}`, handler);
|
|
77
|
+
return this;
|
|
78
|
+
},
|
|
79
|
+
middleware: function() {
|
|
80
|
+
return async (ctx, next) => {
|
|
81
|
+
const routeKey = `${ctx.method}:${ctx.url}`;
|
|
82
|
+
const handler = this.routes.get(routeKey);
|
|
83
|
+
if (handler) {
|
|
84
|
+
await handler(ctx);
|
|
85
|
+
} else if (typeof next === 'function') {
|
|
86
|
+
await next();
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
} catch (error) {
|
|
93
|
+
console.error('Error creating router:', error);
|
|
94
|
+
throw error;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// ========== BASIC ROUTES ==========
|
|
99
|
+
// Check if router.get exists before using it
|
|
100
|
+
if (typeof router.get === 'function') {
|
|
101
|
+
router.get("/", (ctx) => {
|
|
102
|
+
ctx.json({ message: "Welcome to AetherJS API" });
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
// Path parameters - Use getState for query parameters
|
|
106
|
+
router.get("/users/:id", (ctx) => {
|
|
107
|
+
// Use getState to access query parameters instead of direct ctx.query
|
|
108
|
+
const query = ctx.getState("query") || {};
|
|
109
|
+
ctx.json({
|
|
110
|
+
userId: ctx.params.id,
|
|
111
|
+
query: query // Supports &id=1&name=test&sort=asc
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
// Query parameters - Use getState for query parameters
|
|
116
|
+
router.get("/search", (ctx) => {
|
|
117
|
+
const query = ctx.getState("query") || {};
|
|
118
|
+
const { q, page = 1, limit = 10, sort = "desc" } = query;
|
|
119
|
+
ctx.json({
|
|
120
|
+
query: q,
|
|
121
|
+
page: parseInt(page),
|
|
122
|
+
limit: parseInt(limit),
|
|
123
|
+
sort: sort
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
// POST with body parsing
|
|
128
|
+
router.post("/users", (ctx) => {
|
|
129
|
+
const userData = ctx.getState("parsedBody");
|
|
130
|
+
ctx.json({
|
|
131
|
+
success: true,
|
|
132
|
+
data: userData,
|
|
133
|
+
created: new Date().toISOString()
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
} else {
|
|
137
|
+
console.error('router.get() method not available. Router may not be properly initialized.');
|
|
138
|
+
throw new Error('Router not properly initialized');
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// ========== ROUTE GROUPING ==========
|
|
142
|
+
// Check if router.group exists before using it
|
|
143
|
+
if (typeof router.group === 'function') {
|
|
144
|
+
router.group("/api", (api) => {
|
|
145
|
+
// /api/users
|
|
146
|
+
api.get("/users", (ctx) => {
|
|
147
|
+
ctx.json({ users: [] });
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
// /api/users/:id
|
|
151
|
+
api.get("/users/:id", (ctx) => {
|
|
152
|
+
ctx.json({ user: { id: ctx.params.id } });
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
// Nested grouping
|
|
156
|
+
api.group("/v1", (v1) => {
|
|
157
|
+
// /api/v1/products
|
|
158
|
+
v1.get("/products", (ctx) => {
|
|
159
|
+
ctx.json({ products: [] });
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
// /api/v1/products/:id
|
|
163
|
+
v1.get("/products/:id", (ctx) => {
|
|
164
|
+
ctx.json({ productId: ctx.params.id });
|
|
165
|
+
});
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
} else {
|
|
169
|
+
console.log('Router.group() method not available, using direct routes instead');
|
|
170
|
+
// Fallback: Define routes directly without grouping
|
|
171
|
+
router.get("/api/users", (ctx) => {
|
|
172
|
+
ctx.json({ users: [] });
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
router.get("/api/users/:id", (ctx) => {
|
|
176
|
+
ctx.json({ user: { id: ctx.params.id } });
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
router.get("/api/v1/products", (ctx) => {
|
|
180
|
+
ctx.json({ products: [] });
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
router.get("/api/v1/products/:id", (ctx) => {
|
|
184
|
+
ctx.json({ productId: ctx.params.id });
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// ========== API VERSIONING ==========
|
|
189
|
+
// Check if version method exists before using it
|
|
190
|
+
// If version() doesn't exist, use group() method as alternative
|
|
191
|
+
if (typeof router.version === 'function') {
|
|
192
|
+
router.version("1", (v1) => {
|
|
193
|
+
v1.get("/users", (ctx) => {
|
|
194
|
+
ctx.json({ version: "v1", users: [] });
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
v1.post("/users", (ctx) => {
|
|
198
|
+
ctx.json({ version: "v1", created: true });
|
|
199
|
+
});
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
router.version("2", (v2) => {
|
|
203
|
+
v2.get("/users", (ctx) => {
|
|
204
|
+
ctx.json({
|
|
205
|
+
version: "v2",
|
|
206
|
+
users: [],
|
|
207
|
+
features: ["enhanced", "pagination"]
|
|
208
|
+
});
|
|
209
|
+
});
|
|
210
|
+
});
|
|
211
|
+
} else {
|
|
212
|
+
console.log('Router.version() method not available, using group() for versioning');
|
|
213
|
+
// Alternative: Use group method for versioning
|
|
214
|
+
// First check if group method is available
|
|
215
|
+
if (typeof router.group === 'function') {
|
|
216
|
+
router.group("/v1", (v1) => {
|
|
217
|
+
v1.get("/users", (ctx) => {
|
|
218
|
+
ctx.json({ version: "v1", users: [] });
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
v1.post("/users", (ctx) => {
|
|
222
|
+
ctx.json({ version: "v1", created: true });
|
|
223
|
+
});
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
router.group("/v2", (v2) => {
|
|
227
|
+
v2.get("/users", (ctx) => {
|
|
228
|
+
ctx.json({
|
|
229
|
+
version: "v2",
|
|
230
|
+
users: [],
|
|
231
|
+
features: ["enhanced", "pagination"]
|
|
232
|
+
});
|
|
233
|
+
});
|
|
234
|
+
});
|
|
235
|
+
} else {
|
|
236
|
+
// If group is also not available, define routes directly
|
|
237
|
+
router.get("/v1/users", (ctx) => {
|
|
238
|
+
ctx.json({ version: "v1", users: [] });
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
router.post("/v1/users", (ctx) => {
|
|
242
|
+
ctx.json({ version: "v1", created: true });
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
router.get("/v2/users", (ctx) => {
|
|
246
|
+
ctx.json({
|
|
247
|
+
version: "v2",
|
|
248
|
+
users: [],
|
|
249
|
+
features: ["enhanced", "pagination"]
|
|
250
|
+
});
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// ========== ROUTE MIDDLEWARE ==========
|
|
256
|
+
const authMiddleware = async (ctx, next) => {
|
|
257
|
+
const token = ctx.getHeader("authorization");
|
|
258
|
+
if (!token) {
|
|
259
|
+
return ctx.setStatus(401).json({ error: "Unauthorized" });
|
|
260
|
+
}
|
|
261
|
+
await next();
|
|
262
|
+
};
|
|
263
|
+
|
|
264
|
+
const loggerMiddleware = async (ctx, next) => {
|
|
265
|
+
console.log(`[${new Date().toISOString()}] ${ctx.method} ${ctx.url}`);
|
|
266
|
+
await next();
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
// Apply middleware to specific routes
|
|
270
|
+
router.get("/admin/dashboard", authMiddleware, loggerMiddleware, (ctx) => {
|
|
271
|
+
ctx.json({ admin: true, data: "Sensitive information" });
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
// ========== WILDCARD ROUTES ==========
|
|
275
|
+
router.get("/files/*", (ctx) => {
|
|
276
|
+
const filePath = ctx.params["0"]; // Wildcard parameter
|
|
277
|
+
ctx.json({ file: filePath });
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
// ========== OPTIONAL PARAMETERS ==========
|
|
281
|
+
router.get("/posts/:id?", (ctx) => {
|
|
282
|
+
if (ctx.params.id) {
|
|
283
|
+
ctx.json({ post: ctx.params.id });
|
|
284
|
+
} else {
|
|
285
|
+
ctx.json({ posts: [] });
|
|
286
|
+
}
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
// ========== REGEX CONSTRAINTS ==========
|
|
290
|
+
router.get("/users/:id(\\d+)", (ctx) => {
|
|
291
|
+
// Only matches numeric IDs
|
|
292
|
+
ctx.json({ userId: parseInt(ctx.params.id) });
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
// ========== MULTIPLE PARAMETERS ==========
|
|
296
|
+
router.get("/products/:category/:id", (ctx) => {
|
|
297
|
+
const query = ctx.getState("query") || {};
|
|
298
|
+
ctx.json({
|
|
299
|
+
category: ctx.params.category,
|
|
300
|
+
productId: ctx.params.id,
|
|
301
|
+
query: query
|
|
302
|
+
});
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
// ========== ARRAY QUERY PARAMETERS ==========
|
|
306
|
+
// Supports: /api/filter?tags=js&tags=node&tags=express
|
|
307
|
+
router.get("/api/filter", (ctx) => {
|
|
308
|
+
const query = ctx.getState("query") || {};
|
|
309
|
+
const { tags = [], page = 1 } = query;
|
|
310
|
+
ctx.json({
|
|
311
|
+
tags: Array.isArray(tags) ? tags : [tags],
|
|
312
|
+
page: parseInt(page)
|
|
313
|
+
});
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
// Add router middleware to pipeline
|
|
317
|
+
if (typeof router.middleware === 'function') {
|
|
318
|
+
app.use(router.middleware());
|
|
319
|
+
} else {
|
|
320
|
+
console.error('Router.middleware() method not available');
|
|
321
|
+
// Fallback: Add routes directly to pipeline
|
|
322
|
+
app.use(async (ctx, next) => {
|
|
323
|
+
const routeKey = `${ctx.method}:${ctx.url}`;
|
|
324
|
+
const handler = router.routes?.get(routeKey);
|
|
325
|
+
if (handler) {
|
|
326
|
+
await handler(ctx);
|
|
327
|
+
} else if (typeof next === 'function') {
|
|
328
|
+
await next();
|
|
329
|
+
}
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// ========== ERROR HANDLING ==========
|
|
334
|
+
app.use(async (ctx) => {
|
|
335
|
+
if (!ctx.isTerminated()) {
|
|
336
|
+
ctx.setStatus(404).json({
|
|
337
|
+
error: "Not Found",
|
|
338
|
+
message: `Cannot ${ctx.method} ${ctx.url}`,
|
|
339
|
+
timestamp: new Date().toISOString()
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
// Start server
|
|
345
|
+
import http from "http";
|
|
346
|
+
|
|
347
|
+
const server = http.createServer(async (req, res) => {
|
|
348
|
+
await app.handle(req, res);
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
server.listen(3000, () => {
|
|
352
|
+
console.log("🚀 AetherJS Server running on http://localhost:3000");
|
|
353
|
+
console.log("📋 Available routes:");
|
|
354
|
+
|
|
355
|
+
// Check if getRoutes method exists
|
|
356
|
+
if (typeof router.getRoutes === 'function') {
|
|
357
|
+
console.log(router.getRoutes());
|
|
358
|
+
} else if (router.routes) {
|
|
359
|
+
// Fallback: Display routes from router.routes Map
|
|
360
|
+
const routes = [];
|
|
361
|
+
router.routes.forEach((handler, key) => {
|
|
362
|
+
const [method, path] = key.split(':');
|
|
363
|
+
routes.push({ method, path });
|
|
364
|
+
});
|
|
365
|
+
console.log(routes);
|
|
366
|
+
} else {
|
|
367
|
+
console.log('No route information available');
|
|
368
|
+
}
|
|
369
|
+
});
|
package/index.js
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
// index.js - ES Module version (updated)
|
|
2
|
+
// --- Core Components ---
|
|
3
|
+
import AetherContext from './src/core/AetherContext.js';
|
|
4
|
+
import AetherPipeline from './src/core/AetherPipeline.js';
|
|
5
|
+
import AetherStore from './src/core/AetherStore.js';
|
|
6
|
+
import AetherCompiler from './src/core/AetherCompiler.js';
|
|
7
|
+
import AetherRouter from './src/core/AetherRouter.js'; // Added
|
|
8
|
+
|
|
9
|
+
// --- Utilities ---
|
|
10
|
+
import envLoader from './src/utils/env-loader.js';
|
|
11
|
+
import memoryPool from './src/utils/memory-pool.js';
|
|
12
|
+
import atomicOps from './src/utils/atomic-ops.js';
|
|
13
|
+
|
|
14
|
+
// --- Middleware Factories ---
|
|
15
|
+
import createRateLimit from './src/middleware/rate-limit.js';
|
|
16
|
+
import createSecurity from './src/middleware/security.js';
|
|
17
|
+
import createBodyParser from './src/middleware/body-parser.js';
|
|
18
|
+
import createCors from './src/middleware/cors.js';
|
|
19
|
+
import createCompression from './src/middleware/compression.js';
|
|
20
|
+
import createJwt from './src/middleware/jwt.js';
|
|
21
|
+
import SessionManager from './src/middleware/session.js';
|
|
22
|
+
import createJson from './src/middleware/json.js';
|
|
23
|
+
|
|
24
|
+
// 修复:使用命名导入而不是默认导入
|
|
25
|
+
import { createRouter } from './src/middleware/router.js'; // 改为命名导入
|
|
26
|
+
import createParamsMiddleware from './src/middleware/params.js';
|
|
27
|
+
|
|
28
|
+
// Export all components
|
|
29
|
+
export {
|
|
30
|
+
AetherContext,
|
|
31
|
+
AetherPipeline,
|
|
32
|
+
AetherStore,
|
|
33
|
+
AetherCompiler,
|
|
34
|
+
AetherRouter // Added
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
// Export utility functions
|
|
38
|
+
export const utils = {
|
|
39
|
+
envLoader,
|
|
40
|
+
memoryPool,
|
|
41
|
+
atomicOps
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
// Export middleware factory functions
|
|
45
|
+
export const middleware = {
|
|
46
|
+
rateLimit: createRateLimit,
|
|
47
|
+
security: createSecurity,
|
|
48
|
+
bodyParser: createBodyParser,
|
|
49
|
+
cors: createCors,
|
|
50
|
+
compression: createCompression,
|
|
51
|
+
jwt: createJwt,
|
|
52
|
+
session: SessionManager,
|
|
53
|
+
json: createJson,
|
|
54
|
+
router: createRouter, // 这里使用导入的 createRouter
|
|
55
|
+
params: createParamsMiddleware
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
// Default export
|
|
59
|
+
export default {
|
|
60
|
+
AetherContext,
|
|
61
|
+
AetherPipeline,
|
|
62
|
+
AetherStore,
|
|
63
|
+
AetherCompiler,
|
|
64
|
+
AetherRouter,
|
|
65
|
+
utils,
|
|
66
|
+
middleware
|
|
67
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@aetherframework/middleware",
|
|
3
|
+
"version": "1.0.2",
|
|
4
|
+
"description": "Ultra-performance, framework-agnostic middleware system for Aether Framework",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"start:basic": "node examples/basic-server.js",
|
|
9
|
+
"start:advanced": "node examples/advanced-server.js",
|
|
10
|
+
"test": "node --test tests/**/*.test.js",
|
|
11
|
+
"benchmark": "node examples/benchmark.js",
|
|
12
|
+
"lint": "eslint src/",
|
|
13
|
+
"format": "prettier --write \"src/**/*.js\""
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"middleware",
|
|
17
|
+
"aetherjs",
|
|
18
|
+
"performance",
|
|
19
|
+
"framework-agnostic",
|
|
20
|
+
"http",
|
|
21
|
+
"server"
|
|
22
|
+
],
|
|
23
|
+
"author": "Aether Framework Team",
|
|
24
|
+
"license": "MIT",
|
|
25
|
+
"repository": {
|
|
26
|
+
"type": "git",
|
|
27
|
+
"url": "https://github.com/aetherjs/aetherframework-middleware.git"
|
|
28
|
+
},
|
|
29
|
+
"bugs": {
|
|
30
|
+
"url": "https://github.com/aetherjs/aetherframework-middleware/issues",
|
|
31
|
+
"email": "support@aetherjs.org"
|
|
32
|
+
},
|
|
33
|
+
"homepage": "https://www.aetherjs.org",
|
|
34
|
+
"engines": {
|
|
35
|
+
"node": ">=16.0.0"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"autocannon": "^7.0.0",
|
|
39
|
+
"eslint": "^8.0.0",
|
|
40
|
+
"jest": "^29.0.0",
|
|
41
|
+
"prettier": "^3.0.0",
|
|
42
|
+
"supertest": "^6.0.0"
|
|
43
|
+
},
|
|
44
|
+
"jest": {
|
|
45
|
+
"testEnvironment": "node",
|
|
46
|
+
"collectCoverageFrom": [
|
|
47
|
+
"src/**/*.js",
|
|
48
|
+
"!src/**/*.test.js"
|
|
49
|
+
],
|
|
50
|
+
"coverageThreshold": {
|
|
51
|
+
"global": {
|
|
52
|
+
"branches": 80,
|
|
53
|
+
"functions": 80,
|
|
54
|
+
"lines": 80,
|
|
55
|
+
"statements": 80
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license MIT
|
|
3
|
+
* Copyright (c) 2026-present AetherFramework Contributors.
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
* @module @aetherframework/middleware/core/AetherComplier
|
|
6
|
+
*/
|
|
7
|
+
class AetherCompiler {
|
|
8
|
+
constructor(options = {}) {
|
|
9
|
+
this.cache = new Map();
|
|
10
|
+
this.maxCacheSize = options.maxCacheSize || 128;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Compile middleware chain into high-speed execution unit
|
|
15
|
+
*/
|
|
16
|
+
compile(middlewares) {
|
|
17
|
+
const cacheKey = this._generateCacheKey(middlewares);
|
|
18
|
+
if (this.cache.has(cacheKey)) {
|
|
19
|
+
return this.cache.get(cacheKey);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const compiledFn = this._compileChain(middlewares);
|
|
23
|
+
|
|
24
|
+
if (this.cache.size >= this.maxCacheSize) {
|
|
25
|
+
const firstKey = this.cache.keys().next().value;
|
|
26
|
+
this.cache.delete(firstKey);
|
|
27
|
+
}
|
|
28
|
+
this.cache.set(cacheKey, compiledFn);
|
|
29
|
+
|
|
30
|
+
return compiledFn;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
_generateCacheKey(middlewares) {
|
|
34
|
+
// Generate absolutely precise and fast cache keys using unique reference identifiers
|
|
35
|
+
let key = "";
|
|
36
|
+
for (let i = 0; i < middlewares.length; i++) {
|
|
37
|
+
key +=
|
|
38
|
+
(middlewares[i]._id ||
|
|
39
|
+
(middlewares[i]._id = Math.random().toString(36).substring(2))) + "|";
|
|
40
|
+
}
|
|
41
|
+
return key;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Ultimate compilation core: Completely strip signal closure allocation, use lossless index state machine pointers for iteration
|
|
46
|
+
*/
|
|
47
|
+
_compileChain(middlewares) {
|
|
48
|
+
const len = middlewares.length;
|
|
49
|
+
|
|
50
|
+
if (len === 0) {
|
|
51
|
+
return function (context) {
|
|
52
|
+
context._finalize();
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Check if the entire chain is purely synchronous (no async/await/promise)
|
|
57
|
+
const isAllSync = middlewares.every((mw) => {
|
|
58
|
+
const str = mw.toString();
|
|
59
|
+
return (
|
|
60
|
+
!str.includes("async ") &&
|
|
61
|
+
!str.includes(".then") &&
|
|
62
|
+
!str.includes("await ")
|
|
63
|
+
);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
// Path 1: Fully synchronous chain → Use the fastest flat `for` loop sequential execution with no extra function stack depth
|
|
67
|
+
if (isAllSync) {
|
|
68
|
+
return function executePureSyncChain(context) {
|
|
69
|
+
for (let i = 0; i < len; i++) {
|
|
70
|
+
middlewares[i](context, null); // No need to care about traditional next parameter passing in synchronous state
|
|
71
|
+
if (context.isTerminated()) return;
|
|
72
|
+
}
|
|
73
|
+
context._finalize();
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Path 2: Contains asynchronous chain → Strip closures. Achieve zero object allocation iteration by dynamically simulating 'state pointers' at runtime
|
|
78
|
+
return function executeAsyncChain(context) {
|
|
79
|
+
let index = 0;
|
|
80
|
+
|
|
81
|
+
// Reuse single-stack function, never allocate closures like `() => next()` for each middleware
|
|
82
|
+
function next() {
|
|
83
|
+
if (index >= len) {
|
|
84
|
+
if (!context.isTerminated()) context._finalize();
|
|
85
|
+
return Promise.resolve();
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (context.isTerminated()) return Promise.resolve();
|
|
89
|
+
|
|
90
|
+
const currMiddleware = middlewares[index++];
|
|
91
|
+
try {
|
|
92
|
+
const result = currMiddleware(context, next);
|
|
93
|
+
|
|
94
|
+
// Compatibility handling: If it's a Promise, mount subsequent chain; if synchronous return, directly accelerate progression
|
|
95
|
+
if (result && typeof result.then === "function") {
|
|
96
|
+
return result.then(next);
|
|
97
|
+
}
|
|
98
|
+
return next();
|
|
99
|
+
} catch (err) {
|
|
100
|
+
return Promise.reject(err);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return next();
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
clearCache() {
|
|
109
|
+
this.cache.clear();
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Maintain factory export format
|
|
114
|
+
function createAetherCompiler(options = {}) {
|
|
115
|
+
return new AetherCompiler(options);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export default createAetherCompiler;
|