loadscope 0.0.0-stage → 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,720 @@
1
+ import { z } from 'zod';
2
+
3
+ interface RunOptions {
4
+ url: string;
5
+ duration?: number;
6
+ concurrency?: number;
7
+ rate?: number;
8
+ distribution?: "uniform" | "poisson";
9
+ honest?: boolean;
10
+ ttfb?: boolean;
11
+ method?: string;
12
+ headers?: Record<string, string>;
13
+ body?: string;
14
+ timeout?: number;
15
+ warmup?: number;
16
+ rampUp?: number;
17
+ mode?: "closed" | "open";
18
+ workers?: number | "auto";
19
+ dashboard?: boolean;
20
+ json?: string | boolean;
21
+ csv?: string | boolean;
22
+ html?: string | boolean;
23
+ pdf?: string;
24
+ aiReport?: string;
25
+ aiDryRun?: boolean;
26
+ baseline?: string;
27
+ saveBaseline?: string | boolean;
28
+ maxP95Increase?: number;
29
+ maxRpsDrop?: number;
30
+ maxP99Increase?: number;
31
+ maxErrors?: number;
32
+ }
33
+ interface LatencyPoint {
34
+ t: number;
35
+ p95: number;
36
+ }
37
+ interface LatencyDistribution {
38
+ p50: number;
39
+ p90: number;
40
+ p95: number;
41
+ p99: number;
42
+ min: number;
43
+ max: number;
44
+ mean: number;
45
+ }
46
+ interface HistogramSnapshot {
47
+ counts: Uint32Array;
48
+ total: number;
49
+ minVal: number;
50
+ maxVal: number;
51
+ sumUs: number;
52
+ }
53
+ interface WorkerInitData {
54
+ workerIndex: number;
55
+ totalWorkers: number;
56
+ url: string;
57
+ duration: number;
58
+ concurrency: number;
59
+ rate?: number;
60
+ distribution?: "uniform" | "poisson";
61
+ honest?: boolean;
62
+ ttfb?: boolean;
63
+ method: string;
64
+ headers: Record<string, string>;
65
+ body?: string;
66
+ timeout: number;
67
+ warmup: number;
68
+ rampUp: number;
69
+ mode: "closed" | "open";
70
+ }
71
+ interface WorkerTickMessage {
72
+ type: "tick";
73
+ workerIndex: number;
74
+ elapsedSec: number;
75
+ dispatched: number;
76
+ networkErrors: number;
77
+ httpErrors: number;
78
+ statusCodes: Record<number, number>;
79
+ errorsByType: Record<string, number>;
80
+ windowSnapshot: HistogramSnapshot;
81
+ cumulativeSnapshot: HistogramSnapshot;
82
+ serviceTimeSnapshot?: HistogramSnapshot;
83
+ ttfbSnapshot?: HistogramSnapshot;
84
+ loopLagMs: number;
85
+ }
86
+ interface WorkerDoneMessage {
87
+ type: "done";
88
+ workerIndex: number;
89
+ dispatched: number;
90
+ networkErrors: number;
91
+ httpErrors: number;
92
+ statusCodes: Record<number, number>;
93
+ errorsByType: Record<string, number>;
94
+ finalSnapshot: HistogramSnapshot;
95
+ serviceTimeSnapshot?: HistogramSnapshot;
96
+ ttfbSnapshot?: HistogramSnapshot;
97
+ loopLagMaxMs: number;
98
+ loopLagP99Ms: number;
99
+ avgDriftMs?: number;
100
+ }
101
+ interface WorkerErrorMessage {
102
+ type: "error";
103
+ workerIndex: number;
104
+ error: string;
105
+ }
106
+ type WorkerMessage = WorkerTickMessage | WorkerDoneMessage | WorkerErrorMessage;
107
+ interface RunSummary {
108
+ target: string;
109
+ rps: number;
110
+ totalRequests: number;
111
+ durationSec: number;
112
+ p50: number;
113
+ p90: number;
114
+ p95: number;
115
+ p99: number;
116
+ errorRate: number;
117
+ networkErrors: number;
118
+ httpErrors: number;
119
+ statusCodes: Record<number, number>;
120
+ errorsByType: Record<string, number>;
121
+ series: LatencyPoint[];
122
+ selfCheckWarnings: string[];
123
+ workerCount?: number;
124
+ distribution?: "uniform" | "poisson";
125
+ serviceTime?: LatencyDistribution;
126
+ queueDelay?: LatencyDistribution;
127
+ ttfb?: LatencyDistribution;
128
+ scheduleDriftMs?: number;
129
+ }
130
+ interface BreakpointLimits {
131
+ maxP95?: number;
132
+ maxP99?: number;
133
+ maxErrorRate: number;
134
+ }
135
+ interface BreakpointStepResult {
136
+ stepIndex: number;
137
+ load: number;
138
+ rps: number;
139
+ p50: number;
140
+ p95: number;
141
+ p99: number;
142
+ errorRate: number;
143
+ totalRequests: number;
144
+ networkErrors: number;
145
+ httpErrors: number;
146
+ status: "PASS" | "BREACH";
147
+ breachReason?: string;
148
+ isRefinement?: boolean;
149
+ summary: RunSummary;
150
+ }
151
+ interface BreakpointSummary {
152
+ target: string;
153
+ mode: "concurrency" | "rate";
154
+ start: number;
155
+ max: number;
156
+ step: number;
157
+ stepDurationSec: number;
158
+ breakingPoint?: number;
159
+ safeCapacity?: number;
160
+ breached: boolean;
161
+ breachReason?: string;
162
+ steps: BreakpointStepResult[];
163
+ refinementSteps: BreakpointStepResult[];
164
+ limits: BreakpointLimits;
165
+ }
166
+ interface BreakpointOptions {
167
+ url: string;
168
+ mode?: "concurrency" | "rate";
169
+ start?: number;
170
+ max?: number;
171
+ step?: number;
172
+ stepDuration?: string | number;
173
+ maxP95?: number;
174
+ maxP99?: number;
175
+ maxErrorRate?: number;
176
+ refine?: boolean;
177
+ tolerance?: number;
178
+ workers?: number | "auto";
179
+ method?: string;
180
+ headers?: Record<string, string>;
181
+ body?: string;
182
+ timeout?: number | string;
183
+ honest?: boolean;
184
+ distribution?: "uniform" | "poisson";
185
+ json?: string | boolean;
186
+ csv?: string | boolean;
187
+ onStepStart?: (stepNumber: number, load: number, isRefinement?: boolean) => void;
188
+ onStepComplete?: (result: BreakpointStepResult) => void;
189
+ }
190
+ interface GateThresholds {
191
+ maxP95IncreasePct: number;
192
+ maxRpsDropPct: number;
193
+ maxP99IncreasePct?: number;
194
+ maxErrorRate?: number;
195
+ }
196
+ interface BaselineData {
197
+ timestamp: string;
198
+ target: string;
199
+ concurrency?: number;
200
+ rate?: number;
201
+ durationSec: number;
202
+ rps: number;
203
+ totalRequests: number;
204
+ p50: number;
205
+ p90: number;
206
+ p95: number;
207
+ p99: number;
208
+ errorRate: number;
209
+ networkErrors: number;
210
+ httpErrors: number;
211
+ commitHash?: string;
212
+ }
213
+ interface ComparisonMetric {
214
+ name: string;
215
+ baseline: number;
216
+ current: number;
217
+ delta: number;
218
+ deltaPct: number;
219
+ unit: string;
220
+ isHigherBetter: boolean;
221
+ status: "PASS" | "IMPROVEMENT" | "REGRESSION";
222
+ threshold?: number;
223
+ thresholdViolation?: boolean;
224
+ message?: string;
225
+ }
226
+ interface ComparisonSummary {
227
+ passed: boolean;
228
+ baselineTarget: string;
229
+ currentTarget: string;
230
+ baselineTimestamp?: string;
231
+ metrics: ComparisonMetric[];
232
+ regressions: ComparisonMetric[];
233
+ improvements: ComparisonMetric[];
234
+ thresholds: GateThresholds;
235
+ }
236
+ interface ScenarioStep {
237
+ name: string;
238
+ method?: string;
239
+ path?: string;
240
+ url?: string;
241
+ headers?: Record<string, string>;
242
+ body?: string;
243
+ extract?: Record<string, string>;
244
+ thinkTime?: string | number;
245
+ }
246
+ interface ScenarioDefinition {
247
+ name: string;
248
+ target: string;
249
+ duration?: string | number;
250
+ concurrency?: number;
251
+ timeout?: string | number;
252
+ steps: ScenarioStep[];
253
+ }
254
+ interface StepSummary {
255
+ name: string;
256
+ method: string;
257
+ path: string;
258
+ totalRequests: number;
259
+ rps: number;
260
+ p50: number;
261
+ p90: number;
262
+ p95: number;
263
+ p99: number;
264
+ min: number;
265
+ max: number;
266
+ mean: number;
267
+ errorRate: number;
268
+ statusCodes: Record<number, number>;
269
+ networkErrors: number;
270
+ httpErrors: number;
271
+ }
272
+ interface ScenarioSummary {
273
+ name: string;
274
+ target: string;
275
+ durationSec: number;
276
+ concurrency: number;
277
+ totalJourneys: number;
278
+ completedJourneys: number;
279
+ failedJourneys: number;
280
+ journeysPerSec: number;
281
+ journeyP50: number;
282
+ journeyP90: number;
283
+ journeyP95: number;
284
+ journeyP99: number;
285
+ steps: StepSummary[];
286
+ overallSummary: RunSummary;
287
+ }
288
+
289
+ /**
290
+ * Fixed-Memory Log-Bucketed Histogram.
291
+ *
292
+ * Storing raw latency arrays creates O(N) memory usage and triggers GC pauses.
293
+ * This histogram uses a fixed Uint32Array(1200) (~4.8 KB of memory forever).
294
+ * Relative error is bounded by (GROWTH - 1) ≈ 2%.
295
+ */
296
+ declare class Histogram {
297
+ /** Fixed 4.8 KB bucket array of counts */
298
+ readonly counts: Uint32Array<ArrayBuffer>;
299
+ /** Total number of recorded samples */
300
+ total: number;
301
+ private minVal;
302
+ private maxVal;
303
+ private sumUs;
304
+ /**
305
+ * Calculate bucket index from latency in microseconds.
306
+ * O(1) mathematical mapping.
307
+ */
308
+ private idx;
309
+ /**
310
+ * Reconstruct microsecond value from bucket index.
311
+ */
312
+ private valFromIdx;
313
+ /**
314
+ * Record a latency value in microseconds (us).
315
+ */
316
+ record(us: number): void;
317
+ /**
318
+ * Merge another histogram into this one.
319
+ * Merging is simple O(B) vector addition across the fixed bucket array.
320
+ */
321
+ merge(other: Histogram): void;
322
+ /**
323
+ * Calculate the given percentile (0..100) in microseconds (us).
324
+ */
325
+ percentile(p: number): number;
326
+ /**
327
+ * Return percentile in milliseconds (ms).
328
+ */
329
+ percentileMs(p: number): number;
330
+ /**
331
+ * Minimum recorded latency in microseconds (us).
332
+ */
333
+ min(): number;
334
+ /**
335
+ * Minimum recorded latency in milliseconds (ms).
336
+ */
337
+ minMs(): number;
338
+ /**
339
+ * Maximum recorded latency in microseconds (us).
340
+ */
341
+ max(): number;
342
+ /**
343
+ * Maximum recorded latency in milliseconds (ms).
344
+ */
345
+ maxMs(): number;
346
+ /**
347
+ * Mean (average) latency in microseconds (us).
348
+ */
349
+ mean(): number;
350
+ /**
351
+ * Mean (average) latency in milliseconds (ms).
352
+ */
353
+ meanMs(): number;
354
+ /**
355
+ * Reset all bucket counts and statistics.
356
+ */
357
+ reset(): void;
358
+ /**
359
+ * Export raw snapshot data for inter-thread messaging (worker_threads).
360
+ */
361
+ toSnapshot(): {
362
+ counts: Uint32Array;
363
+ total: number;
364
+ minVal: number;
365
+ maxVal: number;
366
+ sumUs: number;
367
+ };
368
+ /**
369
+ * Restore or merge from a worker snapshot.
370
+ */
371
+ mergeSnapshot(snapshot: {
372
+ counts: Uint32Array;
373
+ total: number;
374
+ minVal: number;
375
+ maxVal: number;
376
+ sumUs: number;
377
+ }): void;
378
+ }
379
+
380
+ /**
381
+ * Generate a clean, formatted terminal summary report string.
382
+ * Kept pure without console.log side-effects for testability.
383
+ */
384
+ declare function formatTerminalReport(s: RunSummary): string;
385
+ /**
386
+ * Print a clean, formatted terminal summary report to stdout.
387
+ */
388
+ declare function printTerminalReport(s: RunSummary): void;
389
+
390
+ /**
391
+ * Serializes a RunSummary to formatted JSON string.
392
+ */
393
+ declare function formatJsonReport(summary: RunSummary): string;
394
+ /**
395
+ * Formats a RunSummary and its per-second time series into CSV format.
396
+ */
397
+ declare function formatCsvReport(summary: RunSummary): string;
398
+ /**
399
+ * Serializes a BreakpointSummary to formatted JSON string.
400
+ */
401
+ declare function formatBreakpointJsonReport(summary: BreakpointSummary): string;
402
+ /**
403
+ * Formats a BreakpointSummary and all its steps into CSV format.
404
+ */
405
+ declare function formatBreakpointCsvReport(summary: BreakpointSummary): string;
406
+ /**
407
+ * Serializes a ComparisonSummary to formatted JSON string.
408
+ */
409
+ declare function formatComparisonJsonReport(summary: ComparisonSummary): string;
410
+ /**
411
+ * Formats a ComparisonSummary into CSV format.
412
+ */
413
+ declare function formatComparisonCsvReport(summary: ComparisonSummary): string;
414
+
415
+ interface DashboardStats {
416
+ target: string;
417
+ elapsedSec: number;
418
+ totalDurationSec: number;
419
+ totalRequests: number;
420
+ currentRps: number;
421
+ p50Ms: number;
422
+ p90Ms: number;
423
+ p95Ms: number;
424
+ networkErrors: number;
425
+ httpErrors: number;
426
+ workerCount: number;
427
+ mode: "closed" | "open";
428
+ warnings?: string[];
429
+ }
430
+ /**
431
+ * Real-time terminal dashboard powered by log-update.
432
+ */
433
+ declare class LiveDashboard {
434
+ private enabled;
435
+ constructor(enabled?: boolean);
436
+ /**
437
+ * Format a progress bar like [████████░░░░░░] 60%
438
+ */
439
+ private renderProgressBar;
440
+ /**
441
+ * Generates the dashboard text representation.
442
+ */
443
+ formatDashboard(stats: DashboardStats): string;
444
+ /**
445
+ * Update the live terminal display.
446
+ */
447
+ update(stats: DashboardStats): void;
448
+ /**
449
+ * Stop the live dashboard and clean up terminal state.
450
+ */
451
+ stop(): void;
452
+ }
453
+
454
+ /**
455
+ * Schema validating options passed to LoadScope run.
456
+ */
457
+ declare const RunOptionsSchema: z.ZodObject<{
458
+ url: z.ZodString;
459
+ duration: z.ZodEffects<z.ZodDefault<z.ZodUnion<[z.ZodString, z.ZodNumber]>>, number, string | number | undefined>;
460
+ concurrency: z.ZodDefault<z.ZodNumber>;
461
+ rate: z.ZodOptional<z.ZodNumber>;
462
+ method: z.ZodDefault<z.ZodEnum<["GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS"]>>;
463
+ headers: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodString>>;
464
+ body: z.ZodOptional<z.ZodString>;
465
+ timeout: z.ZodEffects<z.ZodDefault<z.ZodUnion<[z.ZodString, z.ZodNumber]>>, number, string | number | undefined>;
466
+ warmup: z.ZodEffects<z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodNumber]>>, number, string | number | undefined>;
467
+ rampUp: z.ZodEffects<z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodNumber]>>, number, string | number | undefined>;
468
+ mode: z.ZodOptional<z.ZodEnum<["closed", "open"]>>;
469
+ distribution: z.ZodDefault<z.ZodEnum<["uniform", "poisson"]>>;
470
+ honest: z.ZodDefault<z.ZodBoolean>;
471
+ ttfb: z.ZodDefault<z.ZodBoolean>;
472
+ workers: z.ZodDefault<z.ZodUnion<[z.ZodNumber, z.ZodLiteral<"auto">]>>;
473
+ dashboard: z.ZodDefault<z.ZodBoolean>;
474
+ json: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodBoolean]>>;
475
+ csv: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodBoolean]>>;
476
+ pdf: z.ZodOptional<z.ZodString>;
477
+ aiReport: z.ZodOptional<z.ZodString>;
478
+ aiDryRun: z.ZodDefault<z.ZodBoolean>;
479
+ }, "strip", z.ZodTypeAny, {
480
+ concurrency: number;
481
+ duration: number;
482
+ timeout: number;
483
+ url: string;
484
+ method: "GET" | "POST" | "PUT" | "DELETE" | "PATCH" | "HEAD" | "OPTIONS";
485
+ headers: Record<string, string>;
486
+ warmup: number;
487
+ rampUp: number;
488
+ distribution: "uniform" | "poisson";
489
+ honest: boolean;
490
+ ttfb: boolean;
491
+ workers: number | "auto";
492
+ dashboard: boolean;
493
+ aiDryRun: boolean;
494
+ rate?: number | undefined;
495
+ body?: string | undefined;
496
+ mode?: "open" | "closed" | undefined;
497
+ json?: string | boolean | undefined;
498
+ csv?: string | boolean | undefined;
499
+ pdf?: string | undefined;
500
+ aiReport?: string | undefined;
501
+ }, {
502
+ url: string;
503
+ concurrency?: number | undefined;
504
+ rate?: number | undefined;
505
+ duration?: string | number | undefined;
506
+ timeout?: string | number | undefined;
507
+ method?: "GET" | "POST" | "PUT" | "DELETE" | "PATCH" | "HEAD" | "OPTIONS" | undefined;
508
+ headers?: Record<string, string> | undefined;
509
+ body?: string | undefined;
510
+ warmup?: string | number | undefined;
511
+ rampUp?: string | number | undefined;
512
+ mode?: "open" | "closed" | undefined;
513
+ distribution?: "uniform" | "poisson" | undefined;
514
+ honest?: boolean | undefined;
515
+ ttfb?: boolean | undefined;
516
+ workers?: number | "auto" | undefined;
517
+ dashboard?: boolean | undefined;
518
+ json?: string | boolean | undefined;
519
+ csv?: string | boolean | undefined;
520
+ pdf?: string | undefined;
521
+ aiReport?: string | undefined;
522
+ aiDryRun?: boolean | undefined;
523
+ }>;
524
+ type ValidatedRunOptions = z.infer<typeof RunOptionsSchema>;
525
+
526
+ /**
527
+ * Execute a closed-model load test using undici.Pool.
528
+ *
529
+ * In the closed model, concurrency is fixed: exactly `concurrency` parallel
530
+ * workers loop, each dispatching the next request as soon as the previous finishes.
531
+ */
532
+ declare function executeClosedModel(options: ValidatedRunOptions): Promise<RunSummary>;
533
+
534
+ /**
535
+ * Execute an open-model load test using undici.Pool.
536
+ *
537
+ * In the open arrival model, requests are scheduled at target arrival times
538
+ * independent of whether previous requests have completed (Uniform or Poisson process).
539
+ * Latency is measured from the INTENDED dispatch timestamp to completion timestamp,
540
+ * directly revealing client-side queueing delay and eliminating Coordinated Omission.
541
+ */
542
+ declare function executeOpenModel(options: ValidatedRunOptions): Promise<RunSummary>;
543
+
544
+ /**
545
+ * Execute a multi-threaded load test across worker threads.
546
+ * Partitions concurrency and arrival rate across W workers, merges their
547
+ * log-bucketed histogram snapshots in O(B) time, and updates the live dashboard.
548
+ */
549
+ declare function executeMultiThreaded(options: ValidatedRunOptions): Promise<RunSummary>;
550
+
551
+ /**
552
+ * High-precision arrival scheduler for open-model load testing.
553
+ * Supports deterministic uniform intervals and stochastic Poisson arrival processes.
554
+ */
555
+ declare class ArrivalScheduler {
556
+ private readonly rate;
557
+ private readonly distribution;
558
+ private readonly startNs;
559
+ private currentScheduledNs;
560
+ private totalDriftNs;
561
+ private sampleCount;
562
+ private maxDriftNs;
563
+ constructor(rate: number, distribution?: "uniform" | "poisson", startNs?: bigint);
564
+ /**
565
+ * Generates the next scheduled arrival timestamp (in nanoseconds).
566
+ */
567
+ nextArrivalNs(): bigint;
568
+ /**
569
+ * High-resolution pause until the target timestamp is reached.
570
+ * Uses setTimeout for long waits and micro-spinning for sub-millisecond precision.
571
+ */
572
+ waitUntil(targetNs: bigint): Promise<void>;
573
+ private recordDrift;
574
+ /**
575
+ * Average schedule drift in milliseconds.
576
+ */
577
+ get averageDriftMs(): number;
578
+ /**
579
+ * Maximum schedule drift in milliseconds.
580
+ */
581
+ get maxDriftMs(): number;
582
+ }
583
+
584
+ /**
585
+ * Gil Tene's Coordinated Omission Correction algorithm (from wrk2 / HdrHistogram).
586
+ *
587
+ * In load testing, when a request stalls or experiences high latency L exceeding
588
+ * the expected inter-arrival interval I, all requests that would have arrived
589
+ * behind it during that stall are omitted from the sample pool.
590
+ *
591
+ * This function injects the missing virtual samples (L - I, L - 2I, ...) into
592
+ * the histogram, accurately penalizing high percentiles (p95, p99) to reflect
593
+ * what real users experienced while the system was stalled.
594
+ */
595
+ declare function recordWithCorrection(histogram: Histogram, latencyUs: number, expectedIntervalUs: number): number;
596
+ /**
597
+ * Helper to extract formatted LatencyDistribution metrics from a Histogram.
598
+ */
599
+ declare function extractDistribution(h: Histogram): LatencyDistribution;
600
+ /**
601
+ * Calculates the queue delay distribution by subtracting service time from response time.
602
+ */
603
+ declare function computeQueueDelay(response: LatencyDistribution, service: LatencyDistribution): LatencyDistribution;
604
+
605
+ /**
606
+ * Runs the Breaking-Point Finder: stepped ramp + binary search capacity detection.
607
+ */
608
+ declare function runBreakingPoint(options: BreakpointOptions): Promise<BreakpointSummary>;
609
+
610
+ /**
611
+ * Format a single step table row for real-time progress logging.
612
+ */
613
+ declare function formatStepRow(step: BreakpointStepResult, mode: "concurrency" | "rate"): string;
614
+ /**
615
+ * Generates a comprehensive terminal report string for Breaking-Point results.
616
+ */
617
+ declare function formatBreakpointTerminalReport(summary: BreakpointSummary): string;
618
+ /**
619
+ * Print the Breaking-Point report to stdout.
620
+ */
621
+ declare function printBreakpointTerminalReport(summary: BreakpointSummary): void;
622
+
623
+ /**
624
+ * Saves a RunSummary as a standard JSON baseline file.
625
+ */
626
+ declare function saveBaseline(summary: RunSummary, filePath?: string, options?: {
627
+ concurrency?: number;
628
+ rate?: number;
629
+ }): Promise<string>;
630
+ /**
631
+ * Loads a baseline JSON file from disk.
632
+ */
633
+ declare function loadBaseline(filePath: string): Promise<BaselineData>;
634
+ /**
635
+ * Compares current benchmark results against a reference baseline and evaluates regression thresholds.
636
+ */
637
+ declare function compareRuns(current: RunSummary | BaselineData, baseline: BaselineData, thresholdsInput?: Partial<GateThresholds>): ComparisonSummary;
638
+
639
+ /**
640
+ * Generates an aligned terminal comparison table string.
641
+ */
642
+ declare function formatComparisonTerminalReport(summary: ComparisonSummary): string;
643
+ /**
644
+ * Print the comparison report to stdout.
645
+ */
646
+ declare function printComparisonTerminalReport(summary: ComparisonSummary): void;
647
+ /**
648
+ * Generates GitHub Actions-flavored markdown step summary.
649
+ */
650
+ declare function generateGithubStepSummary(summary: ComparisonSummary): string;
651
+ /**
652
+ * Appends markdown summary to $GITHUB_STEP_SUMMARY if available in GitHub Actions.
653
+ */
654
+ declare function writeGithubStepSummary(summary: ComparisonSummary): Promise<void>;
655
+
656
+ /**
657
+ * Generates a complete publication-grade vector PDF report from a RunSummary.
658
+ */
659
+ declare function generatePdfReport(summary: RunSummary, outputPath: string, aiAnalysis?: string): Promise<string>;
660
+
661
+ /**
662
+ * Builds a structured, technical engineering prompt for an LLM to analyze load test results.
663
+ */
664
+ declare function buildAiDiagnosticPrompt(summary: RunSummary): string;
665
+ /**
666
+ * Generates an automated AI diagnostic assessment for the summary.
667
+ * If an API key is available (GEMINI_API_KEY or OPENAI_API_KEY or LLM_API_KEY),
668
+ * it queries the LLM API; otherwise it returns a structured algorithmic assessment.
669
+ */
670
+ declare function fetchAiDiagnostic(summary: RunSummary, explicitApiKey?: string): Promise<string>;
671
+
672
+ /**
673
+ * Generates an interactive, zero-external-dependency HTML document string.
674
+ */
675
+ declare function renderHtmlReport(summary: RunSummary): string;
676
+ /**
677
+ * Generates and writes the interactive HTML report to disk.
678
+ */
679
+ declare function generateHtmlReport(summary: RunSummary, outputPath?: string): Promise<string>;
680
+
681
+ /**
682
+ * Replaces all occurrences of {{varName}} in a template string with values from context.
683
+ */
684
+ declare function interpolateVariables(template: string, context: Record<string, string>): string;
685
+ /**
686
+ * Extracts variables from an HTTP response using configured extraction rules.
687
+ */
688
+ declare function extractFromResponse(body: string, headers: Record<string, string | string[] | undefined>, rules: Record<string, string>): Record<string, string>;
689
+ /**
690
+ * Parses and validates a ScenarioDefinition from a raw YAML/JSON string or file path.
691
+ */
692
+ declare function parseScenario(input: string): ScenarioDefinition;
693
+
694
+ interface ScenarioRunOverrides {
695
+ concurrency?: number;
696
+ duration?: number | string;
697
+ timeout?: number | string;
698
+ }
699
+ /**
700
+ * Executes a multi-step user journey scenario with concurrent virtual users.
701
+ */
702
+ declare function runScenario(definition: ScenarioDefinition, overrides?: ScenarioRunOverrides): Promise<ScenarioSummary>;
703
+
704
+ /**
705
+ * Formats a comprehensive terminal report for multi-step scenario execution.
706
+ */
707
+ declare function formatScenarioTerminalReport(summary: ScenarioSummary): string;
708
+ /**
709
+ * Prints the formatted scenario report directly to stdout.
710
+ */
711
+ declare function printScenarioTerminalReport(summary: ScenarioSummary): void;
712
+
713
+ /**
714
+ * Programmatic API to execute a load test run.
715
+ * Automatically delegates to multi-threaded execution when workers > 1,
716
+ * open arrival model when rate is specified, or single-threaded closed concurrency.
717
+ */
718
+ declare function run(options: RunOptions): Promise<RunSummary>;
719
+
720
+ export { ArrivalScheduler, type BaselineData, type BreakpointLimits, type BreakpointOptions, type BreakpointStepResult, type BreakpointSummary, type ComparisonMetric, type ComparisonSummary, type GateThresholds, Histogram, type HistogramSnapshot, type LatencyDistribution, type LatencyPoint, LiveDashboard, type RunOptions, type RunSummary, type ScenarioDefinition, type ScenarioStep, type ScenarioSummary, type StepSummary, type WorkerDoneMessage, type WorkerErrorMessage, type WorkerInitData, type WorkerMessage, type WorkerTickMessage, buildAiDiagnosticPrompt, compareRuns, computeQueueDelay, executeClosedModel, executeMultiThreaded, executeOpenModel, extractDistribution, extractFromResponse, fetchAiDiagnostic, formatBreakpointCsvReport, formatBreakpointJsonReport, formatBreakpointTerminalReport, formatComparisonCsvReport, formatComparisonJsonReport, formatComparisonTerminalReport, formatCsvReport, formatJsonReport, formatScenarioTerminalReport, formatStepRow, formatTerminalReport, generateGithubStepSummary, generateHtmlReport, generatePdfReport, interpolateVariables, loadBaseline, parseScenario, printBreakpointTerminalReport, printComparisonTerminalReport, printScenarioTerminalReport, printTerminalReport, recordWithCorrection, renderHtmlReport, run, runBreakingPoint, runScenario, saveBaseline, writeGithubStepSummary };