offbyt 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/README.md +2 -0
- package/cli/index.js +2 -0
- package/cli.js +206 -0
- package/core/detector/detectAxios.js +107 -0
- package/core/detector/detectFetch.js +148 -0
- package/core/detector/detectForms.js +55 -0
- package/core/detector/detectSocket.js +341 -0
- package/core/generator/generateControllers.js +17 -0
- package/core/generator/generateModels.js +25 -0
- package/core/generator/generateRoutes.js +17 -0
- package/core/generator/generateServer.js +18 -0
- package/core/generator/generateSocket.js +160 -0
- package/core/index.js +14 -0
- package/core/ir/IRTypes.js +25 -0
- package/core/ir/buildIR.js +83 -0
- package/core/parser/parseJS.js +26 -0
- package/core/parser/parseTS.js +27 -0
- package/core/rules/relationRules.js +38 -0
- package/core/rules/resourceRules.js +32 -0
- package/core/rules/schemaInference.js +26 -0
- package/core/scanner/scanProject.js +58 -0
- package/deploy/cloudflare.js +41 -0
- package/deploy/cloudflareWorker.js +122 -0
- package/deploy/connect.js +198 -0
- package/deploy/flyio.js +51 -0
- package/deploy/index.js +322 -0
- package/deploy/netlify.js +29 -0
- package/deploy/railway.js +215 -0
- package/deploy/render.js +195 -0
- package/deploy/utils.js +383 -0
- package/deploy/vercel.js +29 -0
- package/index.js +18 -0
- package/lib/generator/advancedCrudGenerator.js +475 -0
- package/lib/generator/crudCodeGenerator.js +486 -0
- package/lib/generator/irBasedGenerator.js +360 -0
- package/lib/ir-builder/index.js +16 -0
- package/lib/ir-builder/irBuilder.js +330 -0
- package/lib/ir-builder/rulesEngine.js +353 -0
- package/lib/ir-builder/templateEngine.js +193 -0
- package/lib/ir-builder/templates/index.js +14 -0
- package/lib/ir-builder/templates/model.template.js +47 -0
- package/lib/ir-builder/templates/routes-generic.template.js +66 -0
- package/lib/ir-builder/templates/routes-user.template.js +105 -0
- package/lib/ir-builder/templates/routes.template.js +102 -0
- package/lib/ir-builder/templates/validation.template.js +15 -0
- package/lib/ir-integration.js +349 -0
- package/lib/modes/benchmark.js +162 -0
- package/lib/modes/configBasedGenerator.js +2258 -0
- package/lib/modes/connect.js +1125 -0
- package/lib/modes/doctorAi.js +172 -0
- package/lib/modes/generateApi.js +435 -0
- package/lib/modes/interactiveSetup.js +548 -0
- package/lib/modes/offline.clean.js +14 -0
- package/lib/modes/offline.enhanced.js +787 -0
- package/lib/modes/offline.js +295 -0
- package/lib/modes/offline.v2.js +13 -0
- package/lib/modes/sync.js +629 -0
- package/lib/scanner/apiEndpointExtractor.js +387 -0
- package/lib/scanner/authPatternDetector.js +54 -0
- package/lib/scanner/frontendScanner.js +642 -0
- package/lib/utils/apiClientGenerator.js +242 -0
- package/lib/utils/apiScanner.js +95 -0
- package/lib/utils/codeInjector.js +350 -0
- package/lib/utils/doctor.js +381 -0
- package/lib/utils/envGenerator.js +36 -0
- package/lib/utils/loadTester.js +61 -0
- package/lib/utils/performanceAnalyzer.js +298 -0
- package/lib/utils/resourceDetector.js +281 -0
- package/package.json +20 -0
- package/templates/.env.template +31 -0
- package/templates/advanced.model.template.js +201 -0
- package/templates/advanced.route.template.js +341 -0
- package/templates/auth.middleware.template.js +87 -0
- package/templates/auth.routes.template.js +238 -0
- package/templates/auth.user.model.template.js +78 -0
- package/templates/cache.middleware.js +34 -0
- package/templates/chat.models.template.js +260 -0
- package/templates/chat.routes.template.js +478 -0
- package/templates/compression.middleware.js +19 -0
- package/templates/database.config.js +74 -0
- package/templates/errorHandler.middleware.js +54 -0
- package/templates/express/controller.ejs +26 -0
- package/templates/express/model.ejs +9 -0
- package/templates/express/route.ejs +18 -0
- package/templates/express/server.ejs +16 -0
- package/templates/frontend.env.template +14 -0
- package/templates/model.template.js +86 -0
- package/templates/package.production.json +51 -0
- package/templates/package.template.json +41 -0
- package/templates/pagination.utility.js +110 -0
- package/templates/production.server.template.js +233 -0
- package/templates/rateLimiter.middleware.js +36 -0
- package/templates/requestLogger.middleware.js +19 -0
- package/templates/response.helper.js +179 -0
- package/templates/route.template.js +130 -0
- package/templates/security.middleware.js +78 -0
- package/templates/server.template.js +91 -0
- package/templates/socket.server.template.js +433 -0
- package/templates/utils.helper.js +157 -0
- package/templates/validation.middleware.js +63 -0
- package/templates/validation.schema.js +128 -0
- package/utils/fileWriter.js +15 -0
- package/utils/logger.js +18 -0
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* offbyt Benchmark - Scalability & Performance Testing
|
|
3
|
+
* Simulates different load levels and provides performance insights
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import path from 'path';
|
|
7
|
+
import chalk from 'chalk';
|
|
8
|
+
import ora from 'ora';
|
|
9
|
+
import fs from 'fs';
|
|
10
|
+
import { scanBackendRoutes } from '../utils/apiScanner.js';
|
|
11
|
+
import { runLoadTest } from '../utils/loadTester.js';
|
|
12
|
+
import { analyzePerformance, generateReport } from '../utils/performanceAnalyzer.js';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Main benchmark function
|
|
16
|
+
*/
|
|
17
|
+
export async function runBenchmark(projectPath, options) {
|
|
18
|
+
console.log(chalk.cyan('\nâš¡ offbyt Benchmark - Scalability Testing\n'));
|
|
19
|
+
console.log(chalk.gray('Analyzing your backend performance at scale...\n'));
|
|
20
|
+
|
|
21
|
+
const backendPath = path.join(projectPath, 'backend');
|
|
22
|
+
|
|
23
|
+
// Check if backend exists
|
|
24
|
+
if (!fs.existsSync(backendPath)) {
|
|
25
|
+
console.log(chalk.red('⌠Backend folder not found. Please run `offbyt generate` first.'));
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Check if server is running
|
|
30
|
+
const serverPort = await detectServerPort(backendPath);
|
|
31
|
+
if (!serverPort) {
|
|
32
|
+
console.log(chalk.yellow('\nâš ï¸ Backend server is not running!'));
|
|
33
|
+
console.log(chalk.gray('Please start your backend server first (e.g., npm start or node server.js)\n'));
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
console.log(chalk.green(`✅ Server detected on port ${serverPort}\n`));
|
|
38
|
+
|
|
39
|
+
// STEP 1: Scan backend APIs
|
|
40
|
+
const scanSpinner = ora('Scanning backend routes...').start();
|
|
41
|
+
const routes = await scanBackendRoutes(backendPath);
|
|
42
|
+
scanSpinner.succeed(chalk.green(`✅ Found ${routes.length} API endpoints`));
|
|
43
|
+
|
|
44
|
+
if (routes.length === 0) {
|
|
45
|
+
console.log(chalk.yellow('\nâš ï¸ No routes detected. Make sure your backend has API endpoints.\n'));
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
console.log(chalk.gray('\nDetected endpoints:'));
|
|
50
|
+
routes.forEach(r => console.log(chalk.gray(` ${r.method.padEnd(7)} ${r.path}`)));
|
|
51
|
+
console.log('');
|
|
52
|
+
|
|
53
|
+
const benchmarkRoutes = selectBenchmarkRoutes(routes);
|
|
54
|
+
if (benchmarkRoutes.length === 0) {
|
|
55
|
+
console.log(chalk.yellow('âš ï¸ No benchmark-safe routes found (all routes require dynamic params).'));
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// STEP 2: Run load tests at different levels
|
|
60
|
+
const loadLevels = options.levels.split(',').map(Number);
|
|
61
|
+
const duration = parseInt(options.duration);
|
|
62
|
+
const baseUrl = `http://localhost:${serverPort}`;
|
|
63
|
+
|
|
64
|
+
const results = [];
|
|
65
|
+
|
|
66
|
+
for (const level of loadLevels) {
|
|
67
|
+
console.log(chalk.cyan(`\n📊 Testing with ${level} concurrent users...\n`));
|
|
68
|
+
|
|
69
|
+
const levelResults = [];
|
|
70
|
+
|
|
71
|
+
for (const route of benchmarkRoutes) {
|
|
72
|
+
const testSpinner = ora(`Testing ${route.method} ${route.path}`).start();
|
|
73
|
+
|
|
74
|
+
try {
|
|
75
|
+
const result = await runLoadTest({
|
|
76
|
+
url: `${baseUrl}${route.path}`,
|
|
77
|
+
method: route.method,
|
|
78
|
+
connections: level,
|
|
79
|
+
duration: duration
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
levelResults.push({
|
|
83
|
+
route: `${route.method} ${route.path}`,
|
|
84
|
+
...result
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
const avgLatency = result.latency.mean.toFixed(2);
|
|
88
|
+
const reqPerSec = result.requests.average.toFixed(2);
|
|
89
|
+
|
|
90
|
+
if (avgLatency > 500) {
|
|
91
|
+
testSpinner.fail(chalk.red(`${route.method} ${route.path} - ${avgLatency}ms (SLOW) - ${reqPerSec} req/s`));
|
|
92
|
+
} else if (avgLatency > 200) {
|
|
93
|
+
testSpinner.warn(chalk.yellow(`${route.method} ${route.path} - ${avgLatency}ms - ${reqPerSec} req/s`));
|
|
94
|
+
} else {
|
|
95
|
+
testSpinner.succeed(chalk.green(`${route.method} ${route.path} - ${avgLatency}ms - ${reqPerSec} req/s`));
|
|
96
|
+
}
|
|
97
|
+
} catch (error) {
|
|
98
|
+
testSpinner.fail(chalk.red(`${route.method} ${route.path} - Error: ${error.message}`));
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
results.push({
|
|
103
|
+
level: level,
|
|
104
|
+
routes: levelResults
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// STEP 3: Analyze and generate report
|
|
109
|
+
console.log(chalk.cyan('\n\n📈 Analyzing Performance...\n'));
|
|
110
|
+
|
|
111
|
+
const analysis = analyzePerformance(results, routes);
|
|
112
|
+
const report = generateReport(analysis, options.startupMode);
|
|
113
|
+
|
|
114
|
+
console.log(report);
|
|
115
|
+
|
|
116
|
+
// Save report to file
|
|
117
|
+
const reportPath = path.join(projectPath, 'benchmark-report.txt');
|
|
118
|
+
fs.writeFileSync(reportPath, report, 'utf8');
|
|
119
|
+
console.log(chalk.green(`\n✅ Report saved to: ${reportPath}\n`));
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function selectBenchmarkRoutes(routes) {
|
|
123
|
+
const safeRoutes = routes.filter((route) => {
|
|
124
|
+
const routePath = route.path || '';
|
|
125
|
+
const hasDynamicSegments = routePath.includes(':') || routePath.includes('${');
|
|
126
|
+
const isBulkOperation = /\/bulk\//i.test(routePath);
|
|
127
|
+
return !hasDynamicSegments && !isBulkOperation;
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
const preferredOrder = ['GET', 'POST', 'PATCH', 'PUT', 'DELETE'];
|
|
131
|
+
safeRoutes.sort((a, b) => {
|
|
132
|
+
const methodDiff = preferredOrder.indexOf(a.method) - preferredOrder.indexOf(b.method);
|
|
133
|
+
if (methodDiff !== 0) return methodDiff;
|
|
134
|
+
return a.path.length - b.path.length;
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
return safeRoutes.slice(0, 5);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Detect server port from backend files
|
|
142
|
+
*/
|
|
143
|
+
async function detectServerPort(backendPath) {
|
|
144
|
+
try {
|
|
145
|
+
const serverFile = path.join(backendPath, 'server.js');
|
|
146
|
+
if (!fs.existsSync(serverFile)) return null;
|
|
147
|
+
|
|
148
|
+
const content = fs.readFileSync(serverFile, 'utf8');
|
|
149
|
+
|
|
150
|
+
// Try to find port in code
|
|
151
|
+
const portMatch = content.match(/\.listen\s*\(\s*(\d+)|PORT\s*=\s*(\d+)|port:\s*(\d+)/i);
|
|
152
|
+
if (portMatch) {
|
|
153
|
+
return portMatch[1] || portMatch[2] || portMatch[3];
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Default to 5000
|
|
157
|
+
return 5000;
|
|
158
|
+
} catch {
|
|
159
|
+
return null;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|