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.
- package/.env.example +88 -0
- package/LICENSE +21 -0
- package/README.md +578 -0
- package/examples/advanced-server.js +272 -0
- package/examples/basic-server.js +134 -0
- package/examples/benchmark.js +85 -0
- package/index.js +59 -0
- package/package.json +62 -0
- package/src/core/AetherCompiler.js +118 -0
- package/src/core/AetherContext.js +240 -0
- package/src/core/AetherPipeline.js +371 -0
- package/src/core/AetherStore.js +200 -0
- package/src/middleware/body-parser.js +295 -0
- package/src/middleware/compression.js +243 -0
- package/src/middleware/cors.js +155 -0
- package/src/middleware/json.js +207 -0
- package/src/middleware/jwt.js +222 -0
- package/src/middleware/rate-limit.js +232 -0
- package/src/middleware/security.js +114 -0
- package/src/middleware/session.js +167 -0
- package/src/utils/atomic-ops.js +125 -0
- package/src/utils/env-loader.js +124 -0
- package/src/utils/memory-pool.js +93 -0
|
@@ -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
|
+
}
|