vaspera 2.9.2 → 2.10.1
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/CHANGELOG.md +68 -0
- package/README.md +58 -1
- package/dist/__tests__/autofix/branch-manager.test.d.ts +2 -0
- package/dist/__tests__/autofix/branch-manager.test.d.ts.map +1 -0
- package/dist/__tests__/autofix/branch-manager.test.js +60 -0
- package/dist/__tests__/autofix/branch-manager.test.js.map +1 -0
- package/dist/__tests__/autofix/commit-generator.test.d.ts +2 -0
- package/dist/__tests__/autofix/commit-generator.test.d.ts.map +1 -0
- package/dist/__tests__/autofix/commit-generator.test.js +147 -0
- package/dist/__tests__/autofix/commit-generator.test.js.map +1 -0
- package/dist/__tests__/autofix/constitution.test.d.ts +9 -0
- package/dist/__tests__/autofix/constitution.test.d.ts.map +1 -0
- package/dist/__tests__/autofix/constitution.test.js +421 -0
- package/dist/__tests__/autofix/constitution.test.js.map +1 -0
- package/dist/__tests__/autofix/pr-generator.test.d.ts +2 -0
- package/dist/__tests__/autofix/pr-generator.test.d.ts.map +1 -0
- package/dist/__tests__/autofix/pr-generator.test.js +152 -0
- package/dist/__tests__/autofix/pr-generator.test.js.map +1 -0
- package/dist/__tests__/property-test-helpers.d.ts +87 -0
- package/dist/__tests__/property-test-helpers.d.ts.map +1 -0
- package/dist/__tests__/property-test-helpers.js +136 -0
- package/dist/__tests__/property-test-helpers.js.map +1 -0
- package/dist/__tests__/scanners/ai-code/ai-detector.test.d.ts +2 -0
- package/dist/__tests__/scanners/ai-code/ai-detector.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/ai-code/ai-detector.test.js +188 -0
- package/dist/__tests__/scanners/ai-code/ai-detector.test.js.map +1 -0
- package/dist/__tests__/scanners/ai-code/confidence-scorer.test.d.ts +2 -0
- package/dist/__tests__/scanners/ai-code/confidence-scorer.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/ai-code/confidence-scorer.test.js +363 -0
- package/dist/__tests__/scanners/ai-code/confidence-scorer.test.js.map +1 -0
- package/dist/__tests__/scanners/ai-code/hallucination-checker.test.d.ts +2 -0
- package/dist/__tests__/scanners/ai-code/hallucination-checker.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/ai-code/hallucination-checker.test.js +226 -0
- package/dist/__tests__/scanners/ai-code/hallucination-checker.test.js.map +1 -0
- package/dist/__tests__/scanners/ai-code/index.test.d.ts +2 -0
- package/dist/__tests__/scanners/ai-code/index.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/ai-code/index.test.js +214 -0
- package/dist/__tests__/scanners/ai-code/index.test.js.map +1 -0
- package/dist/__tests__/scanners/dast/index.test.d.ts +2 -0
- package/dist/__tests__/scanners/dast/index.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/dast/index.test.js +183 -0
- package/dist/__tests__/scanners/dast/index.test.js.map +1 -0
- package/dist/__tests__/scanners/dast/nuclei.test.d.ts +2 -0
- package/dist/__tests__/scanners/dast/nuclei.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/dast/nuclei.test.js +166 -0
- package/dist/__tests__/scanners/dast/nuclei.test.js.map +1 -0
- package/dist/__tests__/scanners/dast/zap.test.d.ts +2 -0
- package/dist/__tests__/scanners/dast/zap.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/dast/zap.test.js +158 -0
- package/dist/__tests__/scanners/dast/zap.test.js.map +1 -0
- package/dist/__tests__/scanners/deploy/health-checker.test.d.ts +2 -0
- package/dist/__tests__/scanners/deploy/health-checker.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/deploy/health-checker.test.js +67 -0
- package/dist/__tests__/scanners/deploy/health-checker.test.js.map +1 -0
- package/dist/__tests__/scanners/deploy/index.test.d.ts +2 -0
- package/dist/__tests__/scanners/deploy/index.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/deploy/index.test.js +84 -0
- package/dist/__tests__/scanners/deploy/index.test.js.map +1 -0
- package/dist/__tests__/scanners/deploy/provider-detector.test.d.ts +2 -0
- package/dist/__tests__/scanners/deploy/provider-detector.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/deploy/provider-detector.test.js +88 -0
- package/dist/__tests__/scanners/deploy/provider-detector.test.js.map +1 -0
- package/dist/__tests__/scanners/deploy/types.test.d.ts +2 -0
- package/dist/__tests__/scanners/deploy/types.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/deploy/types.test.js +126 -0
- package/dist/__tests__/scanners/deploy/types.test.js.map +1 -0
- package/dist/__tests__/scanners/fp-feedback.test.d.ts +2 -0
- package/dist/__tests__/scanners/fp-feedback.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/fp-feedback.test.js +202 -0
- package/dist/__tests__/scanners/fp-feedback.test.js.map +1 -0
- package/dist/__tests__/scanners/fp-filter.property.test.d.ts +9 -0
- package/dist/__tests__/scanners/fp-filter.property.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/fp-filter.property.test.js +253 -0
- package/dist/__tests__/scanners/fp-filter.property.test.js.map +1 -0
- package/dist/__tests__/scanners/fp-filter.test.d.ts +2 -0
- package/dist/__tests__/scanners/fp-filter.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/fp-filter.test.js +234 -0
- package/dist/__tests__/scanners/fp-filter.test.js.map +1 -0
- package/dist/__tests__/scanners/fp-tracker.test.d.ts +2 -0
- package/dist/__tests__/scanners/fp-tracker.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/fp-tracker.test.js +262 -0
- package/dist/__tests__/scanners/fp-tracker.test.js.map +1 -0
- package/dist/__tests__/scanners/logic/endpoint-analyzer.property.test.d.ts +10 -0
- package/dist/__tests__/scanners/logic/endpoint-analyzer.property.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/logic/endpoint-analyzer.property.test.js +238 -0
- package/dist/__tests__/scanners/logic/endpoint-analyzer.property.test.js.map +1 -0
- package/dist/__tests__/scanners/logic/endpoint-analyzer.test.d.ts +2 -0
- package/dist/__tests__/scanners/logic/endpoint-analyzer.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/logic/endpoint-analyzer.test.js +55 -0
- package/dist/__tests__/scanners/logic/endpoint-analyzer.test.js.map +1 -0
- package/dist/__tests__/scanners/logic/index.test.d.ts +2 -0
- package/dist/__tests__/scanners/logic/index.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/logic/index.test.js +165 -0
- package/dist/__tests__/scanners/logic/index.test.js.map +1 -0
- package/dist/__tests__/scanners/logic/types.test.d.ts +2 -0
- package/dist/__tests__/scanners/logic/types.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/logic/types.test.js +85 -0
- package/dist/__tests__/scanners/logic/types.test.js.map +1 -0
- package/dist/__tests__/scanners/runtime/app-launcher.test.d.ts +2 -0
- package/dist/__tests__/scanners/runtime/app-launcher.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/runtime/app-launcher.test.js +94 -0
- package/dist/__tests__/scanners/runtime/app-launcher.test.js.map +1 -0
- package/dist/__tests__/scanners/runtime/golden-path-runner.test.d.ts +2 -0
- package/dist/__tests__/scanners/runtime/golden-path-runner.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/runtime/golden-path-runner.test.js +195 -0
- package/dist/__tests__/scanners/runtime/golden-path-runner.test.js.map +1 -0
- package/dist/__tests__/scanners/runtime/index.test.d.ts +2 -0
- package/dist/__tests__/scanners/runtime/index.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/runtime/index.test.js +120 -0
- package/dist/__tests__/scanners/runtime/index.test.js.map +1 -0
- package/dist/__tests__/scanners/runtime/types.test.d.ts +2 -0
- package/dist/__tests__/scanners/runtime/types.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/runtime/types.test.js +126 -0
- package/dist/__tests__/scanners/runtime/types.test.js.map +1 -0
- package/dist/__tests__/scanners/scale/bottleneck-detector.test.d.ts +2 -0
- package/dist/__tests__/scanners/scale/bottleneck-detector.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/scale/bottleneck-detector.test.js +187 -0
- package/dist/__tests__/scanners/scale/bottleneck-detector.test.js.map +1 -0
- package/dist/__tests__/scanners/scale/index.test.d.ts +2 -0
- package/dist/__tests__/scanners/scale/index.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/scale/index.test.js +87 -0
- package/dist/__tests__/scanners/scale/index.test.js.map +1 -0
- package/dist/__tests__/scanners/scale/load-profiler.test.d.ts +2 -0
- package/dist/__tests__/scanners/scale/load-profiler.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/scale/load-profiler.test.js +122 -0
- package/dist/__tests__/scanners/scale/load-profiler.test.js.map +1 -0
- package/dist/__tests__/scanners/scale/types.test.d.ts +2 -0
- package/dist/__tests__/scanners/scale/types.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/scale/types.test.js +129 -0
- package/dist/__tests__/scanners/scale/types.test.js.map +1 -0
- package/dist/action/pr-comment.test.js +4 -0
- package/dist/action/pr-comment.test.js.map +1 -1
- package/dist/action/sarif-upload.test.js +4 -0
- package/dist/action/sarif-upload.test.js.map +1 -1
- package/dist/autofix/branch-manager.d.ts +115 -0
- package/dist/autofix/branch-manager.d.ts.map +1 -0
- package/dist/autofix/branch-manager.js +308 -0
- package/dist/autofix/branch-manager.js.map +1 -0
- package/dist/autofix/commit-generator.d.ts +55 -0
- package/dist/autofix/commit-generator.d.ts.map +1 -0
- package/dist/autofix/commit-generator.js +277 -0
- package/dist/autofix/commit-generator.js.map +1 -0
- package/dist/autofix/constitution.d.ts +77 -0
- package/dist/autofix/constitution.d.ts.map +1 -0
- package/dist/autofix/constitution.js +261 -0
- package/dist/autofix/constitution.js.map +1 -0
- package/dist/autofix/constitution.schema.d.ts +441 -0
- package/dist/autofix/constitution.schema.d.ts.map +1 -0
- package/dist/autofix/constitution.schema.js +144 -0
- package/dist/autofix/constitution.schema.js.map +1 -0
- package/dist/autofix/index.d.ts +13 -0
- package/dist/autofix/index.d.ts.map +1 -0
- package/dist/autofix/index.js +15 -0
- package/dist/autofix/index.js.map +1 -0
- package/dist/autofix/pr-generator.d.ts +57 -0
- package/dist/autofix/pr-generator.d.ts.map +1 -0
- package/dist/autofix/pr-generator.js +597 -0
- package/dist/autofix/pr-generator.js.map +1 -0
- package/dist/autofix/types.d.ts +151 -0
- package/dist/autofix/types.d.ts.map +1 -0
- package/dist/autofix/types.js +22 -0
- package/dist/autofix/types.js.map +1 -0
- package/dist/eval/fixtures.d.ts +20 -0
- package/dist/eval/fixtures.d.ts.map +1 -1
- package/dist/eval/fixtures.js +430 -0
- package/dist/eval/fixtures.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +874 -0
- package/dist/index.js.map +1 -1
- package/dist/install-skills.d.ts +11 -0
- package/dist/install-skills.d.ts.map +1 -0
- package/dist/install-skills.js +81 -0
- package/dist/install-skills.js.map +1 -0
- package/dist/scanners/ai-code/ai-detector.d.ts +25 -0
- package/dist/scanners/ai-code/ai-detector.d.ts.map +1 -0
- package/dist/scanners/ai-code/ai-detector.js +192 -0
- package/dist/scanners/ai-code/ai-detector.js.map +1 -0
- package/dist/scanners/ai-code/confidence-scorer.d.ts +40 -0
- package/dist/scanners/ai-code/confidence-scorer.d.ts.map +1 -0
- package/dist/scanners/ai-code/confidence-scorer.js +148 -0
- package/dist/scanners/ai-code/confidence-scorer.js.map +1 -0
- package/dist/scanners/ai-code/hallucination-checker.d.ts +36 -0
- package/dist/scanners/ai-code/hallucination-checker.d.ts.map +1 -0
- package/dist/scanners/ai-code/hallucination-checker.js +298 -0
- package/dist/scanners/ai-code/hallucination-checker.js.map +1 -0
- package/dist/scanners/ai-code/index.d.ts +30 -0
- package/dist/scanners/ai-code/index.d.ts.map +1 -0
- package/dist/scanners/ai-code/index.js +224 -0
- package/dist/scanners/ai-code/index.js.map +1 -0
- package/dist/scanners/ai-code/types.d.ts +192 -0
- package/dist/scanners/ai-code/types.d.ts.map +1 -0
- package/dist/scanners/ai-code/types.js +37 -0
- package/dist/scanners/ai-code/types.js.map +1 -0
- package/dist/scanners/cache.d.ts.map +1 -1
- package/dist/scanners/cache.js +4 -0
- package/dist/scanners/cache.js.map +1 -1
- package/dist/scanners/dast/index.d.ts +39 -0
- package/dist/scanners/dast/index.d.ts.map +1 -0
- package/dist/scanners/dast/index.js +259 -0
- package/dist/scanners/dast/index.js.map +1 -0
- package/dist/scanners/dast/nuclei.d.ts +26 -0
- package/dist/scanners/dast/nuclei.d.ts.map +1 -0
- package/dist/scanners/dast/nuclei.js +354 -0
- package/dist/scanners/dast/nuclei.js.map +1 -0
- package/dist/scanners/dast/types.d.ts +306 -0
- package/dist/scanners/dast/types.d.ts.map +1 -0
- package/dist/scanners/dast/types.js +52 -0
- package/dist/scanners/dast/types.js.map +1 -0
- package/dist/scanners/dast/zap.d.ts +26 -0
- package/dist/scanners/dast/zap.d.ts.map +1 -0
- package/dist/scanners/dast/zap.js +453 -0
- package/dist/scanners/dast/zap.js.map +1 -0
- package/dist/scanners/deploy/health-checker.d.ts +38 -0
- package/dist/scanners/deploy/health-checker.d.ts.map +1 -0
- package/dist/scanners/deploy/health-checker.js +272 -0
- package/dist/scanners/deploy/health-checker.js.map +1 -0
- package/dist/scanners/deploy/index.d.ts +44 -0
- package/dist/scanners/deploy/index.d.ts.map +1 -0
- package/dist/scanners/deploy/index.js +208 -0
- package/dist/scanners/deploy/index.js.map +1 -0
- package/dist/scanners/deploy/provider-detector.d.ts +25 -0
- package/dist/scanners/deploy/provider-detector.d.ts.map +1 -0
- package/dist/scanners/deploy/provider-detector.js +177 -0
- package/dist/scanners/deploy/provider-detector.js.map +1 -0
- package/dist/scanners/deploy/types.d.ts +406 -0
- package/dist/scanners/deploy/types.d.ts.map +1 -0
- package/dist/scanners/deploy/types.js +58 -0
- package/dist/scanners/deploy/types.js.map +1 -0
- package/dist/scanners/deploy/vercel-integration.d.ts +52 -0
- package/dist/scanners/deploy/vercel-integration.d.ts.map +1 -0
- package/dist/scanners/deploy/vercel-integration.js +280 -0
- package/dist/scanners/deploy/vercel-integration.js.map +1 -0
- package/dist/scanners/fp-feedback.d.ts +140 -0
- package/dist/scanners/fp-feedback.d.ts.map +1 -0
- package/dist/scanners/fp-feedback.js +292 -0
- package/dist/scanners/fp-feedback.js.map +1 -0
- package/dist/scanners/fp-filter.d.ts +94 -0
- package/dist/scanners/fp-filter.d.ts.map +1 -0
- package/dist/scanners/fp-filter.js +397 -0
- package/dist/scanners/fp-filter.js.map +1 -0
- package/dist/scanners/fp-tracker.d.ts +125 -0
- package/dist/scanners/fp-tracker.d.ts.map +1 -0
- package/dist/scanners/fp-tracker.js +330 -0
- package/dist/scanners/fp-tracker.js.map +1 -0
- package/dist/scanners/index.d.ts.map +1 -1
- package/dist/scanners/index.js +56 -0
- package/dist/scanners/index.js.map +1 -1
- package/dist/scanners/index.test.js +6 -6
- package/dist/scanners/index.test.js.map +1 -1
- package/dist/scanners/logic/auth-flow-analyzer.d.ts +18 -0
- package/dist/scanners/logic/auth-flow-analyzer.d.ts.map +1 -0
- package/dist/scanners/logic/auth-flow-analyzer.js +384 -0
- package/dist/scanners/logic/auth-flow-analyzer.js.map +1 -0
- package/dist/scanners/logic/endpoint-analyzer.d.ts +29 -0
- package/dist/scanners/logic/endpoint-analyzer.d.ts.map +1 -0
- package/dist/scanners/logic/endpoint-analyzer.js +528 -0
- package/dist/scanners/logic/endpoint-analyzer.js.map +1 -0
- package/dist/scanners/logic/index.d.ts +41 -0
- package/dist/scanners/logic/index.d.ts.map +1 -0
- package/dist/scanners/logic/index.js +268 -0
- package/dist/scanners/logic/index.js.map +1 -0
- package/dist/scanners/logic/types.d.ts +254 -0
- package/dist/scanners/logic/types.d.ts.map +1 -0
- package/dist/scanners/logic/types.js +142 -0
- package/dist/scanners/logic/types.js.map +1 -0
- package/dist/scanners/runtime/app-launcher.d.ts +33 -0
- package/dist/scanners/runtime/app-launcher.d.ts.map +1 -0
- package/dist/scanners/runtime/app-launcher.js +419 -0
- package/dist/scanners/runtime/app-launcher.js.map +1 -0
- package/dist/scanners/runtime/golden-path-runner.d.ts +48 -0
- package/dist/scanners/runtime/golden-path-runner.d.ts.map +1 -0
- package/dist/scanners/runtime/golden-path-runner.js +373 -0
- package/dist/scanners/runtime/golden-path-runner.js.map +1 -0
- package/dist/scanners/runtime/index.d.ts +41 -0
- package/dist/scanners/runtime/index.d.ts.map +1 -0
- package/dist/scanners/runtime/index.js +164 -0
- package/dist/scanners/runtime/index.js.map +1 -0
- package/dist/scanners/runtime/playwright-executor.d.ts +50 -0
- package/dist/scanners/runtime/playwright-executor.d.ts.map +1 -0
- package/dist/scanners/runtime/playwright-executor.js +387 -0
- package/dist/scanners/runtime/playwright-executor.js.map +1 -0
- package/dist/scanners/runtime/types.d.ts +215 -0
- package/dist/scanners/runtime/types.d.ts.map +1 -0
- package/dist/scanners/runtime/types.js +40 -0
- package/dist/scanners/runtime/types.js.map +1 -0
- package/dist/scanners/scale/bottleneck-detector.d.ts +17 -0
- package/dist/scanners/scale/bottleneck-detector.d.ts.map +1 -0
- package/dist/scanners/scale/bottleneck-detector.js +250 -0
- package/dist/scanners/scale/bottleneck-detector.js.map +1 -0
- package/dist/scanners/scale/capacity-estimator.d.ts +17 -0
- package/dist/scanners/scale/capacity-estimator.d.ts.map +1 -0
- package/dist/scanners/scale/capacity-estimator.js +197 -0
- package/dist/scanners/scale/capacity-estimator.js.map +1 -0
- package/dist/scanners/scale/index.d.ts +37 -0
- package/dist/scanners/scale/index.d.ts.map +1 -0
- package/dist/scanners/scale/index.js +101 -0
- package/dist/scanners/scale/index.js.map +1 -0
- package/dist/scanners/scale/load-profiler.d.ts +48 -0
- package/dist/scanners/scale/load-profiler.d.ts.map +1 -0
- package/dist/scanners/scale/load-profiler.js +377 -0
- package/dist/scanners/scale/load-profiler.js.map +1 -0
- package/dist/scanners/scale/types.d.ts +529 -0
- package/dist/scanners/scale/types.d.ts.map +1 -0
- package/dist/scanners/scale/types.js +57 -0
- package/dist/scanners/scale/types.js.map +1 -0
- package/dist/scanners/secrets.d.ts.map +1 -1
- package/dist/scanners/secrets.js +13 -2
- package/dist/scanners/secrets.js.map +1 -1
- package/dist/scanners/types.d.ts +1 -1
- package/dist/scanners/types.d.ts.map +1 -1
- package/dist/scanners/types.js +4 -0
- package/dist/scanners/types.js.map +1 -1
- package/package.json +8 -4
- package/skills/vaspera-add-tests/SKILL.md +102 -0
- package/skills/vaspera-ai-verify/SKILL.md +166 -0
- package/skills/vaspera-audit/SKILL.md +67 -0
- package/skills/vaspera-certify/SKILL.md +130 -0
- package/skills/vaspera-deploy/SKILL.md +152 -0
- package/skills/vaspera-fix-critical/SKILL.md +52 -0
- package/skills/vaspera-fix-high/SKILL.md +81 -0
- package/skills/vaspera-fix-medium/SKILL.md +56 -0
- package/skills/vaspera-fix-rls/SKILL.md +85 -0
- package/skills/vaspera-harden/SKILL.md +102 -0
- package/skills/vaspera-help/SKILL.md +61 -0
- package/skills/vaspera-load-test/SKILL.md +167 -0
- package/skills/vaspera-verify/SKILL.md +70 -0
- package/skills/vaspera-verify-e2e/SKILL.md +117 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bottleneck Detector
|
|
3
|
+
*
|
|
4
|
+
* Analyzes load test results and code patterns to identify performance bottlenecks.
|
|
5
|
+
*
|
|
6
|
+
* @module scanners/scale/bottleneck-detector
|
|
7
|
+
*/
|
|
8
|
+
import type { Bottleneck, LoadTestResult } from "./types.js";
|
|
9
|
+
/**
|
|
10
|
+
* Detect bottlenecks in a project
|
|
11
|
+
*/
|
|
12
|
+
export declare function detectBottlenecks(projectPath: string, loadTestResults?: LoadTestResult): Promise<Bottleneck[]>;
|
|
13
|
+
/**
|
|
14
|
+
* Calculate bottleneck score (100 = no bottlenecks)
|
|
15
|
+
*/
|
|
16
|
+
export declare function calculateBottleneckScore(bottlenecks: Bottleneck[]): number;
|
|
17
|
+
//# sourceMappingURL=bottleneck-detector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bottleneck-detector.d.ts","sourceRoot":"","sources":["../../../src/scanners/scale/bottleneck-detector.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAKH,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AA+M7D;;GAEG;AACH,wBAAsB,iBAAiB,CACrC,WAAW,EAAE,MAAM,EACnB,eAAe,CAAC,EAAE,cAAc,GAC/B,OAAO,CAAC,UAAU,EAAE,CAAC,CA0BvB;AAED;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,WAAW,EAAE,UAAU,EAAE,GAAG,MAAM,CAqB1E"}
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bottleneck Detector
|
|
3
|
+
*
|
|
4
|
+
* Analyzes load test results and code patterns to identify performance bottlenecks.
|
|
5
|
+
*
|
|
6
|
+
* @module scanners/scale/bottleneck-detector
|
|
7
|
+
*/
|
|
8
|
+
import { readFile, readdir } from "fs/promises";
|
|
9
|
+
import { join } from "path";
|
|
10
|
+
import { logger } from "../../logger.js";
|
|
11
|
+
/**
|
|
12
|
+
* N+1 query pattern detection
|
|
13
|
+
*/
|
|
14
|
+
const N_PLUS_ONE_PATTERNS = [
|
|
15
|
+
// Prisma
|
|
16
|
+
/\.findMany\(\s*\{[^}]*include\s*:\s*\{/g,
|
|
17
|
+
// Sequelize
|
|
18
|
+
/\.findAll\(\s*\{[^}]*include\s*:\s*\[/g,
|
|
19
|
+
// TypeORM
|
|
20
|
+
/\.find\(\s*\{[^}]*relations\s*:\s*\[/g,
|
|
21
|
+
// Raw SQL in loop
|
|
22
|
+
/for\s*\([^)]*\)\s*\{[^}]*(?:SELECT|INSERT|UPDATE|DELETE)/gi,
|
|
23
|
+
// forEach with await
|
|
24
|
+
/\.forEach\(\s*async/g,
|
|
25
|
+
];
|
|
26
|
+
/**
|
|
27
|
+
* Memory leak patterns
|
|
28
|
+
*/
|
|
29
|
+
const MEMORY_LEAK_PATTERNS = [
|
|
30
|
+
// Growing arrays in closures
|
|
31
|
+
/const\s+\w+\s*=\s*\[\s*\][\s\S]*setInterval/g,
|
|
32
|
+
// Event listeners without cleanup
|
|
33
|
+
/addEventListener\([^)]+\)(?![\s\S]*removeEventListener)/g,
|
|
34
|
+
// Global state accumulation
|
|
35
|
+
/global\.\w+\s*=\s*\[[\s\S]*\.push\(/g,
|
|
36
|
+
];
|
|
37
|
+
/**
|
|
38
|
+
* Blocking operation patterns
|
|
39
|
+
*/
|
|
40
|
+
const BLOCKING_PATTERNS = [
|
|
41
|
+
// Sync file operations
|
|
42
|
+
/(?:readFileSync|writeFileSync|existsSync|statSync)/g,
|
|
43
|
+
// Blocking crypto
|
|
44
|
+
/crypto\.(?:pbkdf2Sync|scryptSync|randomBytes)\s*\(/g,
|
|
45
|
+
// Large JSON parsing
|
|
46
|
+
/JSON\.parse\([^)]*\.length\s*>\s*\d{6}/g,
|
|
47
|
+
];
|
|
48
|
+
/**
|
|
49
|
+
* Analyze source code for potential bottlenecks
|
|
50
|
+
*/
|
|
51
|
+
async function analyzeSourceCode(projectPath) {
|
|
52
|
+
const bottlenecks = [];
|
|
53
|
+
const srcDirs = ["src", "app", "pages", "api", "lib"];
|
|
54
|
+
for (const dir of srcDirs) {
|
|
55
|
+
try {
|
|
56
|
+
const dirPath = join(projectPath, dir);
|
|
57
|
+
const files = await readdir(dirPath, { recursive: true });
|
|
58
|
+
for (const file of files) {
|
|
59
|
+
if (typeof file !== "string")
|
|
60
|
+
continue;
|
|
61
|
+
if (!file.match(/\.(ts|js|tsx|jsx)$/))
|
|
62
|
+
continue;
|
|
63
|
+
try {
|
|
64
|
+
const filePath = join(dirPath, file);
|
|
65
|
+
const content = await readFile(filePath, "utf-8");
|
|
66
|
+
// Check for N+1 patterns
|
|
67
|
+
for (const pattern of N_PLUS_ONE_PATTERNS) {
|
|
68
|
+
const matches = content.match(pattern);
|
|
69
|
+
if (matches && matches.length > 0) {
|
|
70
|
+
bottlenecks.push({
|
|
71
|
+
type: "database",
|
|
72
|
+
location: `${dir}/${file}`,
|
|
73
|
+
severity: "high",
|
|
74
|
+
description: `Potential N+1 query pattern detected (${matches.length} occurrences)`,
|
|
75
|
+
metrics: {
|
|
76
|
+
current: matches.length,
|
|
77
|
+
threshold: 0,
|
|
78
|
+
unit: "patterns",
|
|
79
|
+
},
|
|
80
|
+
recommendation: "Consider using eager loading or batching queries",
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
// Check for memory leak patterns
|
|
85
|
+
for (const pattern of MEMORY_LEAK_PATTERNS) {
|
|
86
|
+
const matches = content.match(pattern);
|
|
87
|
+
if (matches && matches.length > 0) {
|
|
88
|
+
bottlenecks.push({
|
|
89
|
+
type: "memory",
|
|
90
|
+
location: `${dir}/${file}`,
|
|
91
|
+
severity: "medium",
|
|
92
|
+
description: `Potential memory leak pattern detected`,
|
|
93
|
+
metrics: {
|
|
94
|
+
current: matches.length,
|
|
95
|
+
threshold: 0,
|
|
96
|
+
unit: "patterns",
|
|
97
|
+
},
|
|
98
|
+
recommendation: "Ensure proper cleanup of resources and event listeners",
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
// Check for blocking patterns
|
|
103
|
+
for (const pattern of BLOCKING_PATTERNS) {
|
|
104
|
+
const matches = content.match(pattern);
|
|
105
|
+
if (matches && matches.length > 0) {
|
|
106
|
+
bottlenecks.push({
|
|
107
|
+
type: "cpu",
|
|
108
|
+
location: `${dir}/${file}`,
|
|
109
|
+
severity: "medium",
|
|
110
|
+
description: `Blocking operation detected: ${matches[0]}`,
|
|
111
|
+
metrics: {
|
|
112
|
+
current: matches.length,
|
|
113
|
+
threshold: 0,
|
|
114
|
+
unit: "occurrences",
|
|
115
|
+
},
|
|
116
|
+
recommendation: "Use async alternatives to avoid blocking the event loop",
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
catch {
|
|
122
|
+
// Skip files that can't be read
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
// Directory doesn't exist
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return bottlenecks;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Analyze load test results for bottlenecks
|
|
134
|
+
*/
|
|
135
|
+
function analyzeLoadTestResults(results) {
|
|
136
|
+
const bottlenecks = [];
|
|
137
|
+
// Check for high latency
|
|
138
|
+
if (results.summary.latency.p95 > 500) {
|
|
139
|
+
bottlenecks.push({
|
|
140
|
+
type: "endpoint",
|
|
141
|
+
location: "Overall API",
|
|
142
|
+
severity: results.summary.latency.p95 > 1000 ? "critical" : "high",
|
|
143
|
+
description: `High 95th percentile latency: ${results.summary.latency.p95.toFixed(0)}ms`,
|
|
144
|
+
metrics: {
|
|
145
|
+
current: results.summary.latency.p95,
|
|
146
|
+
threshold: 500,
|
|
147
|
+
unit: "ms",
|
|
148
|
+
},
|
|
149
|
+
recommendation: "Profile endpoints to identify slow operations, add caching, or optimize queries",
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
// Check for high error rate
|
|
153
|
+
if (results.summary.errorRate > 0.01) {
|
|
154
|
+
bottlenecks.push({
|
|
155
|
+
type: "endpoint",
|
|
156
|
+
location: "Overall API",
|
|
157
|
+
severity: results.summary.errorRate > 0.05 ? "critical" : "high",
|
|
158
|
+
description: `High error rate: ${(results.summary.errorRate * 100).toFixed(2)}%`,
|
|
159
|
+
metrics: {
|
|
160
|
+
current: results.summary.errorRate,
|
|
161
|
+
threshold: 0.01,
|
|
162
|
+
unit: "rate",
|
|
163
|
+
},
|
|
164
|
+
recommendation: "Check error logs, add retry logic, or scale resources",
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
// Check for low throughput
|
|
168
|
+
if (results.summary.avgThroughput < 100) {
|
|
169
|
+
bottlenecks.push({
|
|
170
|
+
type: "endpoint",
|
|
171
|
+
location: "Overall API",
|
|
172
|
+
severity: "medium",
|
|
173
|
+
description: `Low throughput: ${results.summary.avgThroughput.toFixed(1)} req/s`,
|
|
174
|
+
metrics: {
|
|
175
|
+
current: results.summary.avgThroughput,
|
|
176
|
+
threshold: 100,
|
|
177
|
+
unit: "req/s",
|
|
178
|
+
},
|
|
179
|
+
recommendation: "Consider horizontal scaling or optimizing request handling",
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
// Check individual endpoints
|
|
183
|
+
for (const scenario of results.scenarios) {
|
|
184
|
+
for (const endpoint of scenario.endpoints) {
|
|
185
|
+
if (endpoint.latency.p95 > 500) {
|
|
186
|
+
bottlenecks.push({
|
|
187
|
+
type: "endpoint",
|
|
188
|
+
location: `${endpoint.method} ${endpoint.path}`,
|
|
189
|
+
severity: endpoint.latency.p95 > 1000 ? "critical" : "high",
|
|
190
|
+
description: `Slow endpoint: p95=${endpoint.latency.p95.toFixed(0)}ms`,
|
|
191
|
+
metrics: {
|
|
192
|
+
current: endpoint.latency.p95,
|
|
193
|
+
threshold: 500,
|
|
194
|
+
unit: "ms",
|
|
195
|
+
},
|
|
196
|
+
recommendation: "Add endpoint-specific caching or optimize the handler",
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
return bottlenecks;
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Detect bottlenecks in a project
|
|
205
|
+
*/
|
|
206
|
+
export async function detectBottlenecks(projectPath, loadTestResults) {
|
|
207
|
+
const bottlenecks = [];
|
|
208
|
+
logger.info("scale.bottleneck_detection_started", { projectPath });
|
|
209
|
+
// Analyze source code
|
|
210
|
+
const codeBottlenecks = await analyzeSourceCode(projectPath);
|
|
211
|
+
bottlenecks.push(...codeBottlenecks);
|
|
212
|
+
// Analyze load test results if available
|
|
213
|
+
if (loadTestResults) {
|
|
214
|
+
const loadBottlenecks = analyzeLoadTestResults(loadTestResults);
|
|
215
|
+
bottlenecks.push(...loadBottlenecks);
|
|
216
|
+
}
|
|
217
|
+
// Sort by severity
|
|
218
|
+
const severityOrder = { critical: 0, high: 1, medium: 2, low: 3 };
|
|
219
|
+
bottlenecks.sort((a, b) => severityOrder[a.severity] - severityOrder[b.severity]);
|
|
220
|
+
logger.info("scale.bottleneck_detection_completed", {
|
|
221
|
+
total: bottlenecks.length,
|
|
222
|
+
critical: bottlenecks.filter((b) => b.severity === "critical").length,
|
|
223
|
+
high: bottlenecks.filter((b) => b.severity === "high").length,
|
|
224
|
+
});
|
|
225
|
+
return bottlenecks;
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Calculate bottleneck score (100 = no bottlenecks)
|
|
229
|
+
*/
|
|
230
|
+
export function calculateBottleneckScore(bottlenecks) {
|
|
231
|
+
let score = 100;
|
|
232
|
+
for (const bottleneck of bottlenecks) {
|
|
233
|
+
switch (bottleneck.severity) {
|
|
234
|
+
case "critical":
|
|
235
|
+
score -= 25;
|
|
236
|
+
break;
|
|
237
|
+
case "high":
|
|
238
|
+
score -= 15;
|
|
239
|
+
break;
|
|
240
|
+
case "medium":
|
|
241
|
+
score -= 8;
|
|
242
|
+
break;
|
|
243
|
+
case "low":
|
|
244
|
+
score -= 3;
|
|
245
|
+
break;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
return Math.max(0, score);
|
|
249
|
+
}
|
|
250
|
+
//# sourceMappingURL=bottleneck-detector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bottleneck-detector.js","sourceRoot":"","sources":["../../../src/scanners/scale/bottleneck-detector.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAGzC;;GAEG;AACH,MAAM,mBAAmB,GAAG;IAC1B,SAAS;IACT,yCAAyC;IACzC,YAAY;IACZ,wCAAwC;IACxC,UAAU;IACV,uCAAuC;IACvC,kBAAkB;IAClB,4DAA4D;IAC5D,qBAAqB;IACrB,sBAAsB;CACvB,CAAC;AAEF;;GAEG;AACH,MAAM,oBAAoB,GAAG;IAC3B,6BAA6B;IAC7B,8CAA8C;IAC9C,kCAAkC;IAClC,0DAA0D;IAC1D,4BAA4B;IAC5B,sCAAsC;CACvC,CAAC;AAEF;;GAEG;AACH,MAAM,iBAAiB,GAAG;IACxB,uBAAuB;IACvB,qDAAqD;IACrD,kBAAkB;IAClB,qDAAqD;IACrD,qBAAqB;IACrB,yCAAyC;CAC1C,CAAC;AAEF;;GAEG;AACH,KAAK,UAAU,iBAAiB,CAAC,WAAmB;IAClD,MAAM,WAAW,GAAiB,EAAE,CAAC;IACrC,MAAM,OAAO,GAAG,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;IAEtD,KAAK,MAAM,GAAG,IAAI,OAAO,EAAE,CAAC;QAC1B,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC;YACvC,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YAE1D,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;gBACzB,IAAI,OAAO,IAAI,KAAK,QAAQ;oBAAE,SAAS;gBACvC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,oBAAoB,CAAC;oBAAE,SAAS;gBAEhD,IAAI,CAAC;oBACH,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;oBACrC,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;oBAElD,yBAAyB;oBACzB,KAAK,MAAM,OAAO,IAAI,mBAAmB,EAAE,CAAC;wBAC1C,MAAM,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;wBACvC,IAAI,OAAO,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;4BAClC,WAAW,CAAC,IAAI,CAAC;gCACf,IAAI,EAAE,UAAU;gCAChB,QAAQ,EAAE,GAAG,GAAG,IAAI,IAAI,EAAE;gCAC1B,QAAQ,EAAE,MAAM;gCAChB,WAAW,EAAE,yCAAyC,OAAO,CAAC,MAAM,eAAe;gCACnF,OAAO,EAAE;oCACP,OAAO,EAAE,OAAO,CAAC,MAAM;oCACvB,SAAS,EAAE,CAAC;oCACZ,IAAI,EAAE,UAAU;iCACjB;gCACD,cAAc,EAAE,kDAAkD;6BACnE,CAAC,CAAC;wBACL,CAAC;oBACH,CAAC;oBAED,iCAAiC;oBACjC,KAAK,MAAM,OAAO,IAAI,oBAAoB,EAAE,CAAC;wBAC3C,MAAM,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;wBACvC,IAAI,OAAO,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;4BAClC,WAAW,CAAC,IAAI,CAAC;gCACf,IAAI,EAAE,QAAQ;gCACd,QAAQ,EAAE,GAAG,GAAG,IAAI,IAAI,EAAE;gCAC1B,QAAQ,EAAE,QAAQ;gCAClB,WAAW,EAAE,wCAAwC;gCACrD,OAAO,EAAE;oCACP,OAAO,EAAE,OAAO,CAAC,MAAM;oCACvB,SAAS,EAAE,CAAC;oCACZ,IAAI,EAAE,UAAU;iCACjB;gCACD,cAAc,EAAE,wDAAwD;6BACzE,CAAC,CAAC;wBACL,CAAC;oBACH,CAAC;oBAED,8BAA8B;oBAC9B,KAAK,MAAM,OAAO,IAAI,iBAAiB,EAAE,CAAC;wBACxC,MAAM,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;wBACvC,IAAI,OAAO,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;4BAClC,WAAW,CAAC,IAAI,CAAC;gCACf,IAAI,EAAE,KAAK;gCACX,QAAQ,EAAE,GAAG,GAAG,IAAI,IAAI,EAAE;gCAC1B,QAAQ,EAAE,QAAQ;gCAClB,WAAW,EAAE,gCAAgC,OAAO,CAAC,CAAC,CAAC,EAAE;gCACzD,OAAO,EAAE;oCACP,OAAO,EAAE,OAAO,CAAC,MAAM;oCACvB,SAAS,EAAE,CAAC;oCACZ,IAAI,EAAE,aAAa;iCACpB;gCACD,cAAc,EAAE,yDAAyD;6BAC1E,CAAC,CAAC;wBACL,CAAC;oBACH,CAAC;gBACH,CAAC;gBAAC,MAAM,CAAC;oBACP,gCAAgC;gBAClC,CAAC;YACH,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,0BAA0B;QAC5B,CAAC;IACH,CAAC;IAED,OAAO,WAAW,CAAC;AACrB,CAAC;AAED;;GAEG;AACH,SAAS,sBAAsB,CAAC,OAAuB;IACrD,MAAM,WAAW,GAAiB,EAAE,CAAC;IAErC,yBAAyB;IACzB,IAAI,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,GAAG,GAAG,EAAE,CAAC;QACtC,WAAW,CAAC,IAAI,CAAC;YACf,IAAI,EAAE,UAAU;YAChB,QAAQ,EAAE,aAAa;YACvB,QAAQ,EAAE,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM;YAClE,WAAW,EAAE,iCAAiC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI;YACxF,OAAO,EAAE;gBACP,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG;gBACpC,SAAS,EAAE,GAAG;gBACd,IAAI,EAAE,IAAI;aACX;YACD,cAAc,EAAE,iFAAiF;SAClG,CAAC,CAAC;IACL,CAAC;IAED,4BAA4B;IAC5B,IAAI,OAAO,CAAC,OAAO,CAAC,SAAS,GAAG,IAAI,EAAE,CAAC;QACrC,WAAW,CAAC,IAAI,CAAC;YACf,IAAI,EAAE,UAAU;YAChB,QAAQ,EAAE,aAAa;YACvB,QAAQ,EAAE,OAAO,CAAC,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM;YAChE,WAAW,EAAE,oBAAoB,CAAC,OAAO,CAAC,OAAO,CAAC,SAAS,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG;YAChF,OAAO,EAAE;gBACP,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,SAAS;gBAClC,SAAS,EAAE,IAAI;gBACf,IAAI,EAAE,MAAM;aACb;YACD,cAAc,EAAE,uDAAuD;SACxE,CAAC,CAAC;IACL,CAAC;IAED,2BAA2B;IAC3B,IAAI,OAAO,CAAC,OAAO,CAAC,aAAa,GAAG,GAAG,EAAE,CAAC;QACxC,WAAW,CAAC,IAAI,CAAC;YACf,IAAI,EAAE,UAAU;YAChB,QAAQ,EAAE,aAAa;YACvB,QAAQ,EAAE,QAAQ;YAClB,WAAW,EAAE,mBAAmB,OAAO,CAAC,OAAO,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ;YAChF,OAAO,EAAE;gBACP,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,aAAa;gBACtC,SAAS,EAAE,GAAG;gBACd,IAAI,EAAE,OAAO;aACd;YACD,cAAc,EAAE,4DAA4D;SAC7E,CAAC,CAAC;IACL,CAAC;IAED,6BAA6B;IAC7B,KAAK,MAAM,QAAQ,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;QACzC,KAAK,MAAM,QAAQ,IAAI,QAAQ,CAAC,SAAS,EAAE,CAAC;YAC1C,IAAI,QAAQ,CAAC,OAAO,CAAC,GAAG,GAAG,GAAG,EAAE,CAAC;gBAC/B,WAAW,CAAC,IAAI,CAAC;oBACf,IAAI,EAAE,UAAU;oBAChB,QAAQ,EAAE,GAAG,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,IAAI,EAAE;oBAC/C,QAAQ,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM;oBAC3D,WAAW,EAAE,sBAAsB,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI;oBACtE,OAAO,EAAE;wBACP,OAAO,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG;wBAC7B,SAAS,EAAE,GAAG;wBACd,IAAI,EAAE,IAAI;qBACX;oBACD,cAAc,EAAE,uDAAuD;iBACxE,CAAC,CAAC;YACL,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,WAAW,CAAC;AACrB,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,WAAmB,EACnB,eAAgC;IAEhC,MAAM,WAAW,GAAiB,EAAE,CAAC;IAErC,MAAM,CAAC,IAAI,CAAC,oCAAoC,EAAE,EAAE,WAAW,EAAE,CAAC,CAAC;IAEnE,sBAAsB;IACtB,MAAM,eAAe,GAAG,MAAM,iBAAiB,CAAC,WAAW,CAAC,CAAC;IAC7D,WAAW,CAAC,IAAI,CAAC,GAAG,eAAe,CAAC,CAAC;IAErC,yCAAyC;IACzC,IAAI,eAAe,EAAE,CAAC;QACpB,MAAM,eAAe,GAAG,sBAAsB,CAAC,eAAe,CAAC,CAAC;QAChE,WAAW,CAAC,IAAI,CAAC,GAAG,eAAe,CAAC,CAAC;IACvC,CAAC;IAED,mBAAmB;IACnB,MAAM,aAAa,GAAG,EAAE,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC;IAClE,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;IAElF,MAAM,CAAC,IAAI,CAAC,sCAAsC,EAAE;QAClD,KAAK,EAAE,WAAW,CAAC,MAAM;QACzB,QAAQ,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,UAAU,CAAC,CAAC,MAAM;QACrE,IAAI,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,MAAM,CAAC,CAAC,MAAM;KAC9D,CAAC,CAAC;IAEH,OAAO,WAAW,CAAC;AACrB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,wBAAwB,CAAC,WAAyB;IAChE,IAAI,KAAK,GAAG,GAAG,CAAC;IAEhB,KAAK,MAAM,UAAU,IAAI,WAAW,EAAE,CAAC;QACrC,QAAQ,UAAU,CAAC,QAAQ,EAAE,CAAC;YAC5B,KAAK,UAAU;gBACb,KAAK,IAAI,EAAE,CAAC;gBACZ,MAAM;YACR,KAAK,MAAM;gBACT,KAAK,IAAI,EAAE,CAAC;gBACZ,MAAM;YACR,KAAK,QAAQ;gBACX,KAAK,IAAI,CAAC,CAAC;gBACX,MAAM;YACR,KAAK,KAAK;gBACR,KAAK,IAAI,CAAC,CAAC;gBACX,MAAM;QACV,CAAC;IACH,CAAC;IAED,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;AAC5B,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Capacity Estimator
|
|
3
|
+
*
|
|
4
|
+
* Estimates maximum capacity and projects costs based on load test results.
|
|
5
|
+
*
|
|
6
|
+
* @module scanners/scale/capacity-estimator
|
|
7
|
+
*/
|
|
8
|
+
import type { CapacityEstimate, LoadTestResult, Bottleneck } from "./types.js";
|
|
9
|
+
/**
|
|
10
|
+
* Estimate capacity for a project
|
|
11
|
+
*/
|
|
12
|
+
export declare function estimateCapacity(loadTestResult?: LoadTestResult, bottlenecks?: Bottleneck[]): Promise<CapacityEstimate>;
|
|
13
|
+
/**
|
|
14
|
+
* Calculate capacity score (100 = excellent capacity margin)
|
|
15
|
+
*/
|
|
16
|
+
export declare function calculateCapacityScore(estimate: CapacityEstimate, targetConcurrent?: number): number;
|
|
17
|
+
//# sourceMappingURL=capacity-estimator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capacity-estimator.d.ts","sourceRoot":"","sources":["../../../src/scanners/scale/capacity-estimator.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,EAAE,gBAAgB,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAiK/E;;GAEG;AACH,wBAAsB,gBAAgB,CACpC,cAAc,CAAC,EAAE,cAAc,EAC/B,WAAW,GAAE,UAAU,EAAO,GAC7B,OAAO,CAAC,gBAAgB,CAAC,CAuC3B;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,gBAAgB,EAC1B,gBAAgB,GAAE,MAAY,GAC7B,MAAM,CAUR"}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Capacity Estimator
|
|
3
|
+
*
|
|
4
|
+
* Estimates maximum capacity and projects costs based on load test results.
|
|
5
|
+
*
|
|
6
|
+
* @module scanners/scale/capacity-estimator
|
|
7
|
+
*/
|
|
8
|
+
import { logger } from "../../logger.js";
|
|
9
|
+
/**
|
|
10
|
+
* Instance type pricing (approximate monthly costs)
|
|
11
|
+
*/
|
|
12
|
+
const INSTANCE_PRICING = {
|
|
13
|
+
// AWS EC2 (us-east-1)
|
|
14
|
+
"t3.micro": { cpu: 2, memory: 1, price: 8 },
|
|
15
|
+
"t3.small": { cpu: 2, memory: 2, price: 15 },
|
|
16
|
+
"t3.medium": { cpu: 2, memory: 4, price: 30 },
|
|
17
|
+
"t3.large": { cpu: 2, memory: 8, price: 60 },
|
|
18
|
+
"t3.xlarge": { cpu: 4, memory: 16, price: 120 },
|
|
19
|
+
"m5.large": { cpu: 2, memory: 8, price: 70 },
|
|
20
|
+
"m5.xlarge": { cpu: 4, memory: 16, price: 140 },
|
|
21
|
+
"m5.2xlarge": { cpu: 8, memory: 32, price: 280 },
|
|
22
|
+
// Vercel (approximate)
|
|
23
|
+
"vercel-hobby": { cpu: 1, memory: 1, price: 0 },
|
|
24
|
+
"vercel-pro": { cpu: 1, memory: 1, price: 20 },
|
|
25
|
+
"vercel-enterprise": { cpu: 4, memory: 4, price: 500 },
|
|
26
|
+
// Railway
|
|
27
|
+
"railway-starter": { cpu: 1, memory: 0.5, price: 5 },
|
|
28
|
+
"railway-pro": { cpu: 2, memory: 2, price: 20 },
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Estimate breakpoint (where system starts failing)
|
|
32
|
+
*/
|
|
33
|
+
function estimateBreakpoint(loadTestResult) {
|
|
34
|
+
// Use Little's Law and observed metrics
|
|
35
|
+
const avgLatency = loadTestResult.summary.latency.mean;
|
|
36
|
+
const throughput = loadTestResult.summary.avgThroughput;
|
|
37
|
+
const errorRate = loadTestResult.summary.errorRate;
|
|
38
|
+
// Find the scenario with highest VUs
|
|
39
|
+
const maxVus = Math.max(...loadTestResult.scenarios.map((s) => s.vusMax));
|
|
40
|
+
// If error rate is already high, breakpoint is near current load
|
|
41
|
+
if (errorRate > 0.05) {
|
|
42
|
+
return {
|
|
43
|
+
vus: Math.round(maxVus * 0.8),
|
|
44
|
+
confidence: 0.7,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
// If latency is degraded but not failing, estimate 50% more capacity
|
|
48
|
+
if (loadTestResult.summary.latency.p95 > 500) {
|
|
49
|
+
return {
|
|
50
|
+
vus: Math.round(maxVus * 1.2),
|
|
51
|
+
confidence: 0.6,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
// System handling load well, estimate 2x capacity
|
|
55
|
+
if (errorRate < 0.01 && avgLatency < 200) {
|
|
56
|
+
return {
|
|
57
|
+
vus: Math.round(maxVus * 2.5),
|
|
58
|
+
confidence: 0.5,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
// Default conservative estimate
|
|
62
|
+
return {
|
|
63
|
+
vus: Math.round(maxVus * 1.5),
|
|
64
|
+
confidence: 0.4,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Calculate maximum requests per second
|
|
69
|
+
*/
|
|
70
|
+
function estimateMaxRPS(loadTestResult) {
|
|
71
|
+
const breakpoint = estimateBreakpoint(loadTestResult);
|
|
72
|
+
const currentRPS = loadTestResult.summary.avgThroughput;
|
|
73
|
+
const currentVUs = Math.max(...loadTestResult.scenarios.map((s) => s.vusMax));
|
|
74
|
+
if (currentVUs === 0)
|
|
75
|
+
return 0;
|
|
76
|
+
// Linear extrapolation with degradation factor
|
|
77
|
+
const rpsPerVU = currentRPS / currentVUs;
|
|
78
|
+
const degradationFactor = 0.8; // Assume 20% degradation at scale
|
|
79
|
+
return Math.round(breakpoint.vus * rpsPerVU * degradationFactor);
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Generate recommendations based on results
|
|
83
|
+
*/
|
|
84
|
+
function generateRecommendations(loadTestResult, bottlenecks) {
|
|
85
|
+
const recommendations = [];
|
|
86
|
+
// High latency recommendations
|
|
87
|
+
if (loadTestResult.summary.latency.p95 > 500) {
|
|
88
|
+
recommendations.push("Add application-level caching (Redis, Memcached) to reduce database load");
|
|
89
|
+
recommendations.push("Consider using a CDN for static assets and cacheable API responses");
|
|
90
|
+
}
|
|
91
|
+
// High error rate recommendations
|
|
92
|
+
if (loadTestResult.summary.errorRate > 0.01) {
|
|
93
|
+
recommendations.push("Implement circuit breakers to prevent cascade failures");
|
|
94
|
+
recommendations.push("Add rate limiting to protect against traffic spikes");
|
|
95
|
+
}
|
|
96
|
+
// Database bottlenecks
|
|
97
|
+
const dbBottlenecks = bottlenecks.filter((b) => b.type === "database");
|
|
98
|
+
if (dbBottlenecks.length > 0) {
|
|
99
|
+
recommendations.push("Optimize database queries - add indexes and use connection pooling");
|
|
100
|
+
recommendations.push("Consider read replicas for read-heavy workloads");
|
|
101
|
+
}
|
|
102
|
+
// Memory bottlenecks
|
|
103
|
+
const memBottlenecks = bottlenecks.filter((b) => b.type === "memory");
|
|
104
|
+
if (memBottlenecks.length > 0) {
|
|
105
|
+
recommendations.push("Profile memory usage and fix potential leaks");
|
|
106
|
+
recommendations.push("Consider increasing instance memory or using smaller request payloads");
|
|
107
|
+
}
|
|
108
|
+
// General scaling recommendations
|
|
109
|
+
if (loadTestResult.summary.avgThroughput < 100) {
|
|
110
|
+
recommendations.push("Consider horizontal scaling with a load balancer");
|
|
111
|
+
}
|
|
112
|
+
// Add default if no specific recommendations
|
|
113
|
+
if (recommendations.length === 0) {
|
|
114
|
+
recommendations.push("System performing well - monitor for degradation at higher loads");
|
|
115
|
+
}
|
|
116
|
+
return recommendations;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Project infrastructure costs
|
|
120
|
+
*/
|
|
121
|
+
function projectCosts(maxRPS, maxConcurrent) {
|
|
122
|
+
// Simple heuristic: 1000 RPS per m5.large
|
|
123
|
+
const rpsPerInstance = 1000;
|
|
124
|
+
const instancesNeeded = Math.ceil(maxRPS / rpsPerInstance);
|
|
125
|
+
// Choose appropriate instance type
|
|
126
|
+
let instanceType = "t3.medium";
|
|
127
|
+
if (maxConcurrent > 500)
|
|
128
|
+
instanceType = "t3.large";
|
|
129
|
+
if (maxConcurrent > 1000)
|
|
130
|
+
instanceType = "m5.large";
|
|
131
|
+
if (maxConcurrent > 5000)
|
|
132
|
+
instanceType = "m5.xlarge";
|
|
133
|
+
const pricing = INSTANCE_PRICING[instanceType];
|
|
134
|
+
return {
|
|
135
|
+
provider: "AWS",
|
|
136
|
+
instanceType,
|
|
137
|
+
instances: Math.max(2, instancesNeeded), // At least 2 for HA
|
|
138
|
+
monthlyCost: Math.max(2, instancesNeeded) * pricing.price,
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Estimate capacity for a project
|
|
143
|
+
*/
|
|
144
|
+
export async function estimateCapacity(loadTestResult, bottlenecks = []) {
|
|
145
|
+
logger.info("scale.capacity_estimation_started");
|
|
146
|
+
// If no load test results, return conservative estimates
|
|
147
|
+
if (!loadTestResult) {
|
|
148
|
+
return {
|
|
149
|
+
maxConcurrentUsers: 100,
|
|
150
|
+
maxRequestsPerSecond: 50,
|
|
151
|
+
estimatedBreakpoint: {
|
|
152
|
+
vus: 200,
|
|
153
|
+
confidence: 0.2,
|
|
154
|
+
},
|
|
155
|
+
recommendations: [
|
|
156
|
+
"Run load tests to get accurate capacity estimates",
|
|
157
|
+
"Start with baseline performance monitoring",
|
|
158
|
+
],
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
const breakpoint = estimateBreakpoint(loadTestResult);
|
|
162
|
+
const maxRPS = estimateMaxRPS(loadTestResult);
|
|
163
|
+
const recommendations = generateRecommendations(loadTestResult, bottlenecks);
|
|
164
|
+
const costProjection = projectCosts(maxRPS, breakpoint.vus);
|
|
165
|
+
const estimate = {
|
|
166
|
+
maxConcurrentUsers: breakpoint.vus,
|
|
167
|
+
maxRequestsPerSecond: maxRPS,
|
|
168
|
+
estimatedBreakpoint: breakpoint,
|
|
169
|
+
recommendations,
|
|
170
|
+
costProjection,
|
|
171
|
+
};
|
|
172
|
+
logger.info("scale.capacity_estimation_completed", {
|
|
173
|
+
maxConcurrent: estimate.maxConcurrentUsers,
|
|
174
|
+
maxRPS: estimate.maxRequestsPerSecond,
|
|
175
|
+
confidence: breakpoint.confidence,
|
|
176
|
+
});
|
|
177
|
+
return estimate;
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Calculate capacity score (100 = excellent capacity margin)
|
|
181
|
+
*/
|
|
182
|
+
export function calculateCapacityScore(estimate, targetConcurrent = 100) {
|
|
183
|
+
// Score based on how much headroom we have
|
|
184
|
+
const headroom = estimate.maxConcurrentUsers / targetConcurrent;
|
|
185
|
+
if (headroom >= 5)
|
|
186
|
+
return 100; // 5x headroom
|
|
187
|
+
if (headroom >= 3)
|
|
188
|
+
return 90; // 3x headroom
|
|
189
|
+
if (headroom >= 2)
|
|
190
|
+
return 80; // 2x headroom
|
|
191
|
+
if (headroom >= 1.5)
|
|
192
|
+
return 70; // 1.5x headroom
|
|
193
|
+
if (headroom >= 1)
|
|
194
|
+
return 50; // Just meeting target
|
|
195
|
+
return Math.round(headroom * 50); // Below target
|
|
196
|
+
}
|
|
197
|
+
//# sourceMappingURL=capacity-estimator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capacity-estimator.js","sourceRoot":"","sources":["../../../src/scanners/scale/capacity-estimator.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAGzC;;GAEG;AACH,MAAM,gBAAgB,GAAmE;IACvF,sBAAsB;IACtB,UAAU,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE;IAC3C,UAAU,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE;IAC5C,WAAW,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE;IAC7C,UAAU,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE;IAC5C,WAAW,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE;IAC/C,UAAU,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE;IAC5C,WAAW,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE;IAC/C,YAAY,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE;IAChD,uBAAuB;IACvB,cAAc,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE;IAC/C,YAAY,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE;IAC9C,mBAAmB,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE;IACtD,UAAU;IACV,iBAAiB,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE;IACpD,aAAa,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE;CAChD,CAAC;AAEF;;GAEG;AACH,SAAS,kBAAkB,CACzB,cAA8B;IAE9B,wCAAwC;IACxC,MAAM,UAAU,GAAG,cAAc,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC;IACvD,MAAM,UAAU,GAAG,cAAc,CAAC,OAAO,CAAC,aAAa,CAAC;IACxD,MAAM,SAAS,GAAG,cAAc,CAAC,OAAO,CAAC,SAAS,CAAC;IAEnD,qCAAqC;IACrC,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,cAAc,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;IAE1E,iEAAiE;IACjE,IAAI,SAAS,GAAG,IAAI,EAAE,CAAC;QACrB,OAAO;YACL,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,GAAG,CAAC;YAC7B,UAAU,EAAE,GAAG;SAChB,CAAC;IACJ,CAAC;IAED,qEAAqE;IACrE,IAAI,cAAc,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,GAAG,GAAG,EAAE,CAAC;QAC7C,OAAO;YACL,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,GAAG,CAAC;YAC7B,UAAU,EAAE,GAAG;SAChB,CAAC;IACJ,CAAC;IAED,kDAAkD;IAClD,IAAI,SAAS,GAAG,IAAI,IAAI,UAAU,GAAG,GAAG,EAAE,CAAC;QACzC,OAAO;YACL,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,GAAG,CAAC;YAC7B,UAAU,EAAE,GAAG;SAChB,CAAC;IACJ,CAAC;IAED,gCAAgC;IAChC,OAAO;QACL,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,GAAG,CAAC;QAC7B,UAAU,EAAE,GAAG;KAChB,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,SAAS,cAAc,CAAC,cAA8B;IACpD,MAAM,UAAU,GAAG,kBAAkB,CAAC,cAAc,CAAC,CAAC;IACtD,MAAM,UAAU,GAAG,cAAc,CAAC,OAAO,CAAC,aAAa,CAAC;IACxD,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,cAAc,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;IAE9E,IAAI,UAAU,KAAK,CAAC;QAAE,OAAO,CAAC,CAAC;IAE/B,+CAA+C;IAC/C,MAAM,QAAQ,GAAG,UAAU,GAAG,UAAU,CAAC;IACzC,MAAM,iBAAiB,GAAG,GAAG,CAAC,CAAC,kCAAkC;IAEjE,OAAO,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,GAAG,QAAQ,GAAG,iBAAiB,CAAC,CAAC;AACnE,CAAC;AAED;;GAEG;AACH,SAAS,uBAAuB,CAC9B,cAA8B,EAC9B,WAAyB;IAEzB,MAAM,eAAe,GAAa,EAAE,CAAC;IAErC,+BAA+B;IAC/B,IAAI,cAAc,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,GAAG,GAAG,EAAE,CAAC;QAC7C,eAAe,CAAC,IAAI,CAAC,0EAA0E,CAAC,CAAC;QACjG,eAAe,CAAC,IAAI,CAAC,oEAAoE,CAAC,CAAC;IAC7F,CAAC;IAED,kCAAkC;IAClC,IAAI,cAAc,CAAC,OAAO,CAAC,SAAS,GAAG,IAAI,EAAE,CAAC;QAC5C,eAAe,CAAC,IAAI,CAAC,wDAAwD,CAAC,CAAC;QAC/E,eAAe,CAAC,IAAI,CAAC,qDAAqD,CAAC,CAAC;IAC9E,CAAC;IAED,uBAAuB;IACvB,MAAM,aAAa,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,UAAU,CAAC,CAAC;IACvE,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC7B,eAAe,CAAC,IAAI,CAAC,oEAAoE,CAAC,CAAC;QAC3F,eAAe,CAAC,IAAI,CAAC,iDAAiD,CAAC,CAAC;IAC1E,CAAC;IAED,qBAAqB;IACrB,MAAM,cAAc,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC;IACtE,IAAI,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC9B,eAAe,CAAC,IAAI,CAAC,8CAA8C,CAAC,CAAC;QACrE,eAAe,CAAC,IAAI,CAAC,uEAAuE,CAAC,CAAC;IAChG,CAAC;IAED,kCAAkC;IAClC,IAAI,cAAc,CAAC,OAAO,CAAC,aAAa,GAAG,GAAG,EAAE,CAAC;QAC/C,eAAe,CAAC,IAAI,CAAC,kDAAkD,CAAC,CAAC;IAC3E,CAAC;IAED,6CAA6C;IAC7C,IAAI,eAAe,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACjC,eAAe,CAAC,IAAI,CAAC,kEAAkE,CAAC,CAAC;IAC3F,CAAC;IAED,OAAO,eAAe,CAAC;AACzB,CAAC;AAED;;GAEG;AACH,SAAS,YAAY,CACnB,MAAc,EACd,aAAqB;IAErB,0CAA0C;IAC1C,MAAM,cAAc,GAAG,IAAI,CAAC;IAC5B,MAAM,eAAe,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,cAAc,CAAC,CAAC;IAE3D,mCAAmC;IACnC,IAAI,YAAY,GAAG,WAAW,CAAC;IAC/B,IAAI,aAAa,GAAG,GAAG;QAAE,YAAY,GAAG,UAAU,CAAC;IACnD,IAAI,aAAa,GAAG,IAAI;QAAE,YAAY,GAAG,UAAU,CAAC;IACpD,IAAI,aAAa,GAAG,IAAI;QAAE,YAAY,GAAG,WAAW,CAAC;IAErD,MAAM,OAAO,GAAG,gBAAgB,CAAC,YAAY,CAAC,CAAC;IAE/C,OAAO;QACL,QAAQ,EAAE,KAAK;QACf,YAAY;QACZ,SAAS,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,eAAe,CAAC,EAAE,oBAAoB;QAC7D,WAAW,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,eAAe,CAAC,GAAG,OAAO,CAAC,KAAK;KAC1D,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,cAA+B,EAC/B,cAA4B,EAAE;IAE9B,MAAM,CAAC,IAAI,CAAC,mCAAmC,CAAC,CAAC;IAEjD,yDAAyD;IACzD,IAAI,CAAC,cAAc,EAAE,CAAC;QACpB,OAAO;YACL,kBAAkB,EAAE,GAAG;YACvB,oBAAoB,EAAE,EAAE;YACxB,mBAAmB,EAAE;gBACnB,GAAG,EAAE,GAAG;gBACR,UAAU,EAAE,GAAG;aAChB;YACD,eAAe,EAAE;gBACf,mDAAmD;gBACnD,4CAA4C;aAC7C;SACF,CAAC;IACJ,CAAC;IAED,MAAM,UAAU,GAAG,kBAAkB,CAAC,cAAc,CAAC,CAAC;IACtD,MAAM,MAAM,GAAG,cAAc,CAAC,cAAc,CAAC,CAAC;IAC9C,MAAM,eAAe,GAAG,uBAAuB,CAAC,cAAc,EAAE,WAAW,CAAC,CAAC;IAC7E,MAAM,cAAc,GAAG,YAAY,CAAC,MAAM,EAAE,UAAU,CAAC,GAAG,CAAC,CAAC;IAE5D,MAAM,QAAQ,GAAqB;QACjC,kBAAkB,EAAE,UAAU,CAAC,GAAG;QAClC,oBAAoB,EAAE,MAAM;QAC5B,mBAAmB,EAAE,UAAU;QAC/B,eAAe;QACf,cAAc;KACf,CAAC;IAEF,MAAM,CAAC,IAAI,CAAC,qCAAqC,EAAE;QACjD,aAAa,EAAE,QAAQ,CAAC,kBAAkB;QAC1C,MAAM,EAAE,QAAQ,CAAC,oBAAoB;QACrC,UAAU,EAAE,UAAU,CAAC,UAAU;KAClC,CAAC,CAAC;IAEH,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,sBAAsB,CACpC,QAA0B,EAC1B,mBAA2B,GAAG;IAE9B,2CAA2C;IAC3C,MAAM,QAAQ,GAAG,QAAQ,CAAC,kBAAkB,GAAG,gBAAgB,CAAC;IAEhE,IAAI,QAAQ,IAAI,CAAC;QAAE,OAAO,GAAG,CAAC,CAAC,cAAc;IAC7C,IAAI,QAAQ,IAAI,CAAC;QAAE,OAAO,EAAE,CAAC,CAAE,cAAc;IAC7C,IAAI,QAAQ,IAAI,CAAC;QAAE,OAAO,EAAE,CAAC,CAAE,cAAc;IAC7C,IAAI,QAAQ,IAAI,GAAG;QAAE,OAAO,EAAE,CAAC,CAAC,gBAAgB;IAChD,IAAI,QAAQ,IAAI,CAAC;QAAE,OAAO,EAAE,CAAC,CAAE,sBAAsB;IACrD,OAAO,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,EAAE,CAAC,CAAC,CAAC,eAAe;AACnD,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scale Assessment Scanner
|
|
3
|
+
*
|
|
4
|
+
* Orchestrates load testing, bottleneck detection, and capacity estimation.
|
|
5
|
+
* This is the entry point for M8 scale assessment capabilities.
|
|
6
|
+
*
|
|
7
|
+
* @module scanners/scale
|
|
8
|
+
*/
|
|
9
|
+
import { detectBottlenecks } from "./bottleneck-detector.js";
|
|
10
|
+
import type { ScaleAssessmentResult } from "./types.js";
|
|
11
|
+
export * from "./types.js";
|
|
12
|
+
export { detectLoadTool, discoverProfiles, runK6Test, generateSampleProfile, loadProfile, isK6Available, } from "./load-profiler.js";
|
|
13
|
+
export { detectBottlenecks, calculateBottleneckScore, } from "./bottleneck-detector.js";
|
|
14
|
+
export { estimateCapacity, calculateCapacityScore, } from "./capacity-estimator.js";
|
|
15
|
+
/**
|
|
16
|
+
* Run full scale assessment
|
|
17
|
+
*
|
|
18
|
+
* 1. Detect load testing tool
|
|
19
|
+
* 2. Discover and run load profiles
|
|
20
|
+
* 3. Detect bottlenecks
|
|
21
|
+
* 4. Estimate capacity
|
|
22
|
+
* 5. Calculate scores
|
|
23
|
+
*/
|
|
24
|
+
export declare function runScaleAssessment(projectPath: string, baseUrl: string, options?: {
|
|
25
|
+
timeout?: number;
|
|
26
|
+
profileName?: string;
|
|
27
|
+
skipLoadTest?: boolean;
|
|
28
|
+
targetConcurrent?: number;
|
|
29
|
+
}): Promise<ScaleAssessmentResult>;
|
|
30
|
+
/**
|
|
31
|
+
* Quick bottleneck scan (no load testing)
|
|
32
|
+
*/
|
|
33
|
+
export declare function quickBottleneckScan(projectPath: string): Promise<{
|
|
34
|
+
bottlenecks: Awaited<ReturnType<typeof detectBottlenecks>>;
|
|
35
|
+
score: number;
|
|
36
|
+
}>;
|
|
37
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/scanners/scale/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAWH,OAAO,EACL,iBAAiB,EAElB,MAAM,0BAA0B,CAAC;AAKlC,OAAO,KAAK,EACV,qBAAqB,EAGtB,MAAM,YAAY,CAAC;AAEpB,cAAc,YAAY,CAAC;AAC3B,OAAO,EACL,cAAc,EACd,gBAAgB,EAChB,SAAS,EACT,qBAAqB,EACrB,WAAW,EACX,aAAa,GACd,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,iBAAiB,EACjB,wBAAwB,GACzB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,gBAAgB,EAChB,sBAAsB,GACvB,MAAM,yBAAyB,CAAC;AAEjC;;;;;;;;GAQG;AACH,wBAAsB,kBAAkB,CACtC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,EACf,OAAO,GAAE;IACP,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CACtB,GACL,OAAO,CAAC,qBAAqB,CAAC,CA8EhC;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CACvC,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC;IACT,WAAW,EAAE,OAAO,CAAC,UAAU,CAAC,OAAO,iBAAiB,CAAC,CAAC,CAAC;IAC3D,KAAK,EAAE,MAAM,CAAC;CACf,CAAC,CAKD"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scale Assessment Scanner
|
|
3
|
+
*
|
|
4
|
+
* Orchestrates load testing, bottleneck detection, and capacity estimation.
|
|
5
|
+
* This is the entry point for M8 scale assessment capabilities.
|
|
6
|
+
*
|
|
7
|
+
* @module scanners/scale
|
|
8
|
+
*/
|
|
9
|
+
import { logger } from "../../logger.js";
|
|
10
|
+
import { detectLoadTool, discoverProfiles, runK6Test, } from "./load-profiler.js";
|
|
11
|
+
import { detectBottlenecks, calculateBottleneckScore, } from "./bottleneck-detector.js";
|
|
12
|
+
import { estimateCapacity, calculateCapacityScore, } from "./capacity-estimator.js";
|
|
13
|
+
export * from "./types.js";
|
|
14
|
+
export { detectLoadTool, discoverProfiles, runK6Test, generateSampleProfile, loadProfile, isK6Available, } from "./load-profiler.js";
|
|
15
|
+
export { detectBottlenecks, calculateBottleneckScore, } from "./bottleneck-detector.js";
|
|
16
|
+
export { estimateCapacity, calculateCapacityScore, } from "./capacity-estimator.js";
|
|
17
|
+
/**
|
|
18
|
+
* Run full scale assessment
|
|
19
|
+
*
|
|
20
|
+
* 1. Detect load testing tool
|
|
21
|
+
* 2. Discover and run load profiles
|
|
22
|
+
* 3. Detect bottlenecks
|
|
23
|
+
* 4. Estimate capacity
|
|
24
|
+
* 5. Calculate scores
|
|
25
|
+
*/
|
|
26
|
+
export async function runScaleAssessment(projectPath, baseUrl, options = {}) {
|
|
27
|
+
const startTime = Date.now();
|
|
28
|
+
const { timeout = 600000, profileName, skipLoadTest = false, targetConcurrent = 100 } = options;
|
|
29
|
+
logger.info("scale.assessment_started", { projectPath, baseUrl });
|
|
30
|
+
let loadTestResult;
|
|
31
|
+
// Step 1: Run load tests if not skipped
|
|
32
|
+
if (!skipLoadTest) {
|
|
33
|
+
// Check for load testing tools
|
|
34
|
+
const tool = await detectLoadTool();
|
|
35
|
+
if (!tool) {
|
|
36
|
+
logger.warn("scale.no_load_tool", {
|
|
37
|
+
message: "No load testing tool found. Install k6 or Artillery.",
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
// Discover profiles
|
|
42
|
+
const profiles = await discoverProfiles(projectPath);
|
|
43
|
+
if (profiles.length === 0) {
|
|
44
|
+
logger.info("scale.no_profiles_found", {
|
|
45
|
+
message: "No load profiles found. Generate one with scale_profile_generate.",
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
// Find matching profile or use first
|
|
50
|
+
const selectedProfile = profileName
|
|
51
|
+
? profiles.find((p) => p.profile.name === profileName)
|
|
52
|
+
: profiles[0];
|
|
53
|
+
if (selectedProfile && tool === "k6") {
|
|
54
|
+
loadTestResult = await runK6Test(selectedProfile.profile, baseUrl, {
|
|
55
|
+
timeout,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
// Step 2: Detect bottlenecks
|
|
62
|
+
const bottlenecks = await detectBottlenecks(projectPath, loadTestResult);
|
|
63
|
+
const bottleneckScore = calculateBottleneckScore(bottlenecks);
|
|
64
|
+
// Step 3: Estimate capacity
|
|
65
|
+
const capacity = await estimateCapacity(loadTestResult, bottlenecks);
|
|
66
|
+
const capacityScore = calculateCapacityScore(capacity, targetConcurrent);
|
|
67
|
+
// Step 4: Calculate overall score
|
|
68
|
+
const loadTestScore = loadTestResult?.score ?? 50; // Neutral if no test
|
|
69
|
+
const overallScore = Math.round((loadTestScore * 0.4) + (bottleneckScore * 0.35) + (capacityScore * 0.25));
|
|
70
|
+
const result = {
|
|
71
|
+
success: overallScore >= 70,
|
|
72
|
+
loadTest: loadTestResult,
|
|
73
|
+
bottlenecks,
|
|
74
|
+
capacity,
|
|
75
|
+
score: {
|
|
76
|
+
loadTestScore,
|
|
77
|
+
bottleneckScore,
|
|
78
|
+
capacityScore,
|
|
79
|
+
overallScore,
|
|
80
|
+
},
|
|
81
|
+
duration: Date.now() - startTime,
|
|
82
|
+
};
|
|
83
|
+
logger.info("scale.assessment_completed", {
|
|
84
|
+
success: result.success,
|
|
85
|
+
overallScore,
|
|
86
|
+
loadTestScore,
|
|
87
|
+
bottleneckScore,
|
|
88
|
+
capacityScore,
|
|
89
|
+
duration: result.duration,
|
|
90
|
+
});
|
|
91
|
+
return result;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Quick bottleneck scan (no load testing)
|
|
95
|
+
*/
|
|
96
|
+
export async function quickBottleneckScan(projectPath) {
|
|
97
|
+
const bottlenecks = await detectBottlenecks(projectPath);
|
|
98
|
+
const score = calculateBottleneckScore(bottlenecks);
|
|
99
|
+
return { bottlenecks, score };
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/scanners/scale/index.ts"],"names":[],"mappings":"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"}
|