@arikajs/benchmark 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.
@@ -0,0 +1,5 @@
1
+
2
+ 
3
+ > @arikajs/benchmark@0.1.0 build /Users/prakashtank/Documents/nodeServices/ArikaJs/packages/benchmark
4
+ > tsc -p tsconfig.json
5
+
package/CHANGELOG.md ADDED
@@ -0,0 +1,37 @@
1
+ # @arikajs/benchmark
2
+
3
+ ## 0.0.8
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies
8
+ - arikajs@0.0.8
9
+ - @arikajs/http@0.0.8
10
+ - @arikajs/router@0.0.8
11
+
12
+ ## 0.0.7
13
+
14
+ ### Patch Changes
15
+
16
+ - Updated dependencies
17
+ - arikajs@0.0.7
18
+ - @arikajs/http@0.0.7
19
+ - @arikajs/router@0.0.7
20
+
21
+ ## 0.0.6
22
+
23
+ ### Patch Changes
24
+
25
+ - Updated dependencies
26
+ - arikajs@0.0.6
27
+ - @arikajs/http@0.0.6
28
+ - @arikajs/router@0.0.6
29
+
30
+ ## 0.0.5
31
+
32
+ ### Patch Changes
33
+
34
+ - Updated dependencies
35
+ - arikajs@0.0.5
36
+ - @arikajs/http@0.0.5
37
+ - @arikajs/router@0.0.5
@@ -0,0 +1,5 @@
1
+ export declare function runBenchmark({ duration, connections, warmup }: {
2
+ duration?: number | undefined;
3
+ connections?: number | undefined;
4
+ warmup?: number | undefined;
5
+ }): Promise<void>;
package/dist/index.js ADDED
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.runBenchmark = runBenchmark;
4
+ const arika_1 = require("./servers/arika");
5
+ const fastify_1 = require("./servers/fastify");
6
+ const express_1 = require("./servers/express");
7
+ const autocannon = require('autocannon');
8
+ async function runBenchmark({ duration = 10, connections = 200, warmup = 2 }) {
9
+ console.log('\n 🚀 ArikaJS Benchmark Suite');
10
+ console.log(' Comparing ArikaJS vs Fastify vs Express\n');
11
+ const run = (serverFactory, name, path) => {
12
+ return new Promise(async (resolve) => {
13
+ const server = await serverFactory();
14
+ await new Promise(res => server.listen(3000, () => res()));
15
+ // Warmup
16
+ await autocannon({ url: `http://localhost:3000${path}`, connections: 10, duration: warmup });
17
+ // Benchmark
18
+ const result = await autocannon({
19
+ url: `http://localhost:3000${path}`,
20
+ connections,
21
+ duration,
22
+ pipelining: 1
23
+ });
24
+ server.close();
25
+ console.log(` ✔ ${name.padEnd(15)} ${(result.requests.average || 0).toFixed(2)} req/s latency avg ${result.latency.average}ms`);
26
+ resolve(result);
27
+ });
28
+ };
29
+ console.log(' 📌 Scenario: GET /hello (simple JSON)\n');
30
+ await run(express_1.createExpressServer, 'Express', '/hello');
31
+ await run(fastify_1.createFastifyServer, 'Fastify', '/hello');
32
+ await run(arika_1.createArikaServer, 'ArikaJS', '/hello');
33
+ console.log('\n 📌 Scenario: GET /users/:id (route params)\n');
34
+ await run(express_1.createExpressServer, 'Express', '/users/123');
35
+ await run(fastify_1.createFastifyServer, 'Fastify', '/users/123');
36
+ await run(arika_1.createArikaServer, 'ArikaJS', '/users/123');
37
+ console.log('\n 📌 Scenario: GET /posts/:id/comments (Middleware + Params)\n');
38
+ await run(express_1.createExpressServer, 'Express', '/posts/1/comments');
39
+ await run(fastify_1.createFastifyServer, 'Fastify', '/posts/1/comments');
40
+ await run(arika_1.createArikaServer, 'ArikaJS', '/posts/1/comments');
41
+ console.log('\n');
42
+ }
@@ -0,0 +1,178 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.printReport = printReport;
7
+ const chalk_1 = __importDefault(require("chalk"));
8
+ const cli_table3_1 = __importDefault(require("cli-table3"));
9
+ // ─── Colour palette ────────────────────────────────────────────────────────
10
+ const FRAMEWORK_COLORS = {
11
+ 'ArikaJS': chalk_1.default.hex('#7C3AED'), // violet
12
+ 'Fastify': chalk_1.default.hex('#00B7A3'), // teal
13
+ 'Express': chalk_1.default.hex('#E09000'), // amber
14
+ };
15
+ function colorFor(name) {
16
+ return FRAMEWORK_COLORS[name] ?? chalk_1.default.white;
17
+ }
18
+ function medal(rank) {
19
+ if (rank === 1)
20
+ return '🥇';
21
+ if (rank === 2)
22
+ return '🥈';
23
+ if (rank === 3)
24
+ return '🥉';
25
+ return ` ${rank}.`;
26
+ }
27
+ function fmtRps(n) {
28
+ return n >= 1000 ? `${(n / 1000).toFixed(2)}k` : n.toFixed(0);
29
+ }
30
+ function fmtBytes(n) {
31
+ if (n >= 1024 * 1024)
32
+ return `${(n / (1024 * 1024)).toFixed(2)} MB/s`;
33
+ if (n >= 1024)
34
+ return `${(n / 1024).toFixed(2)} KB/s`;
35
+ return `${n.toFixed(0)} B/s`;
36
+ }
37
+ function fmtMs(n) {
38
+ return `${n.toFixed(2)} ms`;
39
+ }
40
+ // ─── Header ────────────────────────────────────────────────────────────────
41
+ function printHeader(suite) {
42
+ console.log('');
43
+ console.log(chalk_1.default.hex('#7C3AED').bold('╔══════════════════════════════════════════════════════════════╗'));
44
+ console.log(chalk_1.default.hex('#7C3AED').bold('║') + chalk_1.default.white.bold(' 🚀 ArikaJS Performance Benchmark Report ') + chalk_1.default.hex('#7C3AED').bold('║'));
45
+ console.log(chalk_1.default.hex('#7C3AED').bold('╚══════════════════════════════════════════════════════════════╝'));
46
+ console.log('');
47
+ console.log(chalk_1.default.gray(` 📅 Timestamp : ${suite.timestamp}`));
48
+ console.log(chalk_1.default.gray(` ⬡ Node.js : ${suite.nodeVersion}`));
49
+ console.log(chalk_1.default.gray(` 💻 Platform : ${suite.platform}`));
50
+ console.log('');
51
+ }
52
+ // ─── Per-scenario table ─────────────────────────────────────────────────────
53
+ function printScenarioTable(scenario, rows) {
54
+ // Sort by req/s descending
55
+ const sorted = [...rows].sort((a, b) => b.requestsPerSecond - a.requestsPerSecond);
56
+ const topRps = sorted[0]?.requestsPerSecond ?? 1;
57
+ console.log(chalk_1.default.white.bold(` 📌 Scenario: `) + chalk_1.default.cyan.bold(scenario));
58
+ console.log(chalk_1.default.gray(` Connections: ${sorted[0]?.connections} Duration: ${sorted[0]?.duration}s`));
59
+ console.log('');
60
+ const table = new cli_table3_1.default({
61
+ head: [
62
+ chalk_1.default.white.bold('Rank'),
63
+ chalk_1.default.white.bold('Framework'),
64
+ chalk_1.default.white.bold('Req/s'),
65
+ chalk_1.default.white.bold('Latency avg'),
66
+ chalk_1.default.white.bold('Latency p99'),
67
+ chalk_1.default.white.bold('Throughput'),
68
+ chalk_1.default.white.bold('Errors'),
69
+ chalk_1.default.white.bold('vs Best'),
70
+ ],
71
+ colAligns: ['center', 'left', 'right', 'right', 'right', 'right', 'right', 'right'],
72
+ style: {
73
+ head: [],
74
+ border: ['gray'],
75
+ },
76
+ chars: {
77
+ top: '─', 'top-mid': '┬', 'top-left': '╭', 'top-right': '╮',
78
+ bottom: '─', 'bottom-mid': '┴', 'bottom-left': '╰', 'bottom-right': '╯',
79
+ left: '│', 'left-mid': '├', mid: '─', 'mid-mid': '┼',
80
+ right: '│', 'right-mid': '┤', middle: '│',
81
+ },
82
+ });
83
+ sorted.forEach((r, idx) => {
84
+ const rank = idx + 1;
85
+ const color = colorFor(r.framework);
86
+ const ratio = (r.requestsPerSecond / topRps);
87
+ const vsLabel = rank === 1
88
+ ? chalk_1.default.green.bold(' ★ Best')
89
+ : chalk_1.default.red(` −${((1 - ratio) * 100).toFixed(1)}%`);
90
+ const errText = r.errors > 0
91
+ ? chalk_1.default.red(r.errors.toLocaleString())
92
+ : chalk_1.default.green('0');
93
+ table.push([
94
+ medal(rank),
95
+ color.bold(r.framework),
96
+ color(fmtRps(r.requestsPerSecond)),
97
+ chalk_1.default.white(fmtMs(r.latencyAvg)),
98
+ chalk_1.default.white(fmtMs(r.latencyP99)),
99
+ chalk_1.default.gray(fmtBytes(r.throughput)),
100
+ errText,
101
+ vsLabel,
102
+ ]);
103
+ });
104
+ console.log(table.toString());
105
+ console.log('');
106
+ }
107
+ // ─── Summary comparison table ───────────────────────────────────────────────
108
+ function printSummary(results) {
109
+ const frameworks = [...new Set(results.map(r => r.framework))];
110
+ const scenarios = [...new Set(results.map(r => r.scenario))];
111
+ // Compute average req/s per framework across all scenarios
112
+ const avgMap = {};
113
+ for (const fw of frameworks) {
114
+ const fwResults = results.filter(r => r.framework === fw);
115
+ avgMap[fw] = fwResults.reduce((s, r) => s + r.requestsPerSecond, 0) / fwResults.length;
116
+ }
117
+ const sorted = frameworks.sort((a, b) => avgMap[b] - avgMap[a]);
118
+ const bestRps = avgMap[sorted[0]];
119
+ console.log(chalk_1.default.white.bold(' 📊 Overall Summary ') + chalk_1.default.gray('(avg req/s across all scenarios)'));
120
+ console.log('');
121
+ const table = new cli_table3_1.default({
122
+ head: [
123
+ chalk_1.default.white.bold('Rank'),
124
+ chalk_1.default.white.bold('Framework'),
125
+ chalk_1.default.white.bold('Avg Req/s'),
126
+ chalk_1.default.white.bold('vs Best'),
127
+ ...scenarios.map(s => chalk_1.default.white.bold(s)),
128
+ ],
129
+ colAligns: ['center', 'left', 'right', 'right', ...scenarios.map(() => 'right')],
130
+ style: { head: [], border: ['gray'] },
131
+ chars: {
132
+ top: '─', 'top-mid': '┬', 'top-left': '╭', 'top-right': '╮',
133
+ bottom: '─', 'bottom-mid': '┴', 'bottom-left': '╰', 'bottom-right': '╯',
134
+ left: '│', 'left-mid': '├', mid: '─', 'mid-mid': '┼',
135
+ right: '│', 'right-mid': '┤', middle: '│',
136
+ },
137
+ });
138
+ sorted.forEach((fw, idx) => {
139
+ const rank = idx + 1;
140
+ const color = colorFor(fw);
141
+ const ratio = avgMap[fw] / bestRps;
142
+ const vsLabel = rank === 1
143
+ ? chalk_1.default.green.bold(' ★ Best')
144
+ : chalk_1.default.red(` −${((1 - ratio) * 100).toFixed(1)}%`);
145
+ const perScenario = scenarios.map(s => {
146
+ const r = results.find(x => x.framework === fw && x.scenario === s);
147
+ return r ? color(fmtRps(r.requestsPerSecond)) : chalk_1.default.gray('N/A');
148
+ });
149
+ table.push([
150
+ medal(rank),
151
+ color.bold(fw),
152
+ color.bold(fmtRps(avgMap[fw])),
153
+ vsLabel,
154
+ ...perScenario,
155
+ ]);
156
+ });
157
+ console.log(table.toString());
158
+ console.log('');
159
+ }
160
+ // ─── Footer ─────────────────────────────────────────────────────────────────
161
+ function printFooter() {
162
+ console.log(chalk_1.default.hex('#7C3AED').bold('─────────────────────────────────────────────────────────────────'));
163
+ console.log(chalk_1.default.gray(' ℹ Measured with autocannon. Results may vary between runs.'));
164
+ console.log(chalk_1.default.gray(' ℹ ArikaJS includes full framework boot (routing, middleware, DI).'));
165
+ console.log(chalk_1.default.hex('#7C3AED').bold('─────────────────────────────────────────────────────────────────'));
166
+ console.log('');
167
+ }
168
+ // ─── Public API ─────────────────────────────────────────────────────────────
169
+ function printReport(suite) {
170
+ printHeader(suite);
171
+ const scenarios = [...new Set(suite.results.map(r => r.scenario))];
172
+ for (const scenario of scenarios) {
173
+ const rows = suite.results.filter(r => r.scenario === scenario);
174
+ printScenarioTable(scenario, rows);
175
+ }
176
+ printSummary(suite.results);
177
+ printFooter();
178
+ }
package/dist/runner.js ADDED
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.startServer = startServer;
7
+ exports.stopServer = stopServer;
8
+ exports.runScenario = runScenario;
9
+ const autocannon_1 = __importDefault(require("autocannon"));
10
+ /**
11
+ * Start an HTTP server on a random free port and return the address.
12
+ */
13
+ function startServer(server) {
14
+ return new Promise((resolve, reject) => {
15
+ server.on('error', reject);
16
+ server.listen(0, '127.0.0.1', () => {
17
+ const addr = server.address();
18
+ resolve(addr);
19
+ });
20
+ });
21
+ }
22
+ /**
23
+ * Close an HTTP server gracefully.
24
+ */
25
+ function stopServer(server) {
26
+ return new Promise((resolve) => {
27
+ server.close(() => resolve());
28
+ // Force-close any keep-alive connections
29
+ if (typeof server.closeAllConnections === 'function') {
30
+ server.closeAllConnections();
31
+ }
32
+ });
33
+ }
34
+ /**
35
+ * Run autocannon against a server for a single scenario and return structured results.
36
+ */
37
+ async function runScenario(framework, server, scenario, opts) {
38
+ const { port } = await startServer(server);
39
+ const baseUrl = `http://127.0.0.1:${port}`;
40
+ // -- Warmup run (shorter, results discarded) --
41
+ if (opts.warmupDuration && opts.warmupDuration > 0) {
42
+ await (0, autocannon_1.default)({
43
+ url: `${baseUrl}${scenario.url}`,
44
+ connections: opts.connections,
45
+ duration: opts.warmupDuration,
46
+ silent: true,
47
+ });
48
+ }
49
+ // -- Actual benchmark run --
50
+ const result = await (0, autocannon_1.default)({
51
+ url: `${baseUrl}${scenario.url}`,
52
+ method: scenario.method,
53
+ connections: opts.connections,
54
+ duration: opts.duration,
55
+ pipelining: opts.pipelining ?? 1,
56
+ silent: true,
57
+ ...(scenario.body
58
+ ? {
59
+ headers: { 'content-type': 'application/json' },
60
+ body: JSON.stringify(scenario.body),
61
+ }
62
+ : {}),
63
+ });
64
+ await stopServer(server);
65
+ return {
66
+ framework,
67
+ scenario: scenario.name,
68
+ requestsPerSecond: result.requests.average,
69
+ latencyAvg: result.latency.average,
70
+ latencyP99: result.latency.p99,
71
+ throughput: result.throughput.average,
72
+ errors: result.errors,
73
+ timeouts: result.timeouts,
74
+ duration: opts.duration,
75
+ connections: opts.connections,
76
+ };
77
+ }
@@ -0,0 +1,2 @@
1
+ import http from 'node:http';
2
+ export declare function createArikaServer(): Promise<http.Server>;
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.createArikaServer = createArikaServer;
7
+ const node_http_1 = __importDefault(require("node:http"));
8
+ const node_path_1 = __importDefault(require("node:path"));
9
+ async function createArikaServer() {
10
+ const origConsoleLog = console.log;
11
+ console.log = () => { };
12
+ console.info = () => { };
13
+ console.warn = () => { };
14
+ console.error = () => { };
15
+ const { Application } = require('arikajs');
16
+ const { Route, RouteRegistry } = require('@arikajs/router');
17
+ RouteRegistry.getInstance().clear();
18
+ const app = new Application(node_path_1.default.resolve(__dirname, '../../../../'));
19
+ Route.get('/hello', () => ({ message: 'Hello from ArikaJS!' }));
20
+ // Test parameters
21
+ Route.get('/users/:id', (req) => ({
22
+ id: req.param('id'),
23
+ name: `User ${req.param('id')}`
24
+ }));
25
+ // Test Middleware + Nested Params
26
+ Route.get('/posts/:id/comments', (req) => {
27
+ return {
28
+ id: req.param('id'),
29
+ comments: [
30
+ { id: 1, text: 'First comment' },
31
+ { id: 2, text: 'Second comment' }
32
+ ]
33
+ };
34
+ }).withMiddleware((req, res, next) => {
35
+ // Simple auth simulation
36
+ req.user = { id: 1, name: 'Tester' };
37
+ return next();
38
+ });
39
+ await app.boot();
40
+ const server = node_http_1.default.createServer(app.getCallback());
41
+ console.log = origConsoleLog;
42
+ return server;
43
+ }
@@ -0,0 +1,2 @@
1
+ import http from 'node:http';
2
+ export declare function createExpressServer(): Promise<http.Server>;
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.createExpressServer = createExpressServer;
7
+ const express_1 = __importDefault(require("express"));
8
+ const node_http_1 = __importDefault(require("node:http"));
9
+ async function createExpressServer() {
10
+ const origConsoleLog = console.log;
11
+ console.log = () => { };
12
+ const app = (0, express_1.default)();
13
+ app.get('/hello', (req, res) => {
14
+ res.json({ message: 'Hello from ArikaJS!' });
15
+ });
16
+ app.get('/users/:id', (req, res) => {
17
+ res.json({ id: req.params.id, name: `User ${req.params.id}` });
18
+ });
19
+ app.get('/posts/:id/comments', (req, res, next) => {
20
+ // Simple auth simulation
21
+ req.user = { id: 1, name: 'Tester' };
22
+ next();
23
+ }, (req, res) => {
24
+ res.json({
25
+ id: req.params.id,
26
+ comments: [
27
+ { id: 1, text: 'First comment' },
28
+ { id: 2, text: 'Second comment' }
29
+ ]
30
+ });
31
+ });
32
+ const server = node_http_1.default.createServer(app);
33
+ console.log = origConsoleLog;
34
+ return server;
35
+ }
@@ -0,0 +1 @@
1
+ export declare function createFastifyServer(): Promise<import("http").Server<typeof import("http").IncomingMessage, typeof import("http").ServerResponse>>;
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.createFastifyServer = createFastifyServer;
7
+ const fastify_1 = __importDefault(require("fastify"));
8
+ async function createFastifyServer() {
9
+ const origConsoleLog = console.log;
10
+ console.log = () => { };
11
+ const app = (0, fastify_1.default)();
12
+ app.get('/hello', async (request, reply) => {
13
+ return { message: 'Hello from ArikaJS!' }; // Keep same text
14
+ });
15
+ app.get('/users/:id', async (request, reply) => {
16
+ return { id: request.params.id, name: `User ${request.params.id}` };
17
+ });
18
+ app.get('/posts/:id/comments', {
19
+ onRequest: async (request, reply) => {
20
+ // Simple auth simulation
21
+ request.user = { id: 1, name: 'Tester' };
22
+ }
23
+ }, async (request, reply) => {
24
+ return {
25
+ id: request.params.id,
26
+ comments: [
27
+ { id: 1, text: 'First comment' },
28
+ { id: 2, text: 'Second comment' }
29
+ ]
30
+ };
31
+ });
32
+ await app.ready();
33
+ console.log = origConsoleLog;
34
+ return app.server;
35
+ }
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.createNodeServer = createNodeServer;
7
+ const node_http_1 = __importDefault(require("node:http"));
8
+ /**
9
+ * Minimal pure Node.js HTTP server (no framework overhead) – baseline reference.
10
+ */
11
+ function createNodeServer() {
12
+ return node_http_1.default.createServer((req, res) => {
13
+ if (req.method === 'GET' && req.url === '/hello') {
14
+ res.writeHead(200, { 'Content-Type': 'application/json' });
15
+ res.end(JSON.stringify({ message: 'Hello from Node.js!' }));
16
+ }
17
+ else if (req.method === 'GET' && req.url?.startsWith('/users/')) {
18
+ const id = req.url.split('/')[2];
19
+ res.writeHead(200, { 'Content-Type': 'application/json' });
20
+ res.end(JSON.stringify({ id, name: `User ${id}` }));
21
+ }
22
+ else {
23
+ res.writeHead(404, { 'Content-Type': 'application/json' });
24
+ res.end(JSON.stringify({ error: 'Not Found' }));
25
+ }
26
+ });
27
+ }
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/package.json ADDED
@@ -0,0 +1,26 @@
1
+ {
2
+ "name": "@arikajs/benchmark",
3
+ "version": "0.1.0",
4
+ "description": "Benchmark suite for ArikaJS applications.",
5
+ "license": "MIT",
6
+ "publishConfig": {
7
+ "access": "public"
8
+ },
9
+ "main": "dist/index.js",
10
+ "types": "dist/index.d.ts",
11
+ "dependencies": {
12
+ "autocannon": "^8.0.0",
13
+ "express": "^4.22.1",
14
+ "@arikajs/router": "0.1.0",
15
+ "arikajs": "0.1.0",
16
+ "@arikajs/http": "0.1.0"
17
+ },
18
+ "devDependencies": {
19
+ "@types/express": "^5.0.6",
20
+ "cli-table3": "^0.6.5",
21
+ "fastify": "^5.8.1"
22
+ },
23
+ "scripts": {
24
+ "build": "tsc -p tsconfig.json"
25
+ }
26
+ }
package/src/index.ts ADDED
@@ -0,0 +1,48 @@
1
+ import { createArikaServer } from './servers/arika';
2
+ import { createFastifyServer } from './servers/fastify';
3
+ import { createExpressServer } from './servers/express';
4
+ const autocannon = require('autocannon');
5
+
6
+ export async function runBenchmark({ duration = 10, connections = 200, warmup = 2 }) {
7
+ console.log('\n 🚀 ArikaJS Benchmark Suite');
8
+ console.log(' Comparing ArikaJS vs Fastify vs Express\n');
9
+
10
+ const run = (serverFactory: any, name: string, path: string) => {
11
+ return new Promise<any>(async (resolve) => {
12
+ const server = await serverFactory();
13
+ await new Promise<void>(res => server.listen(3000, () => res()));
14
+
15
+ // Warmup
16
+ await autocannon({ url: `http://localhost:3000${path}`, connections: 10, duration: warmup });
17
+
18
+ // Benchmark
19
+ const result = await autocannon({
20
+ url: `http://localhost:3000${path}`,
21
+ connections,
22
+ duration,
23
+ pipelining: 1
24
+ });
25
+
26
+ server.close();
27
+ console.log(` ✔ ${name.padEnd(15)} ${(result.requests.average || 0).toFixed(2)} req/s latency avg ${result.latency.average}ms`);
28
+ resolve(result);
29
+ });
30
+ };
31
+
32
+ console.log(' 📌 Scenario: GET /hello (simple JSON)\n');
33
+ await run(createExpressServer, 'Express', '/hello');
34
+ await run(createFastifyServer, 'Fastify', '/hello');
35
+ await run(createArikaServer, 'ArikaJS', '/hello');
36
+
37
+ console.log('\n 📌 Scenario: GET /users/:id (route params)\n');
38
+ await run(createExpressServer, 'Express', '/users/123');
39
+ await run(createFastifyServer, 'Fastify', '/users/123');
40
+ await run(createArikaServer, 'ArikaJS', '/users/123');
41
+
42
+ console.log('\n 📌 Scenario: GET /posts/:id/comments (Middleware + Params)\n');
43
+ await run(createExpressServer, 'Express', '/posts/1/comments');
44
+ await run(createFastifyServer, 'Fastify', '/posts/1/comments');
45
+ await run(createArikaServer, 'ArikaJS', '/posts/1/comments');
46
+
47
+ console.log('\n');
48
+ }
@@ -0,0 +1,47 @@
1
+ import http from 'node:http';
2
+ import path from 'node:path';
3
+
4
+ export async function createArikaServer(): Promise<http.Server> {
5
+ const origConsoleLog = console.log;
6
+ console.log = () => { };
7
+ console.info = () => { };
8
+ console.warn = () => { };
9
+ console.error = () => { };
10
+
11
+ const { Application } = require('arikajs');
12
+ const { Route, RouteRegistry } = require('@arikajs/router');
13
+
14
+ RouteRegistry.getInstance().clear();
15
+
16
+ const app = new Application(path.resolve(__dirname, '../../../../'));
17
+
18
+ Route.get('/hello', () => ({ message: 'Hello from ArikaJS!' }));
19
+
20
+ // Test parameters
21
+ Route.get('/users/:id', (req: any) => ({
22
+ id: req.param('id'),
23
+ name: `User ${req.param('id')}`
24
+ }));
25
+
26
+ // Test Middleware + Nested Params
27
+ Route.get('/posts/:id/comments', (req: any) => {
28
+ return {
29
+ id: req.param('id'),
30
+ comments: [
31
+ { id: 1, text: 'First comment' },
32
+ { id: 2, text: 'Second comment' }
33
+ ]
34
+ };
35
+ }).withMiddleware((req: any, res: any, next: any) => {
36
+ // Simple auth simulation
37
+ req.user = { id: 1, name: 'Tester' };
38
+ return next();
39
+ });
40
+
41
+ await app.boot();
42
+
43
+ const server = http.createServer(app.getCallback());
44
+
45
+ console.log = origConsoleLog;
46
+ return server;
47
+ }
@@ -0,0 +1,35 @@
1
+ import express from 'express';
2
+ import http from 'node:http';
3
+
4
+ export async function createExpressServer(): Promise<http.Server> {
5
+ const origConsoleLog = console.log;
6
+ console.log = () => { };
7
+
8
+ const app = express();
9
+
10
+ app.get('/hello', (req: any, res: any) => {
11
+ res.json({ message: 'Hello from ArikaJS!' });
12
+ });
13
+
14
+ app.get('/users/:id', (req: any, res: any) => {
15
+ res.json({ id: req.params.id, name: `User ${req.params.id}` });
16
+ });
17
+
18
+ app.get('/posts/:id/comments', (req: any, res: any, next: any) => {
19
+ // Simple auth simulation
20
+ (req as any).user = { id: 1, name: 'Tester' };
21
+ next();
22
+ }, (req: any, res: any) => {
23
+ res.json({
24
+ id: req.params.id,
25
+ comments: [
26
+ { id: 1, text: 'First comment' },
27
+ { id: 2, text: 'Second comment' }
28
+ ]
29
+ });
30
+ });
31
+
32
+ const server = http.createServer(app);
33
+ console.log = origConsoleLog;
34
+ return server;
35
+ }
@@ -0,0 +1,35 @@
1
+ import fastify from 'fastify';
2
+
3
+ export async function createFastifyServer() {
4
+ const origConsoleLog = console.log;
5
+ console.log = () => { };
6
+
7
+ const app = fastify();
8
+
9
+ app.get('/hello', async (request: any, reply: any) => {
10
+ return { message: 'Hello from ArikaJS!' }; // Keep same text
11
+ });
12
+
13
+ app.get('/users/:id', async (request: any, reply: any) => {
14
+ return { id: request.params.id, name: `User ${request.params.id}` };
15
+ });
16
+
17
+ app.get('/posts/:id/comments', {
18
+ onRequest: async (request: any, reply: any) => {
19
+ // Simple auth simulation
20
+ (request as any).user = { id: 1, name: 'Tester' };
21
+ }
22
+ }, async (request: any, reply: any) => {
23
+ return {
24
+ id: request.params.id,
25
+ comments: [
26
+ { id: 1, text: 'First comment' },
27
+ { id: 2, text: 'Second comment' }
28
+ ]
29
+ };
30
+ });
31
+
32
+ await app.ready();
33
+ console.log = origConsoleLog;
34
+ return app.server;
35
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,17 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "CommonJS",
5
+ "rootDir": "./src",
6
+ "outDir": "./dist",
7
+ "esModuleInterop": true,
8
+ "forceConsistentCasingInFileNames": true,
9
+ "strict": true,
10
+ "skipLibCheck": true,
11
+ "declaration": true,
12
+ "resolveJsonModule": true
13
+ },
14
+ "include": [
15
+ "src/**/*"
16
+ ]
17
+ }