agentic-qe 1.9.3 → 2.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/.claude/agents/qe-api-contract-validator.md +95 -1336
- package/.claude/agents/qe-chaos-engineer.md +152 -1211
- package/.claude/agents/qe-code-complexity.md +144 -707
- package/.claude/agents/qe-coverage-analyzer.md +147 -743
- package/.claude/agents/qe-deployment-readiness.md +143 -1496
- package/.claude/agents/qe-flaky-test-hunter.md +132 -1529
- package/.claude/agents/qe-fleet-commander.md +12 -12
- package/.claude/agents/qe-performance-tester.md +150 -886
- package/.claude/agents/qe-production-intelligence.md +155 -1396
- package/.claude/agents/qe-quality-analyzer.md +6 -6
- package/.claude/agents/qe-quality-gate.md +151 -648
- package/.claude/agents/qe-regression-risk-analyzer.md +132 -1150
- package/.claude/agents/qe-requirements-validator.md +149 -932
- package/.claude/agents/qe-security-scanner.md +157 -797
- package/.claude/agents/qe-test-data-architect.md +96 -1365
- package/.claude/agents/qe-test-executor.md +8 -8
- package/.claude/agents/qe-test-generator.md +145 -1540
- package/.claude/agents/qe-visual-tester.md +153 -1257
- package/.claude/agents/qx-partner.md +235 -0
- package/.claude/agents/subagents/qe-code-reviewer.md +40 -136
- package/.claude/agents/subagents/qe-coverage-gap-analyzer.md +40 -480
- package/.claude/agents/subagents/qe-data-generator.md +41 -125
- package/.claude/agents/subagents/qe-flaky-investigator.md +55 -411
- package/.claude/agents/subagents/qe-integration-tester.md +53 -141
- package/.claude/agents/subagents/qe-performance-validator.md +54 -130
- package/.claude/agents/subagents/qe-security-auditor.md +56 -114
- package/.claude/agents/subagents/qe-test-data-architect-sub.md +57 -548
- package/.claude/agents/subagents/qe-test-implementer.md +58 -551
- package/.claude/agents/subagents/qe-test-refactorer.md +65 -722
- package/.claude/agents/subagents/qe-test-writer.md +63 -726
- package/.claude/skills/skills-manifest.json +632 -0
- package/.claude/skills/testability-scoring/README.md +71 -0
- package/.claude/skills/testability-scoring/SKILL.md +611 -0
- package/.claude/skills/testability-scoring/resources/templates/config.template.js +84 -0
- package/.claude/skills/testability-scoring/resources/templates/testability-scoring.spec.template.js +532 -0
- package/.claude/skills/testability-scoring/scripts/generate-html-report.js +1007 -0
- package/.claude/skills/testability-scoring/scripts/run-assessment.sh +70 -0
- package/CHANGELOG.md +116 -0
- package/README.md +59 -7
- package/config/.env.otel.example +25 -0
- package/config/OTEL-QUICK-REFERENCE.md +137 -0
- package/config/README-OTEL.md +222 -0
- package/config/alerting-rules.yml +518 -0
- package/config/docker-compose.otel.yml +187 -0
- package/config/grafana/dashboards/agentic-qe-overview.json +286 -0
- package/config/grafana/provisioning/dashboards/dashboards.yml +19 -0
- package/config/grafana/provisioning/datasources/datasources.yml +53 -0
- package/config/otel-collector-config.yaml.example +145 -0
- package/config/prometheus.yml.example +106 -0
- package/dist/agents/QXPartnerAgent.d.ts +139 -0
- package/dist/agents/QXPartnerAgent.d.ts.map +1 -0
- package/dist/agents/QXPartnerAgent.js +769 -0
- package/dist/agents/QXPartnerAgent.js.map +1 -0
- package/dist/agents/index.d.ts +1 -0
- package/dist/agents/index.d.ts.map +1 -1
- package/dist/agents/index.js +82 -2
- package/dist/agents/index.js.map +1 -1
- package/dist/alerting/AlertManager.d.ts +120 -0
- package/dist/alerting/AlertManager.d.ts.map +1 -0
- package/dist/alerting/AlertManager.js +345 -0
- package/dist/alerting/AlertManager.js.map +1 -0
- package/dist/alerting/FeedbackRouter.d.ts +98 -0
- package/dist/alerting/FeedbackRouter.d.ts.map +1 -0
- package/dist/alerting/FeedbackRouter.js +331 -0
- package/dist/alerting/FeedbackRouter.js.map +1 -0
- package/dist/alerting/StrategyApplicator.d.ts +120 -0
- package/dist/alerting/StrategyApplicator.d.ts.map +1 -0
- package/dist/alerting/StrategyApplicator.js +299 -0
- package/dist/alerting/StrategyApplicator.js.map +1 -0
- package/dist/alerting/index.d.ts +68 -0
- package/dist/alerting/index.d.ts.map +1 -0
- package/dist/alerting/index.js +112 -0
- package/dist/alerting/index.js.map +1 -0
- package/dist/alerting/types.d.ts +118 -0
- package/dist/alerting/types.d.ts.map +1 -0
- package/dist/alerting/types.js +11 -0
- package/dist/alerting/types.js.map +1 -0
- package/dist/cli/commands/debug/agent.d.ts.map +1 -1
- package/dist/cli/commands/debug/agent.js +19 -6
- package/dist/cli/commands/debug/agent.js.map +1 -1
- package/dist/cli/commands/debug/health-check.js +20 -7
- package/dist/cli/commands/debug/health-check.js.map +1 -1
- package/dist/cli/commands/init-claude-md-template.d.ts +1 -0
- package/dist/cli/commands/init-claude-md-template.d.ts.map +1 -1
- package/dist/cli/commands/init-claude-md-template.js +4 -3
- package/dist/cli/commands/init-claude-md-template.js.map +1 -1
- package/dist/cli/commands/workflow/cancel.d.ts.map +1 -1
- package/dist/cli/commands/workflow/cancel.js +4 -3
- package/dist/cli/commands/workflow/cancel.js.map +1 -1
- package/dist/cli/commands/workflow/list.d.ts.map +1 -1
- package/dist/cli/commands/workflow/list.js +4 -3
- package/dist/cli/commands/workflow/list.js.map +1 -1
- package/dist/cli/commands/workflow/pause.d.ts.map +1 -1
- package/dist/cli/commands/workflow/pause.js +4 -3
- package/dist/cli/commands/workflow/pause.js.map +1 -1
- package/dist/cli/init/claude-config.d.ts.map +1 -1
- package/dist/cli/init/claude-config.js +13 -13
- package/dist/cli/init/claude-config.js.map +1 -1
- package/dist/cli/init/claude-md.d.ts.map +1 -1
- package/dist/cli/init/claude-md.js +44 -2
- package/dist/cli/init/claude-md.js.map +1 -1
- package/dist/cli/init/database-init.js +1 -1
- package/dist/cli/init/index.d.ts.map +1 -1
- package/dist/cli/init/index.js +13 -6
- package/dist/cli/init/index.js.map +1 -1
- package/dist/cli/init/skills.d.ts.map +1 -1
- package/dist/cli/init/skills.js +2 -1
- package/dist/cli/init/skills.js.map +1 -1
- package/dist/core/memory/AgentDBIntegration.d.ts +24 -6
- package/dist/core/memory/AgentDBIntegration.d.ts.map +1 -1
- package/dist/core/memory/AgentDBIntegration.js +66 -10
- package/dist/core/memory/AgentDBIntegration.js.map +1 -1
- package/dist/core/memory/IPatternStore.d.ts +209 -0
- package/dist/core/memory/IPatternStore.d.ts.map +1 -0
- package/dist/core/memory/IPatternStore.js +15 -0
- package/dist/core/memory/IPatternStore.js.map +1 -0
- package/dist/core/memory/MigrationTools.d.ts +192 -0
- package/dist/core/memory/MigrationTools.d.ts.map +1 -0
- package/dist/core/memory/MigrationTools.js +615 -0
- package/dist/core/memory/MigrationTools.js.map +1 -0
- package/dist/core/memory/NeuralEnhancement.d.ts +154 -0
- package/dist/core/memory/NeuralEnhancement.d.ts.map +1 -0
- package/dist/core/memory/NeuralEnhancement.js +598 -0
- package/dist/core/memory/NeuralEnhancement.js.map +1 -0
- package/dist/core/memory/PatternStoreFactory.d.ts +143 -0
- package/dist/core/memory/PatternStoreFactory.d.ts.map +1 -0
- package/dist/core/memory/PatternStoreFactory.js +370 -0
- package/dist/core/memory/PatternStoreFactory.js.map +1 -0
- package/dist/core/memory/RealAgentDBAdapter.d.ts +1 -0
- package/dist/core/memory/RealAgentDBAdapter.d.ts.map +1 -1
- package/dist/core/memory/RealAgentDBAdapter.js +28 -20
- package/dist/core/memory/RealAgentDBAdapter.js.map +1 -1
- package/dist/core/memory/RuVectorPatternStore.d.ts +198 -0
- package/dist/core/memory/RuVectorPatternStore.d.ts.map +1 -0
- package/dist/core/memory/RuVectorPatternStore.js +605 -0
- package/dist/core/memory/RuVectorPatternStore.js.map +1 -0
- package/dist/core/memory/SelfHealingMonitor.d.ts +186 -0
- package/dist/core/memory/SelfHealingMonitor.d.ts.map +1 -0
- package/dist/core/memory/SelfHealingMonitor.js +451 -0
- package/dist/core/memory/SelfHealingMonitor.js.map +1 -0
- package/dist/core/memory/SwarmMemoryManager.d.ts +62 -0
- package/dist/core/memory/SwarmMemoryManager.d.ts.map +1 -1
- package/dist/core/memory/SwarmMemoryManager.js +97 -0
- package/dist/core/memory/SwarmMemoryManager.js.map +1 -1
- package/dist/core/memory/UnifiedMemoryCoordinator.d.ts +341 -0
- package/dist/core/memory/UnifiedMemoryCoordinator.d.ts.map +1 -0
- package/dist/core/memory/UnifiedMemoryCoordinator.js +986 -0
- package/dist/core/memory/UnifiedMemoryCoordinator.js.map +1 -0
- package/dist/core/memory/index.d.ts +16 -0
- package/dist/core/memory/index.d.ts.map +1 -1
- package/dist/core/memory/index.js +58 -1
- package/dist/core/memory/index.js.map +1 -1
- package/dist/core/optimization/SwarmOptimizer.d.ts +185 -0
- package/dist/core/optimization/SwarmOptimizer.d.ts.map +1 -0
- package/dist/core/optimization/SwarmOptimizer.js +631 -0
- package/dist/core/optimization/SwarmOptimizer.js.map +1 -0
- package/dist/core/optimization/index.d.ts +9 -0
- package/dist/core/optimization/index.d.ts.map +1 -0
- package/dist/core/optimization/index.js +25 -0
- package/dist/core/optimization/index.js.map +1 -0
- package/dist/core/optimization/types.d.ts +53 -0
- package/dist/core/optimization/types.d.ts.map +1 -0
- package/dist/core/optimization/types.js +6 -0
- package/dist/core/optimization/types.js.map +1 -0
- package/dist/core/orchestration/PriorityQueue.d.ts +54 -0
- package/dist/core/orchestration/PriorityQueue.d.ts.map +1 -0
- package/dist/core/orchestration/PriorityQueue.js +122 -0
- package/dist/core/orchestration/PriorityQueue.js.map +1 -0
- package/dist/core/orchestration/WorkflowOrchestrator.d.ts +176 -0
- package/dist/core/orchestration/WorkflowOrchestrator.d.ts.map +1 -0
- package/dist/core/orchestration/WorkflowOrchestrator.js +813 -0
- package/dist/core/orchestration/WorkflowOrchestrator.js.map +1 -0
- package/dist/core/orchestration/index.d.ts +7 -0
- package/dist/core/orchestration/index.d.ts.map +1 -0
- package/dist/core/orchestration/index.js +11 -0
- package/dist/core/orchestration/index.js.map +1 -0
- package/dist/core/orchestration/types.d.ts +96 -0
- package/dist/core/orchestration/types.d.ts.map +1 -0
- package/dist/core/orchestration/types.js +6 -0
- package/dist/core/orchestration/types.js.map +1 -0
- package/dist/core/skills/DynamicSkillLoader.d.ts +96 -0
- package/dist/core/skills/DynamicSkillLoader.d.ts.map +1 -0
- package/dist/core/skills/DynamicSkillLoader.js +353 -0
- package/dist/core/skills/DynamicSkillLoader.js.map +1 -0
- package/dist/core/skills/types.d.ts +118 -0
- package/dist/core/skills/types.d.ts.map +1 -0
- package/dist/core/skills/types.js +7 -0
- package/dist/core/skills/types.js.map +1 -0
- package/dist/core/transport/QUICTransport.d.ts +320 -0
- package/dist/core/transport/QUICTransport.d.ts.map +1 -0
- package/dist/core/transport/QUICTransport.js +711 -0
- package/dist/core/transport/QUICTransport.js.map +1 -0
- package/dist/core/transport/index.d.ts +40 -0
- package/dist/core/transport/index.d.ts.map +1 -0
- package/dist/core/transport/index.js +46 -0
- package/dist/core/transport/index.js.map +1 -0
- package/dist/core/transport/quic-loader.d.ts +123 -0
- package/dist/core/transport/quic-loader.d.ts.map +1 -0
- package/dist/core/transport/quic-loader.js +293 -0
- package/dist/core/transport/quic-loader.js.map +1 -0
- package/dist/core/transport/quic.d.ts +154 -0
- package/dist/core/transport/quic.d.ts.map +1 -0
- package/dist/core/transport/quic.js +214 -0
- package/dist/core/transport/quic.js.map +1 -0
- package/dist/mcp/services/AgentRegistry.d.ts.map +1 -1
- package/dist/mcp/services/AgentRegistry.js +4 -1
- package/dist/mcp/services/AgentRegistry.js.map +1 -1
- package/dist/reasoning/RuVectorReasoningAdapter.d.ts +232 -0
- package/dist/reasoning/RuVectorReasoningAdapter.d.ts.map +1 -0
- package/dist/reasoning/RuVectorReasoningAdapter.js +585 -0
- package/dist/reasoning/RuVectorReasoningAdapter.js.map +1 -0
- package/dist/reasoning/index.d.ts +2 -0
- package/dist/reasoning/index.d.ts.map +1 -1
- package/dist/reasoning/index.js +6 -1
- package/dist/reasoning/index.js.map +1 -1
- package/dist/reporting/ResultAggregator.d.ts +107 -0
- package/dist/reporting/ResultAggregator.d.ts.map +1 -0
- package/dist/reporting/ResultAggregator.js +435 -0
- package/dist/reporting/ResultAggregator.js.map +1 -0
- package/dist/reporting/index.d.ts +48 -0
- package/dist/reporting/index.d.ts.map +1 -0
- package/dist/reporting/index.js +154 -0
- package/dist/reporting/index.js.map +1 -0
- package/dist/reporting/reporters/ControlLoopReporter.d.ts +128 -0
- package/dist/reporting/reporters/ControlLoopReporter.d.ts.map +1 -0
- package/dist/reporting/reporters/ControlLoopReporter.js +417 -0
- package/dist/reporting/reporters/ControlLoopReporter.js.map +1 -0
- package/dist/reporting/reporters/HumanReadableReporter.d.ts +140 -0
- package/dist/reporting/reporters/HumanReadableReporter.d.ts.map +1 -0
- package/dist/reporting/reporters/HumanReadableReporter.js +524 -0
- package/dist/reporting/reporters/HumanReadableReporter.js.map +1 -0
- package/dist/reporting/reporters/JSONReporter.d.ts +193 -0
- package/dist/reporting/reporters/JSONReporter.d.ts.map +1 -0
- package/dist/reporting/reporters/JSONReporter.js +324 -0
- package/dist/reporting/reporters/JSONReporter.js.map +1 -0
- package/dist/reporting/reporters/index.d.ts +14 -0
- package/dist/reporting/reporters/index.d.ts.map +1 -0
- package/dist/reporting/reporters/index.js +19 -0
- package/dist/reporting/reporters/index.js.map +1 -0
- package/dist/reporting/types.d.ts +427 -0
- package/dist/reporting/types.d.ts.map +1 -0
- package/dist/reporting/types.js +12 -0
- package/dist/reporting/types.js.map +1 -0
- package/dist/types/index.d.ts +2 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +2 -0
- package/dist/types/index.js.map +1 -1
- package/dist/types/qx.d.ts +397 -0
- package/dist/types/qx.d.ts.map +1 -0
- package/dist/types/qx.js +71 -0
- package/dist/types/qx.js.map +1 -0
- package/dist/visualization/api/RestEndpoints.js +1 -1
- package/dist/visualization/api/RestEndpoints.js.map +1 -1
- package/dist/visualization/api/WebSocketServer.d.ts +44 -0
- package/dist/visualization/api/WebSocketServer.d.ts.map +1 -1
- package/dist/visualization/api/WebSocketServer.js +144 -23
- package/dist/visualization/api/WebSocketServer.js.map +1 -1
- package/dist/visualization/core/DataTransformer.d.ts +10 -0
- package/dist/visualization/core/DataTransformer.d.ts.map +1 -1
- package/dist/visualization/core/DataTransformer.js +60 -5
- package/dist/visualization/core/DataTransformer.js.map +1 -1
- package/dist/visualization/emit-event.d.ts +75 -0
- package/dist/visualization/emit-event.d.ts.map +1 -0
- package/dist/visualization/emit-event.js +213 -0
- package/dist/visualization/emit-event.js.map +1 -0
- package/dist/visualization/index.d.ts +1 -0
- package/dist/visualization/index.d.ts.map +1 -1
- package/dist/visualization/index.js +7 -1
- package/dist/visualization/index.js.map +1 -1
- package/docs/reference/skills.md +63 -1
- package/package.json +12 -4
|
@@ -0,0 +1,711 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* QUIC Transport Layer for AgentDB
|
|
4
|
+
* Provides low-latency, multiplexed connections with HTTP/2 fallback
|
|
5
|
+
*
|
|
6
|
+
* Since QUIC is experimental in Node.js, this implementation uses HTTP/2 as primary
|
|
7
|
+
* transport with the QUIC interface ready for future integration.
|
|
8
|
+
*
|
|
9
|
+
* Features:
|
|
10
|
+
* - Connection pooling with automatic scaling
|
|
11
|
+
* - Circuit breaker pattern for fault tolerance
|
|
12
|
+
* - Exponential backoff retry logic
|
|
13
|
+
* - Health monitoring and metrics
|
|
14
|
+
* - Automatic fallback from HTTP/2 to HTTP/1.1
|
|
15
|
+
* - Low-latency multiplexed streams
|
|
16
|
+
*
|
|
17
|
+
* @version 1.0.0
|
|
18
|
+
*/
|
|
19
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
20
|
+
if (k2 === undefined) k2 = k;
|
|
21
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
22
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
23
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
24
|
+
}
|
|
25
|
+
Object.defineProperty(o, k2, desc);
|
|
26
|
+
}) : (function(o, m, k, k2) {
|
|
27
|
+
if (k2 === undefined) k2 = k;
|
|
28
|
+
o[k2] = m[k];
|
|
29
|
+
}));
|
|
30
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
31
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
32
|
+
}) : function(o, v) {
|
|
33
|
+
o["default"] = v;
|
|
34
|
+
});
|
|
35
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
36
|
+
var ownKeys = function(o) {
|
|
37
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
38
|
+
var ar = [];
|
|
39
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
40
|
+
return ar;
|
|
41
|
+
};
|
|
42
|
+
return ownKeys(o);
|
|
43
|
+
};
|
|
44
|
+
return function (mod) {
|
|
45
|
+
if (mod && mod.__esModule) return mod;
|
|
46
|
+
var result = {};
|
|
47
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
48
|
+
__setModuleDefault(result, mod);
|
|
49
|
+
return result;
|
|
50
|
+
};
|
|
51
|
+
})();
|
|
52
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
53
|
+
exports.DEFAULT_QUIC_CONFIG = exports.QUICTransport = exports.ConnectionPool = exports.CircuitBreaker = void 0;
|
|
54
|
+
exports.createQUICTransport = createQUICTransport;
|
|
55
|
+
const http2 = __importStar(require("http2"));
|
|
56
|
+
const http = __importStar(require("http"));
|
|
57
|
+
const https = __importStar(require("https"));
|
|
58
|
+
const events_1 = require("events");
|
|
59
|
+
/**
|
|
60
|
+
* Circuit Breaker Implementation
|
|
61
|
+
* Prevents cascading failures by stopping requests to unhealthy services
|
|
62
|
+
*/
|
|
63
|
+
class CircuitBreaker {
|
|
64
|
+
constructor(options) {
|
|
65
|
+
this.state = 'closed';
|
|
66
|
+
this.failureCount = 0;
|
|
67
|
+
this.successCount = 0;
|
|
68
|
+
this.lastFailure = null;
|
|
69
|
+
this.nextRetryTime = null;
|
|
70
|
+
this.failureThreshold = options.failureThreshold;
|
|
71
|
+
this.successThreshold = options.successThreshold;
|
|
72
|
+
this.timeout = options.timeout;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Execute operation with circuit breaker protection
|
|
76
|
+
*/
|
|
77
|
+
async execute(operation) {
|
|
78
|
+
// Check if circuit is open
|
|
79
|
+
if (this.state === 'open') {
|
|
80
|
+
const now = Date.now();
|
|
81
|
+
if (this.nextRetryTime && now < this.nextRetryTime.getTime()) {
|
|
82
|
+
throw new Error('Circuit breaker is OPEN - requests blocked');
|
|
83
|
+
}
|
|
84
|
+
// Try half-open state
|
|
85
|
+
this.state = 'half-open';
|
|
86
|
+
this.successCount = 0;
|
|
87
|
+
}
|
|
88
|
+
try {
|
|
89
|
+
const result = await operation();
|
|
90
|
+
this.recordSuccess();
|
|
91
|
+
return result;
|
|
92
|
+
}
|
|
93
|
+
catch (error) {
|
|
94
|
+
this.recordFailure();
|
|
95
|
+
throw error;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Record successful operation
|
|
100
|
+
*/
|
|
101
|
+
recordSuccess() {
|
|
102
|
+
this.failureCount = 0;
|
|
103
|
+
if (this.state === 'half-open') {
|
|
104
|
+
this.successCount++;
|
|
105
|
+
if (this.successCount >= this.successThreshold) {
|
|
106
|
+
this.state = 'closed';
|
|
107
|
+
this.successCount = 0;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Record failed operation
|
|
113
|
+
*/
|
|
114
|
+
recordFailure() {
|
|
115
|
+
this.failureCount++;
|
|
116
|
+
this.lastFailure = new Date();
|
|
117
|
+
if (this.failureCount >= this.failureThreshold) {
|
|
118
|
+
this.state = 'open';
|
|
119
|
+
this.nextRetryTime = new Date(Date.now() + this.timeout);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Get current circuit breaker state
|
|
124
|
+
*/
|
|
125
|
+
getState() {
|
|
126
|
+
return {
|
|
127
|
+
state: this.state,
|
|
128
|
+
failureCount: this.failureCount,
|
|
129
|
+
successCount: this.successCount,
|
|
130
|
+
lastFailure: this.lastFailure,
|
|
131
|
+
nextRetryTime: this.nextRetryTime
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Reset circuit breaker
|
|
136
|
+
*/
|
|
137
|
+
reset() {
|
|
138
|
+
this.state = 'closed';
|
|
139
|
+
this.failureCount = 0;
|
|
140
|
+
this.successCount = 0;
|
|
141
|
+
this.lastFailure = null;
|
|
142
|
+
this.nextRetryTime = null;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
exports.CircuitBreaker = CircuitBreaker;
|
|
146
|
+
/**
|
|
147
|
+
* Connection Pool Management
|
|
148
|
+
* Manages a pool of reusable connections
|
|
149
|
+
*/
|
|
150
|
+
class ConnectionPool {
|
|
151
|
+
constructor(options) {
|
|
152
|
+
this.connections = [];
|
|
153
|
+
this.cleanupInterval = null;
|
|
154
|
+
this.minSize = options.minSize;
|
|
155
|
+
this.maxSize = options.maxSize;
|
|
156
|
+
this.idleTimeout = options.idleTimeout;
|
|
157
|
+
// Start cleanup interval
|
|
158
|
+
this.cleanupInterval = setInterval(() => {
|
|
159
|
+
this.cleanup();
|
|
160
|
+
}, 30000); // Clean up every 30 seconds
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Acquire a connection from the pool
|
|
164
|
+
*/
|
|
165
|
+
async acquire() {
|
|
166
|
+
// Try to find an available healthy connection
|
|
167
|
+
const available = this.connections.find(conn => conn.isHealthy && conn.streams.size < 100);
|
|
168
|
+
if (available) {
|
|
169
|
+
available.lastUsed = new Date();
|
|
170
|
+
available.requestCount++;
|
|
171
|
+
return available;
|
|
172
|
+
}
|
|
173
|
+
// Create new connection if pool not full
|
|
174
|
+
if (this.connections.length < this.maxSize) {
|
|
175
|
+
const conn = await this.createConnection();
|
|
176
|
+
this.connections.push(conn);
|
|
177
|
+
return conn;
|
|
178
|
+
}
|
|
179
|
+
// Pool is full, wait and retry
|
|
180
|
+
await this.sleep(100);
|
|
181
|
+
return this.acquire();
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Release a connection back to the pool
|
|
185
|
+
*/
|
|
186
|
+
release(conn) {
|
|
187
|
+
conn.lastUsed = new Date();
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Mark connection as unhealthy
|
|
191
|
+
*/
|
|
192
|
+
markUnhealthy(conn) {
|
|
193
|
+
conn.isHealthy = false;
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Get pool statistics
|
|
197
|
+
*/
|
|
198
|
+
getStats() {
|
|
199
|
+
const healthy = this.connections.filter(c => c.isHealthy).length;
|
|
200
|
+
return {
|
|
201
|
+
size: this.connections.length,
|
|
202
|
+
healthy,
|
|
203
|
+
utilization: this.connections.length / this.maxSize
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Drain and close all connections
|
|
208
|
+
*/
|
|
209
|
+
async drain() {
|
|
210
|
+
if (this.cleanupInterval) {
|
|
211
|
+
clearInterval(this.cleanupInterval);
|
|
212
|
+
this.cleanupInterval = null;
|
|
213
|
+
}
|
|
214
|
+
const closePromises = this.connections.map(conn => this.closeConnection(conn));
|
|
215
|
+
await Promise.all(closePromises);
|
|
216
|
+
this.connections = [];
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Cleanup idle connections
|
|
220
|
+
*/
|
|
221
|
+
cleanup() {
|
|
222
|
+
const now = Date.now();
|
|
223
|
+
const toRemove = [];
|
|
224
|
+
for (const conn of this.connections) {
|
|
225
|
+
const idle = now - conn.lastUsed.getTime();
|
|
226
|
+
if (idle > this.idleTimeout && this.connections.length > this.minSize) {
|
|
227
|
+
toRemove.push(conn);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
// Remove idle connections
|
|
231
|
+
toRemove.forEach(conn => {
|
|
232
|
+
const index = this.connections.indexOf(conn);
|
|
233
|
+
if (index > -1) {
|
|
234
|
+
this.connections.splice(index, 1);
|
|
235
|
+
this.closeConnection(conn);
|
|
236
|
+
}
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Create a new connection (placeholder - implemented in QUICTransport)
|
|
241
|
+
*/
|
|
242
|
+
async createConnection() {
|
|
243
|
+
return {
|
|
244
|
+
id: `conn-${Date.now()}-${Math.random()}`,
|
|
245
|
+
session: new http.Agent({ keepAlive: true }),
|
|
246
|
+
endpoint: '',
|
|
247
|
+
protocol: 'http1',
|
|
248
|
+
createdAt: new Date(),
|
|
249
|
+
lastUsed: new Date(),
|
|
250
|
+
requestCount: 0,
|
|
251
|
+
isHealthy: true,
|
|
252
|
+
streams: new Set()
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* Close a connection
|
|
257
|
+
*/
|
|
258
|
+
async closeConnection(conn) {
|
|
259
|
+
try {
|
|
260
|
+
if (conn.protocol === 'http2') {
|
|
261
|
+
// HTTP/2 session
|
|
262
|
+
if (conn.session && typeof conn.session.close === 'function') {
|
|
263
|
+
conn.session.close();
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
else {
|
|
267
|
+
// HTTP/1.1 agent
|
|
268
|
+
if (conn.session && typeof conn.session.destroy === 'function') {
|
|
269
|
+
conn.session.destroy();
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
catch (error) {
|
|
274
|
+
// Ignore errors during cleanup
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
sleep(ms) {
|
|
278
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
exports.ConnectionPool = ConnectionPool;
|
|
282
|
+
/**
|
|
283
|
+
* QUIC Transport Layer
|
|
284
|
+
* Main transport implementation with HTTP/2 fallback
|
|
285
|
+
*/
|
|
286
|
+
class QUICTransport extends events_1.EventEmitter {
|
|
287
|
+
constructor(config) {
|
|
288
|
+
super();
|
|
289
|
+
this.pools = new Map();
|
|
290
|
+
this.requests = [];
|
|
291
|
+
this.latencyBuffer = [];
|
|
292
|
+
this.config = {
|
|
293
|
+
...config,
|
|
294
|
+
poolSize: config.poolSize || { min: 2, max: 10 },
|
|
295
|
+
circuitBreaker: config.circuitBreaker || {
|
|
296
|
+
failureThreshold: 5,
|
|
297
|
+
successThreshold: 2,
|
|
298
|
+
timeout: 60000
|
|
299
|
+
}
|
|
300
|
+
};
|
|
301
|
+
this.circuitBreaker = new CircuitBreaker(this.config.circuitBreaker);
|
|
302
|
+
this.metrics = {
|
|
303
|
+
totalRequests: 0,
|
|
304
|
+
successfulRequests: 0,
|
|
305
|
+
failedRequests: 0,
|
|
306
|
+
avgLatency: 0,
|
|
307
|
+
p50Latency: 0,
|
|
308
|
+
p95Latency: 0,
|
|
309
|
+
p99Latency: 0,
|
|
310
|
+
bytesSent: 0,
|
|
311
|
+
bytesReceived: 0,
|
|
312
|
+
circuitBreakerState: 'closed',
|
|
313
|
+
activeConnections: 0,
|
|
314
|
+
poolUtilization: 0
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* Connect to an endpoint
|
|
319
|
+
*/
|
|
320
|
+
async connect(endpoint) {
|
|
321
|
+
const pool = this.getOrCreatePool(endpoint);
|
|
322
|
+
const conn = await pool.acquire();
|
|
323
|
+
// Create actual connection if needed
|
|
324
|
+
if (!conn.endpoint) {
|
|
325
|
+
const url = new URL(endpoint);
|
|
326
|
+
const protocol = await this.detectBestProtocol(url);
|
|
327
|
+
try {
|
|
328
|
+
if (protocol === 'http2') {
|
|
329
|
+
conn.session = await this.createHTTP2Connection(url);
|
|
330
|
+
conn.protocol = 'http2';
|
|
331
|
+
}
|
|
332
|
+
else {
|
|
333
|
+
conn.session = this.createHTTP1Connection(url);
|
|
334
|
+
conn.protocol = 'http1';
|
|
335
|
+
}
|
|
336
|
+
conn.endpoint = endpoint;
|
|
337
|
+
}
|
|
338
|
+
catch (error) {
|
|
339
|
+
pool.markUnhealthy(conn);
|
|
340
|
+
throw error;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
return conn;
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* Disconnect from an endpoint
|
|
347
|
+
*/
|
|
348
|
+
async disconnect(endpoint) {
|
|
349
|
+
const pool = this.pools.get(endpoint);
|
|
350
|
+
if (pool) {
|
|
351
|
+
await pool.drain();
|
|
352
|
+
this.pools.delete(endpoint);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
/**
|
|
356
|
+
* Send data to endpoint
|
|
357
|
+
*/
|
|
358
|
+
async send(endpoint, data) {
|
|
359
|
+
return this.withCircuitBreaker(async () => {
|
|
360
|
+
return this.withRetry(async () => {
|
|
361
|
+
const conn = await this.connect(endpoint);
|
|
362
|
+
const startTime = Date.now();
|
|
363
|
+
try {
|
|
364
|
+
let response;
|
|
365
|
+
if (conn.protocol === 'http2') {
|
|
366
|
+
response = await this.sendHTTP2(conn, data);
|
|
367
|
+
}
|
|
368
|
+
else {
|
|
369
|
+
response = await this.sendHTTP1(conn, endpoint, data);
|
|
370
|
+
}
|
|
371
|
+
this.recordRequest(startTime, true);
|
|
372
|
+
this.emit('request:success', { endpoint, latency: Date.now() - startTime });
|
|
373
|
+
return response;
|
|
374
|
+
}
|
|
375
|
+
catch (error) {
|
|
376
|
+
this.recordRequest(startTime, false);
|
|
377
|
+
this.emit('request:failure', { endpoint, error });
|
|
378
|
+
throw error;
|
|
379
|
+
}
|
|
380
|
+
finally {
|
|
381
|
+
const pool = this.pools.get(endpoint);
|
|
382
|
+
if (pool) {
|
|
383
|
+
pool.release(conn);
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
}, this.config.retryAttempts);
|
|
387
|
+
});
|
|
388
|
+
}
|
|
389
|
+
/**
|
|
390
|
+
* Check connection health
|
|
391
|
+
*/
|
|
392
|
+
async healthCheck(endpoint) {
|
|
393
|
+
const pool = this.pools.get(endpoint);
|
|
394
|
+
if (!pool) {
|
|
395
|
+
return {
|
|
396
|
+
latency: Infinity,
|
|
397
|
+
packetLoss: 1,
|
|
398
|
+
throughput: 0,
|
|
399
|
+
activeStreams: 0,
|
|
400
|
+
lastHealthCheck: new Date(),
|
|
401
|
+
state: 'unhealthy',
|
|
402
|
+
protocol: 'http1'
|
|
403
|
+
};
|
|
404
|
+
}
|
|
405
|
+
const stats = pool.getStats();
|
|
406
|
+
const recentLatencies = this.latencyBuffer.slice(-100);
|
|
407
|
+
const avgLatency = recentLatencies.length > 0
|
|
408
|
+
? recentLatencies.reduce((a, b) => a + b, 0) / recentLatencies.length
|
|
409
|
+
: 0;
|
|
410
|
+
const successRate = this.metrics.totalRequests > 0
|
|
411
|
+
? this.metrics.successfulRequests / this.metrics.totalRequests
|
|
412
|
+
: 0;
|
|
413
|
+
let state = 'healthy';
|
|
414
|
+
if (successRate < 0.5 || avgLatency > 5000) {
|
|
415
|
+
state = 'unhealthy';
|
|
416
|
+
}
|
|
417
|
+
else if (successRate < 0.9 || avgLatency > 1000) {
|
|
418
|
+
state = 'degraded';
|
|
419
|
+
}
|
|
420
|
+
return {
|
|
421
|
+
latency: avgLatency,
|
|
422
|
+
packetLoss: 1 - successRate,
|
|
423
|
+
throughput: this.calculateThroughput(),
|
|
424
|
+
activeStreams: stats.size,
|
|
425
|
+
lastHealthCheck: new Date(),
|
|
426
|
+
state,
|
|
427
|
+
protocol: 'http2' // Assume http2 for now
|
|
428
|
+
};
|
|
429
|
+
}
|
|
430
|
+
/**
|
|
431
|
+
* Get transport metrics
|
|
432
|
+
*/
|
|
433
|
+
getMetrics() {
|
|
434
|
+
const cbState = this.circuitBreaker.getState();
|
|
435
|
+
this.metrics.circuitBreakerState = cbState.state;
|
|
436
|
+
let totalConnections = 0;
|
|
437
|
+
let totalUtilization = 0;
|
|
438
|
+
this.pools.forEach(pool => {
|
|
439
|
+
const stats = pool.getStats();
|
|
440
|
+
totalConnections += stats.size;
|
|
441
|
+
totalUtilization += stats.utilization;
|
|
442
|
+
});
|
|
443
|
+
this.metrics.activeConnections = totalConnections;
|
|
444
|
+
this.metrics.poolUtilization = this.pools.size > 0
|
|
445
|
+
? totalUtilization / this.pools.size
|
|
446
|
+
: 0;
|
|
447
|
+
// Calculate latency percentiles
|
|
448
|
+
if (this.latencyBuffer.length > 0) {
|
|
449
|
+
const sorted = [...this.latencyBuffer].sort((a, b) => a - b);
|
|
450
|
+
this.metrics.p50Latency = sorted[Math.floor(sorted.length * 0.5)];
|
|
451
|
+
this.metrics.p95Latency = sorted[Math.floor(sorted.length * 0.95)];
|
|
452
|
+
this.metrics.p99Latency = sorted[Math.floor(sorted.length * 0.99)];
|
|
453
|
+
}
|
|
454
|
+
return { ...this.metrics };
|
|
455
|
+
}
|
|
456
|
+
/**
|
|
457
|
+
* Execute operation with circuit breaker
|
|
458
|
+
*/
|
|
459
|
+
async withCircuitBreaker(operation) {
|
|
460
|
+
return this.circuitBreaker.execute(operation);
|
|
461
|
+
}
|
|
462
|
+
/**
|
|
463
|
+
* Execute operation with retry logic
|
|
464
|
+
*/
|
|
465
|
+
async withRetry(operation, attempts = 3) {
|
|
466
|
+
let lastError = null;
|
|
467
|
+
for (let i = 0; i < attempts; i++) {
|
|
468
|
+
try {
|
|
469
|
+
return await operation();
|
|
470
|
+
}
|
|
471
|
+
catch (error) {
|
|
472
|
+
lastError = error;
|
|
473
|
+
if (i < attempts - 1) {
|
|
474
|
+
// Exponential backoff
|
|
475
|
+
const delay = this.config.retryDelay * Math.pow(2, i);
|
|
476
|
+
await this.sleep(delay);
|
|
477
|
+
this.emit('retry', { attempt: i + 1, delay });
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
throw lastError || new Error('Operation failed after retries');
|
|
482
|
+
}
|
|
483
|
+
/**
|
|
484
|
+
* Close all connections and cleanup
|
|
485
|
+
*/
|
|
486
|
+
async close() {
|
|
487
|
+
const drainPromises = Array.from(this.pools.values()).map(pool => pool.drain());
|
|
488
|
+
await Promise.all(drainPromises);
|
|
489
|
+
this.pools.clear();
|
|
490
|
+
this.removeAllListeners();
|
|
491
|
+
}
|
|
492
|
+
// ============================================================================
|
|
493
|
+
// Private Methods
|
|
494
|
+
// ============================================================================
|
|
495
|
+
/**
|
|
496
|
+
* Get or create connection pool for endpoint
|
|
497
|
+
*/
|
|
498
|
+
getOrCreatePool(endpoint) {
|
|
499
|
+
let pool = this.pools.get(endpoint);
|
|
500
|
+
if (!pool) {
|
|
501
|
+
pool = new ConnectionPool({
|
|
502
|
+
minSize: this.config.poolSize.min,
|
|
503
|
+
maxSize: this.config.poolSize.max,
|
|
504
|
+
idleTimeout: this.config.idleTimeout
|
|
505
|
+
});
|
|
506
|
+
this.pools.set(endpoint, pool);
|
|
507
|
+
}
|
|
508
|
+
return pool;
|
|
509
|
+
}
|
|
510
|
+
/**
|
|
511
|
+
* Detect best protocol for endpoint
|
|
512
|
+
*/
|
|
513
|
+
async detectBestProtocol(url) {
|
|
514
|
+
// For now, prefer HTTP/2 if available
|
|
515
|
+
if (this.config.enableFallback) {
|
|
516
|
+
try {
|
|
517
|
+
// Quick ALPN check would go here
|
|
518
|
+
return 'http2';
|
|
519
|
+
}
|
|
520
|
+
catch {
|
|
521
|
+
return 'http1';
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
return 'http2';
|
|
525
|
+
}
|
|
526
|
+
/**
|
|
527
|
+
* Create HTTP/2 connection
|
|
528
|
+
*/
|
|
529
|
+
async createHTTP2Connection(url) {
|
|
530
|
+
return new Promise((resolve, reject) => {
|
|
531
|
+
const session = http2.connect(url.origin, {
|
|
532
|
+
maxOutstandingPings: 10,
|
|
533
|
+
maxSessionMemory: 10,
|
|
534
|
+
...this.config.tls
|
|
535
|
+
});
|
|
536
|
+
session.on('connect', () => resolve(session));
|
|
537
|
+
session.on('error', reject);
|
|
538
|
+
setTimeout(() => reject(new Error('Connection timeout')), 5000);
|
|
539
|
+
});
|
|
540
|
+
}
|
|
541
|
+
/**
|
|
542
|
+
* Create HTTP/1.1 connection
|
|
543
|
+
*/
|
|
544
|
+
createHTTP1Connection(url) {
|
|
545
|
+
const options = {
|
|
546
|
+
keepAlive: true,
|
|
547
|
+
maxSockets: this.config.maxStreams,
|
|
548
|
+
...this.config.tls
|
|
549
|
+
};
|
|
550
|
+
return url.protocol === 'https:'
|
|
551
|
+
? new https.Agent(options)
|
|
552
|
+
: new http.Agent(options);
|
|
553
|
+
}
|
|
554
|
+
/**
|
|
555
|
+
* Send data via HTTP/2
|
|
556
|
+
*/
|
|
557
|
+
async sendHTTP2(conn, data) {
|
|
558
|
+
return new Promise((resolve, reject) => {
|
|
559
|
+
const session = conn.session;
|
|
560
|
+
const req = session.request({
|
|
561
|
+
':method': 'POST',
|
|
562
|
+
':path': '/',
|
|
563
|
+
'content-type': 'application/octet-stream',
|
|
564
|
+
'content-length': data.length
|
|
565
|
+
});
|
|
566
|
+
const chunks = [];
|
|
567
|
+
req.on('response', (headers) => {
|
|
568
|
+
const status = headers[':status'];
|
|
569
|
+
if (status && status >= 400) {
|
|
570
|
+
reject(new Error(`HTTP ${status}`));
|
|
571
|
+
}
|
|
572
|
+
});
|
|
573
|
+
req.on('data', (chunk) => chunks.push(chunk));
|
|
574
|
+
req.on('end', () => resolve(Buffer.concat(chunks)));
|
|
575
|
+
req.on('error', reject);
|
|
576
|
+
req.write(data);
|
|
577
|
+
req.end();
|
|
578
|
+
// Track stream ID if available
|
|
579
|
+
const streamId = req.stream?.id;
|
|
580
|
+
if (streamId !== undefined) {
|
|
581
|
+
conn.streams.add(streamId);
|
|
582
|
+
req.on('close', () => conn.streams.delete(streamId));
|
|
583
|
+
}
|
|
584
|
+
});
|
|
585
|
+
}
|
|
586
|
+
/**
|
|
587
|
+
* Send data via HTTP/1.1
|
|
588
|
+
*/
|
|
589
|
+
async sendHTTP1(conn, endpoint, data) {
|
|
590
|
+
return new Promise((resolve, reject) => {
|
|
591
|
+
const url = new URL(endpoint);
|
|
592
|
+
const options = {
|
|
593
|
+
hostname: url.hostname,
|
|
594
|
+
port: url.port,
|
|
595
|
+
path: url.pathname,
|
|
596
|
+
method: 'POST',
|
|
597
|
+
headers: {
|
|
598
|
+
'Content-Type': 'application/octet-stream',
|
|
599
|
+
'Content-Length': data.length
|
|
600
|
+
},
|
|
601
|
+
agent: conn.session
|
|
602
|
+
};
|
|
603
|
+
const reqFn = url.protocol === 'https:' ? https.request : http.request;
|
|
604
|
+
const req = reqFn(options, (res) => {
|
|
605
|
+
const chunks = [];
|
|
606
|
+
res.on('data', (chunk) => chunks.push(chunk));
|
|
607
|
+
res.on('end', () => {
|
|
608
|
+
if (res.statusCode && res.statusCode >= 400) {
|
|
609
|
+
reject(new Error(`HTTP ${res.statusCode}`));
|
|
610
|
+
}
|
|
611
|
+
else {
|
|
612
|
+
resolve(Buffer.concat(chunks));
|
|
613
|
+
}
|
|
614
|
+
});
|
|
615
|
+
});
|
|
616
|
+
req.on('error', reject);
|
|
617
|
+
req.write(data);
|
|
618
|
+
req.end();
|
|
619
|
+
});
|
|
620
|
+
}
|
|
621
|
+
/**
|
|
622
|
+
* Record request timing
|
|
623
|
+
*/
|
|
624
|
+
recordRequest(startTime, success) {
|
|
625
|
+
const latency = Date.now() - startTime;
|
|
626
|
+
this.metrics.totalRequests++;
|
|
627
|
+
if (success) {
|
|
628
|
+
this.metrics.successfulRequests++;
|
|
629
|
+
}
|
|
630
|
+
else {
|
|
631
|
+
this.metrics.failedRequests++;
|
|
632
|
+
}
|
|
633
|
+
this.latencyBuffer.push(latency);
|
|
634
|
+
if (this.latencyBuffer.length > 1000) {
|
|
635
|
+
this.latencyBuffer.shift();
|
|
636
|
+
}
|
|
637
|
+
// Update average latency
|
|
638
|
+
this.metrics.avgLatency = this.latencyBuffer.reduce((a, b) => a + b, 0) / this.latencyBuffer.length;
|
|
639
|
+
}
|
|
640
|
+
/**
|
|
641
|
+
* Calculate throughput
|
|
642
|
+
*/
|
|
643
|
+
calculateThroughput() {
|
|
644
|
+
const windowMs = 60000; // 1 minute window
|
|
645
|
+
const now = Date.now();
|
|
646
|
+
const recentRequests = this.requests.filter(r => r.endTime && (now - r.endTime) < windowMs);
|
|
647
|
+
if (recentRequests.length === 0)
|
|
648
|
+
return 0;
|
|
649
|
+
const totalBytes = this.metrics.bytesSent + this.metrics.bytesReceived;
|
|
650
|
+
return totalBytes / (windowMs / 1000); // bytes per second
|
|
651
|
+
}
|
|
652
|
+
/**
|
|
653
|
+
* Sleep utility
|
|
654
|
+
*/
|
|
655
|
+
sleep(ms) {
|
|
656
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
657
|
+
}
|
|
658
|
+
/**
|
|
659
|
+
* Fallback to HTTP/2 (already implemented as primary)
|
|
660
|
+
*/
|
|
661
|
+
async fallbackToHTTP2(endpoint) {
|
|
662
|
+
return this.connect(endpoint);
|
|
663
|
+
}
|
|
664
|
+
/**
|
|
665
|
+
* Fallback to HTTP/1.1
|
|
666
|
+
*/
|
|
667
|
+
async fallbackToHTTP1(endpoint) {
|
|
668
|
+
const pool = this.getOrCreatePool(endpoint);
|
|
669
|
+
const conn = await pool.acquire();
|
|
670
|
+
if (!conn.endpoint) {
|
|
671
|
+
const url = new URL(endpoint);
|
|
672
|
+
conn.session = this.createHTTP1Connection(url);
|
|
673
|
+
conn.protocol = 'http1';
|
|
674
|
+
conn.endpoint = endpoint;
|
|
675
|
+
}
|
|
676
|
+
return conn;
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
exports.QUICTransport = QUICTransport;
|
|
680
|
+
/**
|
|
681
|
+
* Default QUIC configuration
|
|
682
|
+
*/
|
|
683
|
+
exports.DEFAULT_QUIC_CONFIG = {
|
|
684
|
+
host: 'localhost',
|
|
685
|
+
port: 4433,
|
|
686
|
+
maxStreams: 100,
|
|
687
|
+
idleTimeout: 30000,
|
|
688
|
+
enableFallback: true,
|
|
689
|
+
retryAttempts: 3,
|
|
690
|
+
retryDelay: 1000,
|
|
691
|
+
poolSize: {
|
|
692
|
+
min: 2,
|
|
693
|
+
max: 10
|
|
694
|
+
},
|
|
695
|
+
circuitBreaker: {
|
|
696
|
+
failureThreshold: 5,
|
|
697
|
+
successThreshold: 2,
|
|
698
|
+
timeout: 60000
|
|
699
|
+
},
|
|
700
|
+
enableTLS: false
|
|
701
|
+
};
|
|
702
|
+
/**
|
|
703
|
+
* Create QUIC transport with default configuration
|
|
704
|
+
*/
|
|
705
|
+
function createQUICTransport(config) {
|
|
706
|
+
return new QUICTransport({
|
|
707
|
+
...exports.DEFAULT_QUIC_CONFIG,
|
|
708
|
+
...config
|
|
709
|
+
});
|
|
710
|
+
}
|
|
711
|
+
//# sourceMappingURL=QUICTransport.js.map
|