@defai.digital/resilience-domain 13.0.3
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/LICENSE +214 -0
- package/dist/_contracts.d.ts +11 -0
- package/dist/_contracts.d.ts.map +1 -0
- package/dist/_contracts.js +20 -0
- package/dist/_contracts.js.map +1 -0
- package/dist/circuit-breaker.d.ts +42 -0
- package/dist/circuit-breaker.d.ts.map +1 -0
- package/dist/circuit-breaker.js +188 -0
- package/dist/circuit-breaker.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -0
- package/dist/loop-guard.d.ts +47 -0
- package/dist/loop-guard.d.ts.map +1 -0
- package/dist/loop-guard.js +164 -0
- package/dist/loop-guard.js.map +1 -0
- package/dist/metrics-collector.d.ts +41 -0
- package/dist/metrics-collector.d.ts.map +1 -0
- package/dist/metrics-collector.js +189 -0
- package/dist/metrics-collector.js.map +1 -0
- package/dist/rate-limiter.d.ts +35 -0
- package/dist/rate-limiter.d.ts.map +1 -0
- package/dist/rate-limiter.js +189 -0
- package/dist/rate-limiter.js.map +1 -0
- package/dist/resource-enforcer.d.ts +47 -0
- package/dist/resource-enforcer.d.ts.map +1 -0
- package/dist/resource-enforcer.js +156 -0
- package/dist/resource-enforcer.js.map +1 -0
- package/package.json +41 -0
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Loop Guard Implementation
|
|
3
|
+
*
|
|
4
|
+
* Prevents infinite loops and runaway execution.
|
|
5
|
+
*/
|
|
6
|
+
import { LoopGuardErrorCodes, createDefaultLoopGuardConfig, createLoopGuardContext, } from './_contracts.js';
|
|
7
|
+
/**
|
|
8
|
+
* Loop guard error
|
|
9
|
+
*/
|
|
10
|
+
export class LoopGuardError extends Error {
|
|
11
|
+
code;
|
|
12
|
+
context;
|
|
13
|
+
constructor(code, message, context) {
|
|
14
|
+
super(message);
|
|
15
|
+
this.code = code;
|
|
16
|
+
this.context = context;
|
|
17
|
+
this.name = 'LoopGuardError';
|
|
18
|
+
}
|
|
19
|
+
static maxIterations(context) {
|
|
20
|
+
return new LoopGuardError(LoopGuardErrorCodes.MAX_ITERATIONS, `Maximum iterations (${context.iterations}) exceeded`, context);
|
|
21
|
+
}
|
|
22
|
+
static maxDuration(context) {
|
|
23
|
+
return new LoopGuardError(LoopGuardErrorCodes.MAX_DURATION, `Maximum duration (${context.elapsedMs}ms) exceeded`, context);
|
|
24
|
+
}
|
|
25
|
+
static contextNotFound(contextId) {
|
|
26
|
+
return new LoopGuardError(LoopGuardErrorCodes.CONTEXT_NOT_FOUND, `Loop guard context not found: ${contextId}`);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Creates a loop guard
|
|
31
|
+
*/
|
|
32
|
+
export function createLoopGuard(config) {
|
|
33
|
+
const cfg = { ...createDefaultLoopGuardConfig(), ...config };
|
|
34
|
+
const contexts = new Map();
|
|
35
|
+
const listeners = new Set();
|
|
36
|
+
function emitWarning(contextId, result) {
|
|
37
|
+
for (const listener of listeners) {
|
|
38
|
+
try {
|
|
39
|
+
listener(contextId, result);
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
// Ignore listener errors
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return {
|
|
47
|
+
startContext(contextId, metadata) {
|
|
48
|
+
const context = createLoopGuardContext(contextId);
|
|
49
|
+
contexts.set(contextId, {
|
|
50
|
+
...context,
|
|
51
|
+
metadata,
|
|
52
|
+
startTime: Date.now(),
|
|
53
|
+
});
|
|
54
|
+
},
|
|
55
|
+
checkIteration(contextId) {
|
|
56
|
+
const context = contexts.get(contextId);
|
|
57
|
+
if (!context) {
|
|
58
|
+
throw LoopGuardError.contextNotFound(contextId);
|
|
59
|
+
}
|
|
60
|
+
// Update iteration and elapsed time
|
|
61
|
+
context.iterations++;
|
|
62
|
+
context.elapsedMs = Date.now() - context.startTime;
|
|
63
|
+
// Check max iterations
|
|
64
|
+
if (context.iterations >= cfg.maxIterations) {
|
|
65
|
+
return {
|
|
66
|
+
status: 'blocked',
|
|
67
|
+
iteration: context.iterations,
|
|
68
|
+
elapsedMs: context.elapsedMs,
|
|
69
|
+
reason: `Maximum iterations (${cfg.maxIterations}) exceeded`,
|
|
70
|
+
blockType: 'max-iterations',
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
// Check max duration
|
|
74
|
+
if (context.elapsedMs >= cfg.maxDurationMs) {
|
|
75
|
+
return {
|
|
76
|
+
status: 'blocked',
|
|
77
|
+
iteration: context.iterations,
|
|
78
|
+
elapsedMs: context.elapsedMs,
|
|
79
|
+
reason: `Maximum duration (${cfg.maxDurationMs}ms) exceeded`,
|
|
80
|
+
blockType: 'max-duration',
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
// Check iteration warning
|
|
84
|
+
if (!context.warningIssued && context.iterations >= cfg.warnAtIterations) {
|
|
85
|
+
context.warningIssued = true;
|
|
86
|
+
const result = {
|
|
87
|
+
status: 'warning',
|
|
88
|
+
iteration: context.iterations,
|
|
89
|
+
elapsedMs: context.elapsedMs,
|
|
90
|
+
message: `Approaching iteration limit (${context.iterations}/${cfg.maxIterations})`,
|
|
91
|
+
warningType: 'iteration',
|
|
92
|
+
};
|
|
93
|
+
emitWarning(contextId, result);
|
|
94
|
+
return result;
|
|
95
|
+
}
|
|
96
|
+
// Check duration warning
|
|
97
|
+
if (!context.warningIssued && context.elapsedMs >= cfg.warnAtDurationMs) {
|
|
98
|
+
context.warningIssued = true;
|
|
99
|
+
const result = {
|
|
100
|
+
status: 'warning',
|
|
101
|
+
iteration: context.iterations,
|
|
102
|
+
elapsedMs: context.elapsedMs,
|
|
103
|
+
message: `Approaching duration limit (${context.elapsedMs}ms/${cfg.maxDurationMs}ms)`,
|
|
104
|
+
warningType: 'duration',
|
|
105
|
+
};
|
|
106
|
+
emitWarning(contextId, result);
|
|
107
|
+
return result;
|
|
108
|
+
}
|
|
109
|
+
return {
|
|
110
|
+
status: 'ok',
|
|
111
|
+
iteration: context.iterations,
|
|
112
|
+
elapsedMs: context.elapsedMs,
|
|
113
|
+
};
|
|
114
|
+
},
|
|
115
|
+
endContext(contextId) {
|
|
116
|
+
const context = contexts.get(contextId);
|
|
117
|
+
if (context) {
|
|
118
|
+
context.elapsedMs = Date.now() - context.startTime;
|
|
119
|
+
contexts.delete(contextId);
|
|
120
|
+
// Return without internal startTime property
|
|
121
|
+
const { startTime: _startTime, ...result } = context;
|
|
122
|
+
return result;
|
|
123
|
+
}
|
|
124
|
+
return undefined;
|
|
125
|
+
},
|
|
126
|
+
getContext(contextId) {
|
|
127
|
+
const context = contexts.get(contextId);
|
|
128
|
+
if (context) {
|
|
129
|
+
const { startTime: _startTime, ...result } = context;
|
|
130
|
+
return {
|
|
131
|
+
...result,
|
|
132
|
+
elapsedMs: Date.now() - context.startTime,
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
return undefined;
|
|
136
|
+
},
|
|
137
|
+
onWarning(listener) {
|
|
138
|
+
listeners.add(listener);
|
|
139
|
+
return () => listeners.delete(listener);
|
|
140
|
+
},
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Creates a loop guard that throws on blocked
|
|
145
|
+
*/
|
|
146
|
+
export function createStrictLoopGuard(config) {
|
|
147
|
+
const guard = createLoopGuard(config);
|
|
148
|
+
const originalCheck = guard.checkIteration.bind(guard);
|
|
149
|
+
guard.checkIteration = (contextId) => {
|
|
150
|
+
const result = originalCheck(contextId);
|
|
151
|
+
if (result.status === 'blocked') {
|
|
152
|
+
const context = guard.getContext(contextId);
|
|
153
|
+
if (result.blockType === 'max-iterations') {
|
|
154
|
+
throw LoopGuardError.maxIterations(context);
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
throw LoopGuardError.maxDuration(context);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
return result;
|
|
161
|
+
};
|
|
162
|
+
return guard;
|
|
163
|
+
}
|
|
164
|
+
//# sourceMappingURL=loop-guard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loop-guard.js","sourceRoot":"","sources":["../src/loop-guard.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Metrics Collector Implementation
|
|
3
|
+
*
|
|
4
|
+
* Basic observability metrics for monitoring system health.
|
|
5
|
+
*/
|
|
6
|
+
import { type MetricsTimeRange, type RequestMetric, type ErrorMetric, type MetricsSnapshot } from './_contracts.js';
|
|
7
|
+
/**
|
|
8
|
+
* Metrics collector interface
|
|
9
|
+
*/
|
|
10
|
+
export interface MetricsCollector {
|
|
11
|
+
/** Record a request metric */
|
|
12
|
+
recordRequest(metric: RequestMetric): void;
|
|
13
|
+
/** Record an error metric */
|
|
14
|
+
recordError(metric: ErrorMetric): void;
|
|
15
|
+
/** Get metrics snapshot */
|
|
16
|
+
getStats(timeRange?: MetricsTimeRange): MetricsSnapshot;
|
|
17
|
+
/** Reset all metrics */
|
|
18
|
+
reset(): void;
|
|
19
|
+
/** Get raw request metrics */
|
|
20
|
+
getRequestMetrics(limit?: number): RequestMetric[];
|
|
21
|
+
/** Get raw error metrics */
|
|
22
|
+
getErrorMetrics(limit?: number): ErrorMetric[];
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Metrics collector configuration
|
|
26
|
+
*/
|
|
27
|
+
export interface MetricsCollectorConfig {
|
|
28
|
+
/** Maximum number of request metrics to retain */
|
|
29
|
+
maxRequestMetrics: number;
|
|
30
|
+
/** Maximum number of error metrics to retain */
|
|
31
|
+
maxErrorMetrics: number;
|
|
32
|
+
/** Default time range for stats (e.g., '-1h') */
|
|
33
|
+
defaultTimeRange: string;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Creates a metrics collector
|
|
37
|
+
*/
|
|
38
|
+
export declare function createMetricsCollector(config?: Partial<MetricsCollectorConfig>): MetricsCollector;
|
|
39
|
+
export declare function getGlobalMetrics(): MetricsCollector;
|
|
40
|
+
export declare function resetGlobalMetrics(): void;
|
|
41
|
+
//# sourceMappingURL=metrics-collector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metrics-collector.d.ts","sourceRoot":"","sources":["../src/metrics-collector.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACL,KAAK,gBAAgB,EACrB,KAAK,aAAa,EAClB,KAAK,WAAW,EAEhB,KAAK,eAAe,EAGrB,MAAM,iBAAiB,CAAC;AAEzB;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,8BAA8B;IAC9B,aAAa,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI,CAAC;IAE3C,6BAA6B;IAC7B,WAAW,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI,CAAC;IAEvC,2BAA2B;IAC3B,QAAQ,CAAC,SAAS,CAAC,EAAE,gBAAgB,GAAG,eAAe,CAAC;IAExD,wBAAwB;IACxB,KAAK,IAAI,IAAI,CAAC;IAEd,8BAA8B;IAC9B,iBAAiB,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,aAAa,EAAE,CAAC;IAEnD,4BAA4B;IAC5B,eAAe,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,WAAW,EAAE,CAAC;CAChD;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,kDAAkD;IAClD,iBAAiB,EAAE,MAAM,CAAC;IAE1B,gDAAgD;IAChD,eAAe,EAAE,MAAM,CAAC;IAExB,iDAAiD;IACjD,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAQD;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,CAAC,EAAE,OAAO,CAAC,sBAAsB,CAAC,GACvC,gBAAgB,CAyMlB;AAOD,wBAAgB,gBAAgB,IAAI,gBAAgB,CAKnD;AAED,wBAAgB,kBAAkB,IAAI,IAAI,CAEzC"}
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Metrics Collector Implementation
|
|
3
|
+
*
|
|
4
|
+
* Basic observability metrics for monitoring system health.
|
|
5
|
+
*/
|
|
6
|
+
import { TIME_MULTIPLIERS, DEFAULT_TIME_RANGE_MS, } from './_contracts.js';
|
|
7
|
+
const DEFAULT_CONFIG = {
|
|
8
|
+
maxRequestMetrics: 10000,
|
|
9
|
+
maxErrorMetrics: 1000,
|
|
10
|
+
defaultTimeRange: '-1h',
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Creates a metrics collector
|
|
14
|
+
*/
|
|
15
|
+
export function createMetricsCollector(config) {
|
|
16
|
+
const cfg = { ...DEFAULT_CONFIG, ...config };
|
|
17
|
+
const requestMetrics = [];
|
|
18
|
+
const errorMetrics = [];
|
|
19
|
+
function parseTimeRange(timeRange) {
|
|
20
|
+
const end = timeRange.end === 'now' ? new Date() : new Date(timeRange.end);
|
|
21
|
+
let start;
|
|
22
|
+
if (timeRange.start.startsWith('-')) {
|
|
23
|
+
// Relative time like '-1h', '-30m', '-1d'
|
|
24
|
+
const match = /^-(\d+)([smhd])$/.exec(timeRange.start);
|
|
25
|
+
if (match) {
|
|
26
|
+
const value = parseInt(match[1], 10);
|
|
27
|
+
const unit = match[2];
|
|
28
|
+
const ms = value * (TIME_MULTIPLIERS[unit] ?? DEFAULT_TIME_RANGE_MS);
|
|
29
|
+
start = new Date(end.getTime() - ms);
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
start = new Date(end.getTime() - DEFAULT_TIME_RANGE_MS);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
start = new Date(timeRange.start);
|
|
37
|
+
}
|
|
38
|
+
return { start, end };
|
|
39
|
+
}
|
|
40
|
+
function filterByTimeRange(items, timeRange) {
|
|
41
|
+
const { start, end } = parseTimeRange(timeRange);
|
|
42
|
+
return items.filter((item) => {
|
|
43
|
+
const ts = new Date(item.timestamp);
|
|
44
|
+
return ts >= start && ts <= end;
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
function calculateLatencyStats(latencies) {
|
|
48
|
+
if (latencies.length === 0) {
|
|
49
|
+
return { min: 0, max: 0, mean: 0, p50: 0, p95: 0, p99: 0, count: 0 };
|
|
50
|
+
}
|
|
51
|
+
const sorted = [...latencies].sort((a, b) => a - b);
|
|
52
|
+
const count = sorted.length;
|
|
53
|
+
const percentile = (p) => {
|
|
54
|
+
const index = Math.ceil((p / 100) * count) - 1;
|
|
55
|
+
return sorted[Math.max(0, Math.min(index, count - 1))];
|
|
56
|
+
};
|
|
57
|
+
return {
|
|
58
|
+
min: sorted[0],
|
|
59
|
+
max: sorted[count - 1],
|
|
60
|
+
mean: Math.round(latencies.reduce((a, b) => a + b, 0) / count),
|
|
61
|
+
p50: percentile(50),
|
|
62
|
+
p95: percentile(95),
|
|
63
|
+
p99: percentile(99),
|
|
64
|
+
count,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
return {
|
|
68
|
+
recordRequest(metric) {
|
|
69
|
+
requestMetrics.push(metric);
|
|
70
|
+
// Trim if over limit
|
|
71
|
+
if (requestMetrics.length > cfg.maxRequestMetrics) {
|
|
72
|
+
requestMetrics.splice(0, requestMetrics.length - cfg.maxRequestMetrics);
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
recordError(metric) {
|
|
76
|
+
errorMetrics.push(metric);
|
|
77
|
+
// Trim if over limit
|
|
78
|
+
if (errorMetrics.length > cfg.maxErrorMetrics) {
|
|
79
|
+
errorMetrics.splice(0, errorMetrics.length - cfg.maxErrorMetrics);
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
getStats(timeRange) {
|
|
83
|
+
const range = timeRange ?? {
|
|
84
|
+
start: cfg.defaultTimeRange,
|
|
85
|
+
end: 'now',
|
|
86
|
+
};
|
|
87
|
+
const filteredRequests = filterByTimeRange(requestMetrics, range);
|
|
88
|
+
const filteredErrors = filterByTimeRange(errorMetrics, range);
|
|
89
|
+
// Calculate request stats
|
|
90
|
+
const successCount = filteredRequests.filter((r) => r.success).length;
|
|
91
|
+
const failureCount = filteredRequests.length - successCount;
|
|
92
|
+
const successRate = filteredRequests.length > 0
|
|
93
|
+
? successCount / filteredRequests.length
|
|
94
|
+
: 1;
|
|
95
|
+
// Calculate latency stats
|
|
96
|
+
const latencies = filteredRequests.map((r) => r.durationMs);
|
|
97
|
+
const latencyStats = calculateLatencyStats(latencies);
|
|
98
|
+
// Calculate token stats
|
|
99
|
+
const inputTokens = filteredRequests.reduce((sum, r) => sum + (r.inputTokens ?? 0), 0);
|
|
100
|
+
const outputTokens = filteredRequests.reduce((sum, r) => sum + (r.outputTokens ?? 0), 0);
|
|
101
|
+
// Calculate cost stats
|
|
102
|
+
const totalCost = filteredRequests.reduce((sum, r) => sum + (r.estimatedCost ?? 0), 0);
|
|
103
|
+
// Group errors by code
|
|
104
|
+
const errorsByCode = {};
|
|
105
|
+
for (const error of filteredErrors) {
|
|
106
|
+
errorsByCode[error.code] = (errorsByCode[error.code] ?? 0) + 1;
|
|
107
|
+
}
|
|
108
|
+
// Group by provider
|
|
109
|
+
const byProvider = {};
|
|
110
|
+
for (const req of filteredRequests) {
|
|
111
|
+
if (!byProvider[req.providerId]) {
|
|
112
|
+
byProvider[req.providerId] = {
|
|
113
|
+
requests: 0,
|
|
114
|
+
failures: 0,
|
|
115
|
+
latencyP50: 0,
|
|
116
|
+
tokens: 0,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
const p = byProvider[req.providerId];
|
|
120
|
+
p.requests++;
|
|
121
|
+
if (!req.success)
|
|
122
|
+
p.failures++;
|
|
123
|
+
p.tokens += (req.inputTokens ?? 0) + (req.outputTokens ?? 0);
|
|
124
|
+
}
|
|
125
|
+
// Calculate per-provider p50
|
|
126
|
+
for (const providerId of Object.keys(byProvider)) {
|
|
127
|
+
const providerLatencies = filteredRequests
|
|
128
|
+
.filter((r) => r.providerId === providerId)
|
|
129
|
+
.map((r) => r.durationMs);
|
|
130
|
+
byProvider[providerId].latencyP50 =
|
|
131
|
+
calculateLatencyStats(providerLatencies).p50;
|
|
132
|
+
}
|
|
133
|
+
return {
|
|
134
|
+
timeRange: range,
|
|
135
|
+
requests: {
|
|
136
|
+
total: filteredRequests.length,
|
|
137
|
+
success: successCount,
|
|
138
|
+
failure: failureCount,
|
|
139
|
+
successRate: Math.round(successRate * 1000) / 1000,
|
|
140
|
+
},
|
|
141
|
+
latency: latencyStats,
|
|
142
|
+
tokens: {
|
|
143
|
+
input: inputTokens,
|
|
144
|
+
output: outputTokens,
|
|
145
|
+
total: inputTokens + outputTokens,
|
|
146
|
+
},
|
|
147
|
+
cost: {
|
|
148
|
+
estimated: Math.round(totalCost * 10000) / 10000,
|
|
149
|
+
perRequest: filteredRequests.length > 0
|
|
150
|
+
? Math.round((totalCost / filteredRequests.length) * 10000) / 10000
|
|
151
|
+
: 0,
|
|
152
|
+
},
|
|
153
|
+
errors: errorsByCode,
|
|
154
|
+
byProvider,
|
|
155
|
+
generatedAt: new Date().toISOString(),
|
|
156
|
+
};
|
|
157
|
+
},
|
|
158
|
+
reset() {
|
|
159
|
+
requestMetrics.length = 0;
|
|
160
|
+
errorMetrics.length = 0;
|
|
161
|
+
},
|
|
162
|
+
getRequestMetrics(limit) {
|
|
163
|
+
if (limit) {
|
|
164
|
+
return requestMetrics.slice(-limit);
|
|
165
|
+
}
|
|
166
|
+
return [...requestMetrics];
|
|
167
|
+
},
|
|
168
|
+
getErrorMetrics(limit) {
|
|
169
|
+
if (limit) {
|
|
170
|
+
return errorMetrics.slice(-limit);
|
|
171
|
+
}
|
|
172
|
+
return [...errorMetrics];
|
|
173
|
+
},
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Global metrics collector singleton
|
|
178
|
+
*/
|
|
179
|
+
let globalMetrics = null;
|
|
180
|
+
export function getGlobalMetrics() {
|
|
181
|
+
if (!globalMetrics) {
|
|
182
|
+
globalMetrics = createMetricsCollector();
|
|
183
|
+
}
|
|
184
|
+
return globalMetrics;
|
|
185
|
+
}
|
|
186
|
+
export function resetGlobalMetrics() {
|
|
187
|
+
globalMetrics = null;
|
|
188
|
+
}
|
|
189
|
+
//# sourceMappingURL=metrics-collector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metrics-collector.js","sourceRoot":"","sources":["../src/metrics-collector.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAML,gBAAgB,EAChB,qBAAqB,GACtB,MAAM,iBAAiB,CAAC;AAuCzB,MAAM,cAAc,GAA2B;IAC7C,iBAAiB,EAAE,KAAK;IACxB,eAAe,EAAE,IAAI;IACrB,gBAAgB,EAAE,KAAK;CACxB,CAAC;AAEF;;GAEG;AACH,MAAM,UAAU,sBAAsB,CACpC,MAAwC;IAExC,MAAM,GAAG,GAAG,EAAE,GAAG,cAAc,EAAE,GAAG,MAAM,EAAE,CAAC;IAE7C,MAAM,cAAc,GAAoB,EAAE,CAAC;IAC3C,MAAM,YAAY,GAAkB,EAAE,CAAC;IAEvC,SAAS,cAAc,CAAC,SAA2B;QACjD,MAAM,GAAG,GAAG,SAAS,CAAC,GAAG,KAAK,KAAK,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;QAE3E,IAAI,KAAW,CAAC;QAChB,IAAI,SAAS,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACpC,0CAA0C;YAC1C,MAAM,KAAK,GAAG,kBAAkB,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;YACvD,IAAI,KAAK,EAAE,CAAC;gBACV,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAE,EAAE,EAAE,CAAC,CAAC;gBACtC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;gBACtB,MAAM,EAAE,GAAG,KAAK,GAAG,CAAC,gBAAgB,CAAC,IAAK,CAAC,IAAI,qBAAqB,CAAC,CAAC;gBACtE,KAAK,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC;YACvC,CAAC;iBAAM,CAAC;gBACN,KAAK,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,qBAAqB,CAAC,CAAC;YAC1D,CAAC;QACH,CAAC;aAAM,CAAC;YACN,KAAK,GAAG,IAAI,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QACpC,CAAC;QAED,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC;IACxB,CAAC;IAED,SAAS,iBAAiB,CACxB,KAAU,EACV,SAA2B;QAE3B,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,cAAc,CAAC,SAAS,CAAC,CAAC;QACjD,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE;YAC3B,MAAM,EAAE,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACpC,OAAO,EAAE,IAAI,KAAK,IAAI,EAAE,IAAI,GAAG,CAAC;QAClC,CAAC,CAAC,CAAC;IACL,CAAC;IAED,SAAS,qBAAqB,CAAC,SAAmB;QAChD,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC3B,OAAO,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;QACvE,CAAC;QAED,MAAM,MAAM,GAAG,CAAC,GAAG,SAAS,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QACpD,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC;QAE5B,MAAM,UAAU,GAAG,CAAC,CAAS,EAAU,EAAE;YACvC,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC;YAC/C,OAAO,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC,CAAE,CAAC;QAC1D,CAAC,CAAC;QAEF,OAAO;YACL,GAAG,EAAE,MAAM,CAAC,CAAC,CAAE;YACf,GAAG,EAAE,MAAM,CAAC,KAAK,GAAG,CAAC,CAAE;YACvB,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,GAAG,KAAK,CAAC;YAC9D,GAAG,EAAE,UAAU,CAAC,EAAE,CAAC;YACnB,GAAG,EAAE,UAAU,CAAC,EAAE,CAAC;YACnB,GAAG,EAAE,UAAU,CAAC,EAAE,CAAC;YACnB,KAAK;SACN,CAAC;IACJ,CAAC;IAED,OAAO;QACL,aAAa,CAAC,MAAqB;YACjC,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YAE5B,qBAAqB;YACrB,IAAI,cAAc,CAAC,MAAM,GAAG,GAAG,CAAC,iBAAiB,EAAE,CAAC;gBAClD,cAAc,CAAC,MAAM,CAAC,CAAC,EAAE,cAAc,CAAC,MAAM,GAAG,GAAG,CAAC,iBAAiB,CAAC,CAAC;YAC1E,CAAC;QACH,CAAC;QAED,WAAW,CAAC,MAAmB;YAC7B,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YAE1B,qBAAqB;YACrB,IAAI,YAAY,CAAC,MAAM,GAAG,GAAG,CAAC,eAAe,EAAE,CAAC;gBAC9C,YAAY,CAAC,MAAM,CAAC,CAAC,EAAE,YAAY,CAAC,MAAM,GAAG,GAAG,CAAC,eAAe,CAAC,CAAC;YACpE,CAAC;QACH,CAAC;QAED,QAAQ,CAAC,SAA4B;YACnC,MAAM,KAAK,GAAG,SAAS,IAAI;gBACzB,KAAK,EAAE,GAAG,CAAC,gBAAgB;gBAC3B,GAAG,EAAE,KAAK;aACX,CAAC;YAEF,MAAM,gBAAgB,GAAG,iBAAiB,CAAC,cAAc,EAAE,KAAK,CAAC,CAAC;YAClE,MAAM,cAAc,GAAG,iBAAiB,CAAC,YAAY,EAAE,KAAK,CAAC,CAAC;YAE9D,0BAA0B;YAC1B,MAAM,YAAY,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC;YACtE,MAAM,YAAY,GAAG,gBAAgB,CAAC,MAAM,GAAG,YAAY,CAAC;YAC5D,MAAM,WAAW,GACf,gBAAgB,CAAC,MAAM,GAAG,CAAC;gBACzB,CAAC,CAAC,YAAY,GAAG,gBAAgB,CAAC,MAAM;gBACxC,CAAC,CAAC,CAAC,CAAC;YAER,0BAA0B;YAC1B,MAAM,SAAS,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;YAC5D,MAAM,YAAY,GAAG,qBAAqB,CAAC,SAAS,CAAC,CAAC;YAEtD,wBAAwB;YACxB,MAAM,WAAW,GAAG,gBAAgB,CAAC,MAAM,CACzC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,WAAW,IAAI,CAAC,CAAC,EACtC,CAAC,CACF,CAAC;YACF,MAAM,YAAY,GAAG,gBAAgB,CAAC,MAAM,CAC1C,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,YAAY,IAAI,CAAC,CAAC,EACvC,CAAC,CACF,CAAC;YAEF,uBAAuB;YACvB,MAAM,SAAS,GAAG,gBAAgB,CAAC,MAAM,CACvC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,aAAa,IAAI,CAAC,CAAC,EACxC,CAAC,CACF,CAAC;YAEF,uBAAuB;YACvB,MAAM,YAAY,GAA2B,EAAE,CAAC;YAChD,KAAK,MAAM,KAAK,IAAI,cAAc,EAAE,CAAC;gBACnC,YAAY,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;YACjE,CAAC;YAED,oBAAoB;YACpB,MAAM,UAAU,GAGZ,EAAE,CAAC;YAEP,KAAK,MAAM,GAAG,IAAI,gBAAgB,EAAE,CAAC;gBACnC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC;oBAChC,UAAU,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG;wBAC3B,QAAQ,EAAE,CAAC;wBACX,QAAQ,EAAE,CAAC;wBACX,UAAU,EAAE,CAAC;wBACb,MAAM,EAAE,CAAC;qBACV,CAAC;gBACJ,CAAC;gBACD,MAAM,CAAC,GAAG,UAAU,CAAC,GAAG,CAAC,UAAU,CAAE,CAAC;gBACtC,CAAC,CAAC,QAAQ,EAAE,CAAC;gBACb,IAAI,CAAC,GAAG,CAAC,OAAO;oBAAE,CAAC,CAAC,QAAQ,EAAE,CAAC;gBAC/B,CAAC,CAAC,MAAM,IAAI,CAAC,GAAG,CAAC,WAAW,IAAI,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,YAAY,IAAI,CAAC,CAAC,CAAC;YAC/D,CAAC;YAED,6BAA6B;YAC7B,KAAK,MAAM,UAAU,IAAI,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;gBACjD,MAAM,iBAAiB,GAAG,gBAAgB;qBACvC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,KAAK,UAAU,CAAC;qBAC1C,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;gBAC5B,UAAU,CAAC,UAAU,CAAE,CAAC,UAAU;oBAChC,qBAAqB,CAAC,iBAAiB,CAAC,CAAC,GAAG,CAAC;YACjD,CAAC;YAED,OAAO;gBACL,SAAS,EAAE,KAAK;gBAChB,QAAQ,EAAE;oBACR,KAAK,EAAE,gBAAgB,CAAC,MAAM;oBAC9B,OAAO,EAAE,YAAY;oBACrB,OAAO,EAAE,YAAY;oBACrB,WAAW,EAAE,IAAI,CAAC,KAAK,CAAC,WAAW,GAAG,IAAI,CAAC,GAAG,IAAI;iBACnD;gBACD,OAAO,EAAE,YAAY;gBACrB,MAAM,EAAE;oBACN,KAAK,EAAE,WAAW;oBAClB,MAAM,EAAE,YAAY;oBACpB,KAAK,EAAE,WAAW,GAAG,YAAY;iBAClC;gBACD,IAAI,EAAE;oBACJ,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,KAAK,CAAC,GAAG,KAAK;oBAChD,UAAU,EACR,gBAAgB,CAAC,MAAM,GAAG,CAAC;wBACzB,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,SAAS,GAAG,gBAAgB,CAAC,MAAM,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK;wBACnE,CAAC,CAAC,CAAC;iBACR;gBACD,MAAM,EAAE,YAAY;gBACpB,UAAU;gBACV,WAAW,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;aACtC,CAAC;QACJ,CAAC;QAED,KAAK;YACH,cAAc,CAAC,MAAM,GAAG,CAAC,CAAC;YAC1B,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC;QAC1B,CAAC;QAED,iBAAiB,CAAC,KAAc;YAC9B,IAAI,KAAK,EAAE,CAAC;gBACV,OAAO,cAAc,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC;YACtC,CAAC;YACD,OAAO,CAAC,GAAG,cAAc,CAAC,CAAC;QAC7B,CAAC;QAED,eAAe,CAAC,KAAc;YAC5B,IAAI,KAAK,EAAE,CAAC;gBACV,OAAO,YAAY,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC;YACpC,CAAC;YACD,OAAO,CAAC,GAAG,YAAY,CAAC,CAAC;QAC3B,CAAC;KACF,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,IAAI,aAAa,GAA4B,IAAI,CAAC;AAElD,MAAM,UAAU,gBAAgB;IAC9B,IAAI,CAAC,aAAa,EAAE,CAAC;QACnB,aAAa,GAAG,sBAAsB,EAAE,CAAC;IAC3C,CAAC;IACD,OAAO,aAAa,CAAC;AACvB,CAAC;AAED,MAAM,UAAU,kBAAkB;IAChC,aAAa,GAAG,IAAI,CAAC;AACvB,CAAC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rate Limiter Implementation
|
|
3
|
+
*
|
|
4
|
+
* Token bucket rate limiting to prevent API limit violations.
|
|
5
|
+
*/
|
|
6
|
+
import { type RateLimiterConfig, type RateLimiterStats, type RateLimiterAcquireResult } from './_contracts.js';
|
|
7
|
+
/**
|
|
8
|
+
* Rate limiter error
|
|
9
|
+
*/
|
|
10
|
+
export declare class RateLimiterError extends Error {
|
|
11
|
+
readonly code: string;
|
|
12
|
+
readonly retryAfterMs?: number | undefined;
|
|
13
|
+
constructor(code: string, message: string, retryAfterMs?: number | undefined);
|
|
14
|
+
static rateLimited(retryAfterMs: number): RateLimiterError;
|
|
15
|
+
static queueFull(): RateLimiterError;
|
|
16
|
+
static timeout(): RateLimiterError;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Rate limiter interface
|
|
20
|
+
*/
|
|
21
|
+
export interface RateLimiter {
|
|
22
|
+
/** Acquire capacity (waits if needed) */
|
|
23
|
+
acquire(tokens?: number): Promise<RateLimiterAcquireResult>;
|
|
24
|
+
/** Try to acquire capacity (non-blocking) */
|
|
25
|
+
tryAcquire(tokens?: number): boolean;
|
|
26
|
+
/** Get current statistics */
|
|
27
|
+
getStats(): RateLimiterStats;
|
|
28
|
+
/** Reset the limiter */
|
|
29
|
+
reset(): void;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Creates a rate limiter
|
|
33
|
+
*/
|
|
34
|
+
export declare function createRateLimiter(config?: Partial<RateLimiterConfig>): RateLimiter;
|
|
35
|
+
//# sourceMappingURL=rate-limiter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate-limiter.d.ts","sourceRoot":"","sources":["../src/rate-limiter.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACL,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,KAAK,wBAAwB,EAK9B,MAAM,iBAAiB,CAAC;AAEzB;;GAEG;AACH,qBAAa,gBAAiB,SAAQ,KAAK;aAEvB,IAAI,EAAE,MAAM;aAEZ,YAAY,CAAC,EAAE,MAAM;gBAFrB,IAAI,EAAE,MAAM,EAC5B,OAAO,EAAE,MAAM,EACC,YAAY,CAAC,EAAE,MAAM,YAAA;IAMvC,MAAM,CAAC,WAAW,CAAC,YAAY,EAAE,MAAM,GAAG,gBAAgB;IAQ1D,MAAM,CAAC,SAAS,IAAI,gBAAgB;IAOpC,MAAM,CAAC,OAAO,IAAI,gBAAgB;CAMnC;AAWD;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,yCAAyC;IACzC,OAAO,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,wBAAwB,CAAC,CAAC;IAE5D,6CAA6C;IAC7C,UAAU,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAErC,6BAA6B;IAC7B,QAAQ,IAAI,gBAAgB,CAAC;IAE7B,wBAAwB;IACxB,KAAK,IAAI,IAAI,CAAC;CACf;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,CAAC,EAAE,OAAO,CAAC,iBAAiB,CAAC,GAClC,WAAW,CAqLb"}
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rate Limiter Implementation
|
|
3
|
+
*
|
|
4
|
+
* Token bucket rate limiting to prevent API limit violations.
|
|
5
|
+
*/
|
|
6
|
+
import { RateLimiterErrorCodes, createDefaultRateLimiterConfig, DEFAULT_TOKEN_WINDOW_MS, DEFAULT_CHECK_INTERVAL_MS, } from './_contracts.js';
|
|
7
|
+
/**
|
|
8
|
+
* Rate limiter error
|
|
9
|
+
*/
|
|
10
|
+
export class RateLimiterError extends Error {
|
|
11
|
+
code;
|
|
12
|
+
retryAfterMs;
|
|
13
|
+
constructor(code, message, retryAfterMs) {
|
|
14
|
+
super(message);
|
|
15
|
+
this.code = code;
|
|
16
|
+
this.retryAfterMs = retryAfterMs;
|
|
17
|
+
this.name = 'RateLimiterError';
|
|
18
|
+
}
|
|
19
|
+
static rateLimited(retryAfterMs) {
|
|
20
|
+
return new RateLimiterError(RateLimiterErrorCodes.RATE_LIMITED, `Rate limit exceeded. Retry after ${retryAfterMs}ms`, retryAfterMs);
|
|
21
|
+
}
|
|
22
|
+
static queueFull() {
|
|
23
|
+
return new RateLimiterError(RateLimiterErrorCodes.QUEUE_FULL, 'Rate limiter queue is full');
|
|
24
|
+
}
|
|
25
|
+
static timeout() {
|
|
26
|
+
return new RateLimiterError(RateLimiterErrorCodes.TIMEOUT, 'Rate limiter queue timeout');
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Creates a rate limiter
|
|
31
|
+
*/
|
|
32
|
+
export function createRateLimiter(config) {
|
|
33
|
+
const cfg = { ...createDefaultRateLimiterConfig(), ...config };
|
|
34
|
+
// Token bucket state
|
|
35
|
+
let tokens = cfg.requestsPerMinute * cfg.burstMultiplier;
|
|
36
|
+
const maxTokens = cfg.requestsPerMinute * cfg.burstMultiplier;
|
|
37
|
+
const refillRate = cfg.requestsPerMinute / 60000; // tokens per ms
|
|
38
|
+
let lastRefillTime = Date.now();
|
|
39
|
+
// Token tracking for LLM APIs
|
|
40
|
+
let llmTokensUsed = 0;
|
|
41
|
+
let llmTokenWindowStart = Date.now();
|
|
42
|
+
// Statistics
|
|
43
|
+
let requestsAllowed = 0;
|
|
44
|
+
let requestsRejected = 0;
|
|
45
|
+
const windowStart = new Date().toISOString();
|
|
46
|
+
// Queue
|
|
47
|
+
const queue = [];
|
|
48
|
+
let processingQueue = false;
|
|
49
|
+
function refillTokens() {
|
|
50
|
+
const now = Date.now();
|
|
51
|
+
const elapsed = now - lastRefillTime;
|
|
52
|
+
const refill = elapsed * refillRate;
|
|
53
|
+
tokens = Math.min(maxTokens, tokens + refill);
|
|
54
|
+
lastRefillTime = now;
|
|
55
|
+
// Reset LLM token window if minute elapsed
|
|
56
|
+
if (cfg.tokensPerMinute && now - llmTokenWindowStart >= DEFAULT_TOKEN_WINDOW_MS) {
|
|
57
|
+
llmTokensUsed = 0;
|
|
58
|
+
llmTokenWindowStart = now;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
function calculateWaitTime(requestTokens) {
|
|
62
|
+
if (tokens >= requestTokens)
|
|
63
|
+
return 0;
|
|
64
|
+
const deficit = requestTokens - tokens;
|
|
65
|
+
return Math.ceil(deficit / refillRate);
|
|
66
|
+
}
|
|
67
|
+
function processQueue() {
|
|
68
|
+
if (processingQueue || queue.length === 0)
|
|
69
|
+
return;
|
|
70
|
+
processingQueue = true;
|
|
71
|
+
const processNext = () => {
|
|
72
|
+
if (queue.length === 0) {
|
|
73
|
+
processingQueue = false;
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
const request = queue[0];
|
|
77
|
+
if (!request) {
|
|
78
|
+
processingQueue = false;
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
const now = Date.now();
|
|
82
|
+
// Check timeout
|
|
83
|
+
if (now - request.enqueuedAt >= cfg.queueTimeoutMs) {
|
|
84
|
+
queue.shift();
|
|
85
|
+
request.resolve({
|
|
86
|
+
acquired: false,
|
|
87
|
+
reason: 'timeout',
|
|
88
|
+
});
|
|
89
|
+
setTimeout(processNext, 0);
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
refillTokens();
|
|
93
|
+
if (tokens >= request.tokens) {
|
|
94
|
+
queue.shift();
|
|
95
|
+
tokens -= request.tokens;
|
|
96
|
+
requestsAllowed++;
|
|
97
|
+
request.resolve({
|
|
98
|
+
acquired: true,
|
|
99
|
+
waitedMs: now - request.enqueuedAt,
|
|
100
|
+
});
|
|
101
|
+
setTimeout(processNext, 0);
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
// Wait for tokens
|
|
105
|
+
const waitTime = calculateWaitTime(request.tokens);
|
|
106
|
+
setTimeout(processNext, Math.min(waitTime, DEFAULT_CHECK_INTERVAL_MS));
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
processNext();
|
|
110
|
+
}
|
|
111
|
+
return {
|
|
112
|
+
async acquire(requestTokens = 1) {
|
|
113
|
+
refillTokens();
|
|
114
|
+
// Check LLM token limit
|
|
115
|
+
if (cfg.tokensPerMinute && llmTokensUsed >= cfg.tokensPerMinute) {
|
|
116
|
+
const retryAfterMs = DEFAULT_TOKEN_WINDOW_MS - (Date.now() - llmTokenWindowStart);
|
|
117
|
+
requestsRejected++;
|
|
118
|
+
return {
|
|
119
|
+
acquired: false,
|
|
120
|
+
reason: 'limit-exceeded',
|
|
121
|
+
retryAfterMs,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
// Try immediate acquisition
|
|
125
|
+
if (tokens >= requestTokens && queue.length === 0) {
|
|
126
|
+
tokens -= requestTokens;
|
|
127
|
+
requestsAllowed++;
|
|
128
|
+
return { acquired: true, waitedMs: 0 };
|
|
129
|
+
}
|
|
130
|
+
// Check queue capacity
|
|
131
|
+
if (queue.length >= cfg.maxQueueSize) {
|
|
132
|
+
requestsRejected++;
|
|
133
|
+
return { acquired: false, reason: 'queue-full' };
|
|
134
|
+
}
|
|
135
|
+
// Queue the request
|
|
136
|
+
return new Promise((resolve) => {
|
|
137
|
+
queue.push({
|
|
138
|
+
tokens: requestTokens,
|
|
139
|
+
resolve,
|
|
140
|
+
enqueuedAt: Date.now(),
|
|
141
|
+
});
|
|
142
|
+
processQueue();
|
|
143
|
+
});
|
|
144
|
+
},
|
|
145
|
+
tryAcquire(requestTokens = 1) {
|
|
146
|
+
refillTokens();
|
|
147
|
+
// Check LLM token limit
|
|
148
|
+
if (cfg.tokensPerMinute && llmTokensUsed >= cfg.tokensPerMinute) {
|
|
149
|
+
requestsRejected++;
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
152
|
+
if (tokens >= requestTokens && queue.length === 0) {
|
|
153
|
+
tokens -= requestTokens;
|
|
154
|
+
requestsAllowed++;
|
|
155
|
+
return true;
|
|
156
|
+
}
|
|
157
|
+
requestsRejected++;
|
|
158
|
+
return false;
|
|
159
|
+
},
|
|
160
|
+
getStats() {
|
|
161
|
+
refillTokens();
|
|
162
|
+
return {
|
|
163
|
+
requestsAllowed,
|
|
164
|
+
requestsRejected,
|
|
165
|
+
queueSize: queue.length,
|
|
166
|
+
tokensUsed: llmTokensUsed,
|
|
167
|
+
availableCapacity: tokens,
|
|
168
|
+
nextRefillMs: tokens >= maxTokens ? 0 : Math.ceil((maxTokens - tokens) / refillRate),
|
|
169
|
+
windowStart,
|
|
170
|
+
};
|
|
171
|
+
},
|
|
172
|
+
reset() {
|
|
173
|
+
tokens = maxTokens;
|
|
174
|
+
lastRefillTime = Date.now();
|
|
175
|
+
llmTokensUsed = 0;
|
|
176
|
+
llmTokenWindowStart = Date.now();
|
|
177
|
+
requestsAllowed = 0;
|
|
178
|
+
requestsRejected = 0;
|
|
179
|
+
// Clear queue
|
|
180
|
+
while (queue.length > 0) {
|
|
181
|
+
const request = queue.shift();
|
|
182
|
+
if (request) {
|
|
183
|
+
request.resolve({ acquired: false, reason: 'timeout' });
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
},
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
//# sourceMappingURL=rate-limiter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate-limiter.js","sourceRoot":"","sources":["../src/rate-limiter.ts"],"names":[],"mappings":"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"}
|