@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.
@@ -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;