aetherframework-middleware 1.0.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.
@@ -0,0 +1,272 @@
1
+ /**
2
+ * @license MIT
3
+ * Copyright (c) 2026-present, AetherFramework Contributors.
4
+ * Response compression middleware for AetherFramework framework.
5
+ * Supports gzip, deflate, and brotli compression with zero-copy operations.
6
+ */
7
+
8
+ import http from "http";
9
+ import { AetherPipeline } from "../index.js";
10
+
11
+ // Import optimized middleware
12
+ import security from "../src/middleware/security.js";
13
+ import rateLimit from "../src/middleware/rate-limit.js";
14
+ import cors from "../src/middleware/cors.js";
15
+ import jwt from "../src/middleware/jwt.js";
16
+ import bodyParser from "../src/middleware/body-parser.js";
17
+ import compression from "../src/middleware/compression.js";
18
+ import SessionManager from "../src/middleware/session.js";
19
+
20
+ // Load configuration
21
+ const config = {
22
+ jwtSecret: process.env.JWT_SECRET || "dev-secret",
23
+ port: process.env.PORT || 3001,
24
+ sessionSecret: process.env.SESSION_SECRET || "aether-session-secret",
25
+ };
26
+
27
+ // Initialize Aether pipeline
28
+ const pipeline = new AetherPipeline();
29
+
30
+ // ==========================================================
31
+ // Middleware adapter: Convert standard (ctx, next) middleware to AetherPipeline (ctx, signal) format
32
+ // ==========================================================
33
+ function adaptMiddleware(standardMiddleware) {
34
+ return async function adaptedMiddleware(ctx, signal) {
35
+ // Define a standard next function that calls signal.next()
36
+ const next = async () => {
37
+ if (signal && typeof signal.next === "function") {
38
+ return await signal.next();
39
+ }
40
+ };
41
+
42
+ // Call the original middleware with ctx and the new next function
43
+ // Note: Some middleware may not return a Promise, so use await to ensure execution completes
44
+ try {
45
+ const result = standardMiddleware(ctx, next);
46
+ if (result && typeof result.then === "function") {
47
+ await result;
48
+ }
49
+ } catch (error) {
50
+ console.error("Middleware error:", error);
51
+ // Optionally handle errors here or let the global error handler catch them
52
+ }
53
+ };
54
+ }
55
+
56
+ // ==========================================================
57
+ // Pre-initialize all middleware (never create in request callbacks)
58
+ // ==========================================================
59
+ const securityMiddleware = security({
60
+ hsts: { enabled: true, maxAge: 31536000 },
61
+ noSniff: { enabled: true },
62
+ frameguard: { enabled: true, action: "DENY" },
63
+ });
64
+
65
+ const corsMiddleware = cors({
66
+ origin: "*",
67
+ credentials: true,
68
+ });
69
+
70
+ const compressionMiddleware = compression({
71
+ enabled: process.env.COMPRESSION_ENABLED === "true",
72
+ threshold: parseInt(process.env.COMPRESSION_THRESHOLD) || 1024,
73
+ gzip: process.env.COMPRESSION_GZIP !== "false",
74
+ deflate: process.env.COMPRESSION_DEFLATE === "true",
75
+ brotli: process.env.COMPRESSION_BROTLI === "true",
76
+ types: "application/json,text/plain",
77
+ });
78
+
79
+ const sessionManager = new SessionManager({
80
+ enabled: true,
81
+ secret: config.sessionSecret,
82
+ maxAge: parseInt(process.env.SESSION_MAX_AGE) || 86400000,
83
+ cookieName: "aether_session",
84
+ store: "memory",
85
+ });
86
+ const sessionMiddleware = sessionManager.middleware();
87
+
88
+ const rateLimitMiddleware = rateLimit({
89
+ windowMs: 15 * 60 * 1000,
90
+ max: 100,
91
+ enabled: true,
92
+ });
93
+
94
+ const bodyParserMiddleware = bodyParser({
95
+ json: { enabled: true, limit: "1mb" },
96
+ });
97
+
98
+ const jwtMiddlewareInstance = jwt({
99
+ secret: config.jwtSecret,
100
+ algorithms: ["HS256"],
101
+ });
102
+
103
+ // ==========================================================
104
+ // Mount middleware pipeline (explicitly pass control to next)
105
+ // ==========================================================
106
+
107
+ // 1. Security Headers
108
+ pipeline.use(securityMiddleware);
109
+
110
+ // 2. CORS
111
+ pipeline.use(corsMiddleware);
112
+
113
+ // 3. Response Compression
114
+ pipeline.use(compressionMiddleware);
115
+
116
+ // 4. Session Management
117
+ pipeline.use(sessionMiddleware);
118
+
119
+ // 5. Rate Limiting
120
+ pipeline.use(rateLimitMiddleware);
121
+
122
+ // 6. Body Parsing
123
+ pipeline.use(bodyParserMiddleware);
124
+
125
+ // 7. Public Routes
126
+ pipeline.use((ctx, next) => {
127
+ if (ctx.isTerminated() || ctx.res?.writableEnded) return;
128
+ if (ctx.url === "/public/info") {
129
+ ctx.setStatus(200);
130
+ ctx.json({ message: "This is public information" });
131
+ if (typeof ctx.terminate === "function") ctx.terminate();
132
+ return; // Endpoint reached, do not call next()
133
+ }
134
+ return next(); // Route not matched, must pass control
135
+ });
136
+
137
+ // 8. Session Example Route
138
+ pipeline.use((ctx, next) => {
139
+ if (ctx.isTerminated() || ctx.res?.writableEnded) return;
140
+
141
+ if (ctx.url === "/session/example") {
142
+ const visitCount = ctx.session?.get("visitCount") || 0;
143
+ ctx.session?.set("visitCount", visitCount + 1);
144
+ ctx.session?.set("lastVisit", new Date().toISOString());
145
+
146
+ ctx.setStatus(200);
147
+ ctx.json({
148
+ message: "Session example",
149
+ sessionId: ctx.state?.session?.id,
150
+ visitCount: visitCount + 1,
151
+ });
152
+ if (typeof ctx.terminate === "function") ctx.terminate();
153
+ return;
154
+ }
155
+ return next(); // Pass control
156
+ });
157
+
158
+ // 9. Login Route
159
+ pipeline.use((ctx, next) => {
160
+ if (ctx.isTerminated() || ctx.res?.writableEnded) return;
161
+
162
+ if (ctx.url === "/api/login" && ctx.method === "POST") {
163
+ const { username, password } = ctx._request?.body || ctx.body || {};
164
+
165
+ if (username === "admin" && password === "password") {
166
+ ctx.session?.set("user", {
167
+ id: 1,
168
+ username,
169
+ role: "admin",
170
+ loggedIn: true,
171
+ });
172
+ ctx.session?.save();
173
+
174
+ ctx.setStatus(200);
175
+ ctx.json({ message: "Login successful" });
176
+ } else {
177
+ ctx.setStatus(401);
178
+ ctx.json({ error: "Invalid credentials" });
179
+ }
180
+ if (typeof ctx.terminate === "function") ctx.terminate();
181
+ return;
182
+ }
183
+ return next(); // Pass control
184
+ });
185
+
186
+ // 10. Logout Route
187
+ pipeline.use((ctx, next) => {
188
+ if (ctx.isTerminated() || ctx.res?.writableEnded) return;
189
+
190
+ if (ctx.url === "/api/logout" && ctx.method === "POST") {
191
+ ctx.session?.destroy();
192
+ ctx.setStatus(200);
193
+ ctx.json({ message: "Logged out successfully" });
194
+ if (typeof ctx.terminate === "function") ctx.terminate();
195
+ return;
196
+ }
197
+ return next(); // Pass control
198
+ });
199
+
200
+ // 11. JWT Protection for /api/* routes
201
+ pipeline.use(async (ctx, next) => {
202
+ if (ctx.isTerminated() || ctx.res?.writableEnded) return;
203
+ if (ctx.url.startsWith("/api/")) {
204
+ // Standard parameter passing: pass Aether's next-level async dispatch pointer
205
+ await jwtMiddlewareInstance(ctx, next);
206
+ } else {
207
+ return next(); // Skip non-/api/ routes directly
208
+ }
209
+ });
210
+
211
+ // 12. Profile Route
212
+ pipeline.use((ctx, next) => {
213
+ if (ctx.isTerminated() || ctx.res?.writableEnded) return;
214
+ if (ctx.url === "/api/profile" && ctx.method === "GET") {
215
+ ctx.setStatus(200);
216
+ ctx.json({
217
+ user: { id: 1, name: "Mock User" },
218
+ message: "Access granted",
219
+ });
220
+ if (typeof ctx.terminate === "function") ctx.terminate();
221
+ return;
222
+ }
223
+ return next(); // Pass control
224
+ });
225
+
226
+ // 13. POST Example
227
+ pipeline.use((ctx, next) => {
228
+ if (ctx.isTerminated() || ctx.res?.writableEnded) return;
229
+
230
+ if (ctx.url === "/api/data" && ctx.method === "POST") {
231
+ const reqBody = ctx._request?.body || ctx.body;
232
+ ctx.setStatus(200);
233
+ ctx.json({
234
+ received: reqBody,
235
+ message: "Data created successfully",
236
+ });
237
+ if (typeof ctx.terminate === "function") ctx.terminate();
238
+ return;
239
+ }
240
+ return next(); // Pass control
241
+ });
242
+
243
+ // 14. Fallback 404
244
+ pipeline.use((ctx) => {
245
+ if (ctx.isTerminated() || ctx.res?.writableEnded) return;
246
+ ctx.setStatus(404);
247
+ ctx.json({ error: "Route not found" });
248
+ if (typeof ctx.terminate === "function") ctx.terminate();
249
+ });
250
+
251
+ // 15. Precompile for optimization
252
+ pipeline.precompile();
253
+
254
+ // 16. Create HTTP server
255
+ const server = http.createServer(async (req, res) => {
256
+ try {
257
+ await pipeline.handle(req, res);
258
+ } catch (err) {
259
+ console.error("Pipeline Error:", err);
260
+ if (!res.headersSent) {
261
+ res.statusCode = 500;
262
+ res.setHeader("Content-Type", "application/json; charset=utf-8");
263
+ res.setHeader("Access-Control-Allow-Origin", "*");
264
+ res.end(JSON.stringify({ error: "Internal Server Error" }));
265
+ }
266
+ }
267
+ });
268
+
269
+ // Start server
270
+ server.listen(config.port, () => {
271
+ console.log(`🔒 Advanced Server running on http://localhost:${config.port}`);
272
+ });
@@ -0,0 +1,134 @@
1
+ /**
2
+ * Simplified Advanced Server - Clean and Performant Edition
3
+ */
4
+ import http from "http";
5
+ import { AetherPipeline } from "../index.js";
6
+
7
+ // 1. Create pipeline
8
+ const pipeline = new AetherPipeline();
9
+
10
+ // 2. Basic middleware: Logging
11
+ const logger = (ctx) => {
12
+ console.log(`[${new Date().toISOString()}] ${ctx.method} ${ctx.url}`);
13
+ };
14
+ pipeline.use(logger);
15
+
16
+ // 3. Basic middleware: CORS headers
17
+ pipeline.use((ctx) => {
18
+ ctx.setHeader("Access-Control-Allow-Origin", "*");
19
+ ctx.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
20
+ ctx.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
21
+ });
22
+
23
+ // 4. Basic middleware: Security headers
24
+ pipeline.use((ctx) => {
25
+ ctx.setHeader("X-Content-Type-Options", "nosniff");
26
+ ctx.setHeader("X-Frame-Options", "DENY");
27
+ ctx.setHeader("X-XSS-Protection", "1; mode=block");
28
+ });
29
+
30
+ // 5. Route handling
31
+ pipeline.use((ctx) => {
32
+ if (ctx.url === "/health") {
33
+ ctx.setStatus(200);
34
+ ctx.setHeader("Content-Type", "application/json");
35
+ ctx.body = JSON.stringify({
36
+ status: "ok",
37
+ timestamp: Date.now(),
38
+ server: "Simplified AetherJS"
39
+ });
40
+ ctx._isHandled = true;
41
+ return true;
42
+ }
43
+ });
44
+
45
+ pipeline.use((ctx) => {
46
+ if (ctx.url === "/public/info") {
47
+ ctx.setStatus(200);
48
+ ctx.setHeader("Content-Type", "application/json");
49
+ ctx.body = JSON.stringify({
50
+ message: "This is public information",
51
+ version: "1.0.0",
52
+ endpoints: ["/health", "/public/info", "/api/data"]
53
+ });
54
+ ctx._isHandled = true;
55
+ return true;
56
+ }
57
+ });
58
+
59
+ pipeline.use((ctx) => {
60
+ if (ctx.url === "/api/data" && ctx.method === "GET") {
61
+ ctx.setStatus(200);
62
+ ctx.setHeader("Content-Type", "application/json");
63
+ ctx.body = JSON.stringify({
64
+ data: [1, 2, 3, 4, 5],
65
+ message: "Sample API data",
66
+ timestamp: Date.now()
67
+ });
68
+ ctx._isHandled = true;
69
+ return true;
70
+ }
71
+ });
72
+
73
+ pipeline.use((ctx) => {
74
+ if (ctx.url === "/api/data" && ctx.method === "POST") {
75
+ // Simple POST request handling
76
+ let body = "";
77
+ ctx.req.on("data", chunk => {
78
+ body += chunk.toString();
79
+ });
80
+ ctx.req.on("end", () => {
81
+ ctx.setStatus(201);
82
+ ctx.setHeader("Content-Type", "application/json");
83
+ ctx.body = JSON.stringify({
84
+ received: body ? JSON.parse(body) : null,
85
+ message: "Data received successfully",
86
+ id: Date.now()
87
+ });
88
+ });
89
+ ctx._isHandled = true;
90
+ return true;
91
+ }
92
+ });
93
+
94
+ // 6. 404 handling
95
+ pipeline.use((ctx) => {
96
+ if (ctx._isHandled || ctx.statusCode === 200 || ctx.res?.statusCode === 200) {
97
+ return;
98
+ }
99
+ ctx.setStatus(404);
100
+ ctx.setHeader("Content-Type", "application/json");
101
+ ctx.body = JSON.stringify({
102
+ error: "Not Found",
103
+ path: ctx.url,
104
+ method: ctx.method
105
+ });
106
+ });
107
+
108
+ // 7. Precompile for optimization
109
+ pipeline.precompile();
110
+
111
+ // 8. Create HTTP server
112
+ const server = http.createServer(async (req, res) => {
113
+ try {
114
+ await pipeline.handle(req, res);
115
+ } catch (err) {
116
+ console.error("Pipeline Error:", err);
117
+ if (!res.headersSent) {
118
+ res.statusCode = 500;
119
+ res.setHeader("Content-Type", "application/json");
120
+ res.end(JSON.stringify({ error: "Internal Server Error" }));
121
+ }
122
+ }
123
+ });
124
+
125
+ // 9. Start server
126
+ const PORT = process.env.PORT || 3001;
127
+ server.listen(PORT, () => {
128
+ console.log(`🚀 Simplified Advanced Server running on http://localhost:${PORT}`);
129
+ console.log(`📊 Available endpoints:`);
130
+ console.log(` GET /health - Health check`);
131
+ console.log(` GET /public/info - Public information`);
132
+ console.log(` GET /api/data - Get sample data`);
133
+ console.log(` POST /api/data - Submit data`);
134
+ });
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Simple Benchmark Script
3
+ * Compares raw HTTP vs Aether Pipeline overhead.
4
+ */
5
+ import http from 'http';
6
+ import { AetherPipeline, AetherContext } from '../index.js';
7
+ import json from "../src/middleware/json.js";
8
+
9
+ const ITERATIONS = 10000;
10
+
11
+ // 1. Raw HTTP Server
12
+ const rawServer = http.createServer((req, res) => {
13
+ res.writeHead(200, { 'Content-Type': 'application/json' });
14
+ res.end(JSON.stringify({ status: 'ok' }));
15
+ });
16
+
17
+ // 2. Aether Server
18
+ const pipeline = new AetherPipeline();
19
+ pipeline.use(json());
20
+ pipeline.use(async (ctx, signal) => {
21
+ ctx.body = { status: 'ok' };
22
+ await signal.next();
23
+ });
24
+
25
+ const aetherServer = http.createServer(async (req, res) => {
26
+
27
+ try {
28
+ if (!req || !res) {
29
+ console.error('ERROR: req or res is undefined');
30
+ res.writeHead(500);
31
+ res.end('Internal Server Error');
32
+ return;
33
+ }
34
+
35
+ await pipeline.handle(req, res);
36
+ } catch (error) {
37
+ console.error('Pipeline execution error:', error);
38
+ if (!res.headersSent) {
39
+ res.writeHead(500);
40
+ res.end('Internal Server Error');
41
+ }
42
+ }
43
+ });
44
+
45
+ async function runBenchmark(server, name) {
46
+ return new Promise((resolve) => {
47
+ server.listen(0, () => {
48
+ const port = server.address().port;
49
+ const start = Date.now();
50
+ let completed = 0;
51
+
52
+ function makeRequest() {
53
+ http.get(`http://localhost:${port}/`, (res) => {
54
+ res.resume();
55
+ res.on('end', () => {
56
+ completed++;
57
+ if (completed < ITERATIONS) {
58
+ makeRequest();
59
+ } else {
60
+ const duration = Date.now() - start;
61
+ const rps = (ITERATIONS / duration) * 1000;
62
+ console.log(`${name}: ${duration}ms for ${ITERATIONS} requests (${rps.toFixed(0)} req/sec)`);
63
+ server.close(() => resolve());
64
+ }
65
+ });
66
+ }).on('error', (e) => {
67
+ console.error(e);
68
+ server.close(() => resolve());
69
+ });
70
+ }
71
+
72
+ makeRequest();
73
+ });
74
+ });
75
+ }
76
+
77
+ async function main() {
78
+
79
+
80
+ await runBenchmark(rawServer, 'Raw HTTP');
81
+ await runBenchmark(aetherServer, 'Aether Pipeline');
82
+
83
+ }
84
+
85
+ main().catch(console.error);
package/index.js ADDED
@@ -0,0 +1,59 @@
1
+ // index.js - ES Module 版本
2
+
3
+ // --- Core Components ---
4
+ import AetherContext from './src/core/AetherContext.js';
5
+ import AetherPipeline from './src/core/AetherPipeline.js';
6
+ import AetherStore from './src/core/AetherStore.js';
7
+ import AetherCompiler from './src/core/AetherCompiler.js';
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
+ export {
26
+ AetherContext,
27
+ AetherPipeline,
28
+ AetherStore,
29
+ AetherCompiler
30
+ };
31
+
32
+ // 导出工具函数
33
+ export const utils = {
34
+ envLoader,
35
+ memoryPool,
36
+ atomicOps
37
+ };
38
+
39
+ // 导出中间件工厂函数
40
+ export const middleware = {
41
+ rateLimit: createRateLimit,
42
+ security: createSecurity,
43
+ bodyParser: createBodyParser,
44
+ cors: createCors,
45
+ compression: createCompression,
46
+ jwt: createJwt,
47
+ session: SessionManager,
48
+ json: createJson
49
+ };
50
+
51
+ // 默认导出
52
+ export default {
53
+ AetherContext,
54
+ AetherPipeline,
55
+ AetherStore,
56
+ AetherCompiler,
57
+ utils,
58
+ middleware
59
+ };
package/package.json ADDED
@@ -0,0 +1,62 @@
1
+ {
2
+ "name": "aetherframework-middleware",
3
+ "version": "1.0.0",
4
+ "description": "Ultra-performance, framework-agnostic middleware system for AetherJS",
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
+ },
32
+ "homepage": "https://github.com/aetherjs/aetherframework-middleware/blob/main/README.md",
33
+ "engines": {
34
+ "node": ">=16.0.0"
35
+ },
36
+ "dependencies": {
37
+ "jsonwebtoken": "^9.0.3",
38
+ "redis": "^4.6.0"
39
+ },
40
+ "devDependencies": {
41
+ "autocannon": "^7.0.0",
42
+ "eslint": "^8.0.0",
43
+ "jest": "^29.0.0",
44
+ "prettier": "^3.0.0",
45
+ "supertest": "^6.0.0"
46
+ },
47
+ "jest": {
48
+ "testEnvironment": "node",
49
+ "collectCoverageFrom": [
50
+ "src/**/*.js",
51
+ "!src/**/*.test.js"
52
+ ],
53
+ "coverageThreshold": {
54
+ "global": {
55
+ "branches": 80,
56
+ "functions": 80,
57
+ "lines": 80,
58
+ "statements": 80
59
+ }
60
+ }
61
+ }
62
+ }