@push.rocks/smartregistry 2.2.3 → 2.3.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/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/cargo/classes.cargoregistry.d.ts +7 -1
- package/dist_ts/cargo/classes.cargoregistry.js +42 -4
- package/dist_ts/cargo/classes.cargoupstream.d.ts +44 -0
- package/dist_ts/cargo/classes.cargoupstream.js +129 -0
- package/dist_ts/cargo/index.d.ts +1 -0
- package/dist_ts/cargo/index.js +2 -1
- package/dist_ts/classes.smartregistry.js +8 -8
- package/dist_ts/composer/classes.composerregistry.d.ts +7 -1
- package/dist_ts/composer/classes.composerregistry.js +34 -3
- package/dist_ts/composer/classes.composerupstream.d.ts +40 -0
- package/dist_ts/composer/classes.composerupstream.js +159 -0
- package/dist_ts/composer/index.d.ts +1 -0
- package/dist_ts/composer/index.js +2 -1
- package/dist_ts/core/interfaces.core.d.ts +3 -0
- package/dist_ts/index.d.ts +1 -0
- package/dist_ts/index.js +3 -1
- package/dist_ts/maven/classes.mavenregistry.d.ts +12 -1
- package/dist_ts/maven/classes.mavenregistry.js +69 -4
- package/dist_ts/maven/classes.mavenupstream.d.ts +45 -0
- package/dist_ts/maven/classes.mavenupstream.js +153 -0
- package/dist_ts/maven/index.d.ts +1 -0
- package/dist_ts/maven/index.js +2 -1
- package/dist_ts/npm/classes.npmregistry.d.ts +3 -1
- package/dist_ts/npm/classes.npmregistry.js +55 -6
- package/dist_ts/npm/classes.npmupstream.d.ts +51 -0
- package/dist_ts/npm/classes.npmupstream.js +206 -0
- package/dist_ts/npm/index.d.ts +1 -0
- package/dist_ts/npm/index.js +2 -1
- package/dist_ts/oci/classes.ociregistry.d.ts +4 -1
- package/dist_ts/oci/classes.ociregistry.js +78 -17
- package/dist_ts/oci/classes.ociupstream.d.ts +62 -0
- package/dist_ts/oci/classes.ociupstream.js +206 -0
- package/dist_ts/oci/index.d.ts +1 -0
- package/dist_ts/oci/index.js +2 -1
- package/dist_ts/plugins.d.ts +4 -1
- package/dist_ts/plugins.js +6 -2
- package/dist_ts/pypi/classes.pypiregistry.d.ts +7 -1
- package/dist_ts/pypi/classes.pypiregistry.js +60 -4
- package/dist_ts/pypi/classes.pypiupstream.d.ts +48 -0
- package/dist_ts/pypi/classes.pypiupstream.js +165 -0
- package/dist_ts/pypi/index.d.ts +1 -0
- package/dist_ts/pypi/index.js +2 -1
- package/dist_ts/rubygems/classes.rubygemsregistry.d.ts +7 -1
- package/dist_ts/rubygems/classes.rubygemsregistry.js +35 -4
- package/dist_ts/rubygems/classes.rubygemsupstream.d.ts +47 -0
- package/dist_ts/rubygems/classes.rubygemsupstream.js +184 -0
- package/dist_ts/rubygems/index.d.ts +1 -0
- package/dist_ts/rubygems/index.js +2 -1
- package/dist_ts/upstream/classes.baseupstream.d.ts +112 -0
- package/dist_ts/upstream/classes.baseupstream.js +409 -0
- package/dist_ts/upstream/classes.circuitbreaker.d.ts +111 -0
- package/dist_ts/upstream/classes.circuitbreaker.js +192 -0
- package/dist_ts/upstream/classes.upstreamcache.d.ts +123 -0
- package/dist_ts/upstream/classes.upstreamcache.js +328 -0
- package/dist_ts/upstream/index.d.ts +6 -0
- package/dist_ts/upstream/index.js +7 -0
- package/dist_ts/upstream/interfaces.upstream.d.ts +169 -0
- package/dist_ts/upstream/interfaces.upstream.js +23 -0
- package/package.json +4 -2
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/cargo/classes.cargoregistry.ts +48 -3
- package/ts/cargo/classes.cargoupstream.ts +159 -0
- package/ts/cargo/index.ts +1 -0
- package/ts/classes.smartregistry.ts +49 -7
- package/ts/composer/classes.composerregistry.ts +39 -2
- package/ts/composer/classes.composerupstream.ts +200 -0
- package/ts/composer/index.ts +1 -0
- package/ts/core/interfaces.core.ts +3 -0
- package/ts/index.ts +3 -0
- package/ts/maven/classes.mavenregistry.ts +84 -3
- package/ts/maven/classes.mavenupstream.ts +220 -0
- package/ts/maven/index.ts +1 -0
- package/ts/npm/classes.npmregistry.ts +61 -5
- package/ts/npm/classes.npmupstream.ts +260 -0
- package/ts/npm/index.ts +1 -0
- package/ts/oci/classes.ociregistry.ts +89 -17
- package/ts/oci/classes.ociupstream.ts +263 -0
- package/ts/oci/index.ts +1 -0
- package/ts/plugins.ts +7 -1
- package/ts/pypi/classes.pypiregistry.ts +68 -3
- package/ts/pypi/classes.pypiupstream.ts +211 -0
- package/ts/pypi/index.ts +1 -0
- package/ts/rubygems/classes.rubygemsregistry.ts +40 -3
- package/ts/rubygems/classes.rubygemsupstream.ts +230 -0
- package/ts/rubygems/index.ts +1 -0
- package/ts/upstream/classes.baseupstream.ts +521 -0
- package/ts/upstream/classes.circuitbreaker.ts +238 -0
- package/ts/upstream/classes.upstreamcache.ts +423 -0
- package/ts/upstream/index.ts +11 -0
- package/ts/upstream/interfaces.upstream.ts +195 -0
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import { DEFAULT_RESILIENCE_CONFIG } from './interfaces.upstream.js';
|
|
2
|
+
/**
|
|
3
|
+
* Circuit breaker implementation for upstream resilience.
|
|
4
|
+
*
|
|
5
|
+
* States:
|
|
6
|
+
* - CLOSED: Normal operation, requests pass through
|
|
7
|
+
* - OPEN: Circuit is tripped, requests fail fast
|
|
8
|
+
* - HALF_OPEN: Testing if upstream has recovered
|
|
9
|
+
*
|
|
10
|
+
* Transitions:
|
|
11
|
+
* - CLOSED → OPEN: When failure count exceeds threshold
|
|
12
|
+
* - OPEN → HALF_OPEN: After reset timeout expires
|
|
13
|
+
* - HALF_OPEN → CLOSED: On successful request
|
|
14
|
+
* - HALF_OPEN → OPEN: On failed request
|
|
15
|
+
*/
|
|
16
|
+
export class CircuitBreaker {
|
|
17
|
+
/** Unique identifier for logging and metrics */
|
|
18
|
+
id;
|
|
19
|
+
/** Current circuit state */
|
|
20
|
+
state = 'CLOSED';
|
|
21
|
+
/** Count of consecutive failures */
|
|
22
|
+
failureCount = 0;
|
|
23
|
+
/** Timestamp when circuit was opened */
|
|
24
|
+
openedAt = 0;
|
|
25
|
+
/** Number of successful requests in half-open state */
|
|
26
|
+
halfOpenSuccesses = 0;
|
|
27
|
+
/** Configuration */
|
|
28
|
+
config;
|
|
29
|
+
/** Number of successes required to close circuit from half-open */
|
|
30
|
+
halfOpenThreshold = 2;
|
|
31
|
+
constructor(id, config) {
|
|
32
|
+
this.id = id;
|
|
33
|
+
this.config = { ...DEFAULT_RESILIENCE_CONFIG, ...config };
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Get current circuit state.
|
|
37
|
+
*/
|
|
38
|
+
getState() {
|
|
39
|
+
// Check if we should transition from OPEN to HALF_OPEN
|
|
40
|
+
if (this.state === 'OPEN') {
|
|
41
|
+
const elapsed = Date.now() - this.openedAt;
|
|
42
|
+
if (elapsed >= this.config.circuitBreakerResetMs) {
|
|
43
|
+
this.transitionTo('HALF_OPEN');
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return this.state;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Check if circuit allows requests.
|
|
50
|
+
* Returns true if requests should be allowed.
|
|
51
|
+
*/
|
|
52
|
+
canRequest() {
|
|
53
|
+
const currentState = this.getState();
|
|
54
|
+
return currentState !== 'OPEN';
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Record a successful request.
|
|
58
|
+
* May transition circuit from HALF_OPEN to CLOSED.
|
|
59
|
+
*/
|
|
60
|
+
recordSuccess() {
|
|
61
|
+
if (this.state === 'HALF_OPEN') {
|
|
62
|
+
this.halfOpenSuccesses++;
|
|
63
|
+
if (this.halfOpenSuccesses >= this.halfOpenThreshold) {
|
|
64
|
+
this.transitionTo('CLOSED');
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
else if (this.state === 'CLOSED') {
|
|
68
|
+
// Reset failure count on success
|
|
69
|
+
this.failureCount = 0;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Record a failed request.
|
|
74
|
+
* May transition circuit from CLOSED/HALF_OPEN to OPEN.
|
|
75
|
+
*/
|
|
76
|
+
recordFailure() {
|
|
77
|
+
if (this.state === 'HALF_OPEN') {
|
|
78
|
+
// Any failure in half-open immediately opens circuit
|
|
79
|
+
this.transitionTo('OPEN');
|
|
80
|
+
}
|
|
81
|
+
else if (this.state === 'CLOSED') {
|
|
82
|
+
this.failureCount++;
|
|
83
|
+
if (this.failureCount >= this.config.circuitBreakerThreshold) {
|
|
84
|
+
this.transitionTo('OPEN');
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Force circuit to open state.
|
|
90
|
+
* Useful for manual intervention or external health checks.
|
|
91
|
+
*/
|
|
92
|
+
forceOpen() {
|
|
93
|
+
this.transitionTo('OPEN');
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Force circuit to closed state.
|
|
97
|
+
* Useful for manual intervention after fixing upstream issues.
|
|
98
|
+
*/
|
|
99
|
+
forceClose() {
|
|
100
|
+
this.transitionTo('CLOSED');
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Reset circuit to initial state.
|
|
104
|
+
*/
|
|
105
|
+
reset() {
|
|
106
|
+
this.state = 'CLOSED';
|
|
107
|
+
this.failureCount = 0;
|
|
108
|
+
this.openedAt = 0;
|
|
109
|
+
this.halfOpenSuccesses = 0;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Get circuit metrics for monitoring.
|
|
113
|
+
*/
|
|
114
|
+
getMetrics() {
|
|
115
|
+
return {
|
|
116
|
+
id: this.id,
|
|
117
|
+
state: this.getState(),
|
|
118
|
+
failureCount: this.failureCount,
|
|
119
|
+
openedAt: this.openedAt > 0 ? new Date(this.openedAt) : null,
|
|
120
|
+
timeUntilHalfOpen: this.state === 'OPEN'
|
|
121
|
+
? Math.max(0, this.config.circuitBreakerResetMs - (Date.now() - this.openedAt))
|
|
122
|
+
: 0,
|
|
123
|
+
halfOpenSuccesses: this.halfOpenSuccesses,
|
|
124
|
+
threshold: this.config.circuitBreakerThreshold,
|
|
125
|
+
resetMs: this.config.circuitBreakerResetMs,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Transition to a new state with proper cleanup.
|
|
130
|
+
*/
|
|
131
|
+
transitionTo(newState) {
|
|
132
|
+
const previousState = this.state;
|
|
133
|
+
this.state = newState;
|
|
134
|
+
switch (newState) {
|
|
135
|
+
case 'OPEN':
|
|
136
|
+
this.openedAt = Date.now();
|
|
137
|
+
this.halfOpenSuccesses = 0;
|
|
138
|
+
break;
|
|
139
|
+
case 'HALF_OPEN':
|
|
140
|
+
this.halfOpenSuccesses = 0;
|
|
141
|
+
break;
|
|
142
|
+
case 'CLOSED':
|
|
143
|
+
this.failureCount = 0;
|
|
144
|
+
this.openedAt = 0;
|
|
145
|
+
this.halfOpenSuccesses = 0;
|
|
146
|
+
break;
|
|
147
|
+
}
|
|
148
|
+
// Log state transition (useful for debugging and monitoring)
|
|
149
|
+
// In production, this would emit events or metrics
|
|
150
|
+
if (previousState !== newState) {
|
|
151
|
+
// State changed - could emit event here
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Execute a function with circuit breaker protection.
|
|
157
|
+
*
|
|
158
|
+
* @param breaker The circuit breaker to use
|
|
159
|
+
* @param fn The async function to execute
|
|
160
|
+
* @param fallback Optional fallback function when circuit is open
|
|
161
|
+
* @returns The result of fn or fallback
|
|
162
|
+
* @throws CircuitOpenError if circuit is open and no fallback provided
|
|
163
|
+
*/
|
|
164
|
+
export async function withCircuitBreaker(breaker, fn, fallback) {
|
|
165
|
+
if (!breaker.canRequest()) {
|
|
166
|
+
if (fallback) {
|
|
167
|
+
return fallback();
|
|
168
|
+
}
|
|
169
|
+
throw new CircuitOpenError(breaker.id);
|
|
170
|
+
}
|
|
171
|
+
try {
|
|
172
|
+
const result = await fn();
|
|
173
|
+
breaker.recordSuccess();
|
|
174
|
+
return result;
|
|
175
|
+
}
|
|
176
|
+
catch (error) {
|
|
177
|
+
breaker.recordFailure();
|
|
178
|
+
throw error;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Error thrown when circuit is open and no fallback is provided.
|
|
183
|
+
*/
|
|
184
|
+
export class CircuitOpenError extends Error {
|
|
185
|
+
circuitId;
|
|
186
|
+
constructor(circuitId) {
|
|
187
|
+
super(`Circuit breaker '${circuitId}' is open`);
|
|
188
|
+
this.name = 'CircuitOpenError';
|
|
189
|
+
this.circuitId = circuitId;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5jaXJjdWl0YnJlYWtlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3RzL3Vwc3RyZWFtL2NsYXNzZXMuY2lyY3VpdGJyZWFrZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQ0EsT0FBTyxFQUFFLHlCQUF5QixFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFFckU7Ozs7Ozs7Ozs7Ozs7R0FhRztBQUNILE1BQU0sT0FBTyxjQUFjO0lBQ3pCLGdEQUFnRDtJQUNoQyxFQUFFLENBQVM7SUFFM0IsNEJBQTRCO0lBQ3BCLEtBQUssR0FBa0IsUUFBUSxDQUFDO0lBRXhDLG9DQUFvQztJQUM1QixZQUFZLEdBQVcsQ0FBQyxDQUFDO0lBRWpDLHdDQUF3QztJQUNoQyxRQUFRLEdBQVcsQ0FBQyxDQUFDO0lBRTdCLHVEQUF1RDtJQUMvQyxpQkFBaUIsR0FBVyxDQUFDLENBQUM7SUFFdEMsb0JBQW9CO0lBQ0gsTUFBTSxDQUE0QjtJQUVuRCxtRUFBbUU7SUFDbEQsaUJBQWlCLEdBQVcsQ0FBQyxDQUFDO0lBRS9DLFlBQVksRUFBVSxFQUFFLE1BQTJDO1FBQ2pFLElBQUksQ0FBQyxFQUFFLEdBQUcsRUFBRSxDQUFDO1FBQ2IsSUFBSSxDQUFDLE1BQU0sR0FBRyxFQUFFLEdBQUcseUJBQXlCLEVBQUUsR0FBRyxNQUFNLEVBQUUsQ0FBQztJQUM1RCxDQUFDO0lBRUQ7O09BRUc7SUFDSSxRQUFRO1FBQ2IsdURBQXVEO1FBQ3ZELElBQUksSUFBSSxDQUFDLEtBQUssS0FBSyxNQUFNLEVBQUUsQ0FBQztZQUMxQixNQUFNLE9BQU8sR0FBRyxJQUFJLENBQUMsR0FBRyxFQUFFLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQztZQUMzQyxJQUFJLE9BQU8sSUFBSSxJQUFJLENBQUMsTUFBTSxDQUFDLHFCQUFxQixFQUFFLENBQUM7Z0JBQ2pELElBQUksQ0FBQyxZQUFZLENBQUMsV0FBVyxDQUFDLENBQUM7WUFDakMsQ0FBQztRQUNILENBQUM7UUFD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
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import type { ICacheEntry, IUpstreamCacheConfig, IUpstreamFetchContext } from './interfaces.upstream.js';
|
|
2
|
+
/**
|
|
3
|
+
* In-memory cache for upstream responses.
|
|
4
|
+
*
|
|
5
|
+
* Features:
|
|
6
|
+
* - TTL-based expiration
|
|
7
|
+
* - Stale-while-revalidate support
|
|
8
|
+
* - Negative caching (404s)
|
|
9
|
+
* - Content-type aware caching
|
|
10
|
+
* - ETag support for conditional requests
|
|
11
|
+
*
|
|
12
|
+
* Note: This is an in-memory implementation. For production with persistence,
|
|
13
|
+
* extend this class to use RegistryStorage for S3-backed caching.
|
|
14
|
+
*/
|
|
15
|
+
export declare class UpstreamCache {
|
|
16
|
+
/** Cache storage */
|
|
17
|
+
private readonly cache;
|
|
18
|
+
/** Configuration */
|
|
19
|
+
private readonly config;
|
|
20
|
+
/** Maximum cache entries (prevents memory bloat) */
|
|
21
|
+
private readonly maxEntries;
|
|
22
|
+
/** Cleanup interval handle */
|
|
23
|
+
private cleanupInterval;
|
|
24
|
+
constructor(config?: Partial<IUpstreamCacheConfig>, maxEntries?: number);
|
|
25
|
+
/**
|
|
26
|
+
* Check if caching is enabled.
|
|
27
|
+
*/
|
|
28
|
+
isEnabled(): boolean;
|
|
29
|
+
/**
|
|
30
|
+
* Get cached entry for a request context.
|
|
31
|
+
* Returns null if not found or expired (unless stale-while-revalidate).
|
|
32
|
+
*/
|
|
33
|
+
get(context: IUpstreamFetchContext): ICacheEntry | null;
|
|
34
|
+
/**
|
|
35
|
+
* Store a response in the cache.
|
|
36
|
+
*/
|
|
37
|
+
set(context: IUpstreamFetchContext, data: Buffer, contentType: string, headers: Record<string, string>, upstreamId: string, options?: ICacheSetOptions): void;
|
|
38
|
+
/**
|
|
39
|
+
* Store a negative cache entry (404 response).
|
|
40
|
+
*/
|
|
41
|
+
setNegative(context: IUpstreamFetchContext, upstreamId: string): void;
|
|
42
|
+
/**
|
|
43
|
+
* Check if there's a negative cache entry for this context.
|
|
44
|
+
*/
|
|
45
|
+
hasNegative(context: IUpstreamFetchContext): boolean;
|
|
46
|
+
/**
|
|
47
|
+
* Invalidate a specific cache entry.
|
|
48
|
+
*/
|
|
49
|
+
invalidate(context: IUpstreamFetchContext): boolean;
|
|
50
|
+
/**
|
|
51
|
+
* Invalidate all entries matching a pattern.
|
|
52
|
+
* Useful for invalidating all versions of a package.
|
|
53
|
+
*/
|
|
54
|
+
invalidatePattern(pattern: RegExp): number;
|
|
55
|
+
/**
|
|
56
|
+
* Invalidate all entries from a specific upstream.
|
|
57
|
+
*/
|
|
58
|
+
invalidateUpstream(upstreamId: string): number;
|
|
59
|
+
/**
|
|
60
|
+
* Clear all cache entries.
|
|
61
|
+
*/
|
|
62
|
+
clear(): void;
|
|
63
|
+
/**
|
|
64
|
+
* Get cache statistics.
|
|
65
|
+
*/
|
|
66
|
+
getStats(): ICacheStats;
|
|
67
|
+
/**
|
|
68
|
+
* Stop the cache and cleanup.
|
|
69
|
+
*/
|
|
70
|
+
stop(): void;
|
|
71
|
+
/**
|
|
72
|
+
* Build a unique cache key for a request context.
|
|
73
|
+
*/
|
|
74
|
+
private buildCacheKey;
|
|
75
|
+
/**
|
|
76
|
+
* Determine TTL based on content characteristics.
|
|
77
|
+
*/
|
|
78
|
+
private determineTtl;
|
|
79
|
+
/**
|
|
80
|
+
* Check if content is immutable (content-addressable).
|
|
81
|
+
*/
|
|
82
|
+
private isImmutableContent;
|
|
83
|
+
/**
|
|
84
|
+
* Evict oldest entries to make room for new ones.
|
|
85
|
+
*/
|
|
86
|
+
private evictOldest;
|
|
87
|
+
/**
|
|
88
|
+
* Start periodic cleanup of expired entries.
|
|
89
|
+
*/
|
|
90
|
+
private startCleanup;
|
|
91
|
+
/**
|
|
92
|
+
* Remove all expired entries.
|
|
93
|
+
*/
|
|
94
|
+
private cleanup;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Options for cache set operation.
|
|
98
|
+
*/
|
|
99
|
+
export interface ICacheSetOptions {
|
|
100
|
+
/** Override TTL in seconds */
|
|
101
|
+
ttlSeconds?: number;
|
|
102
|
+
/** ETag for conditional requests */
|
|
103
|
+
etag?: string;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Cache statistics.
|
|
107
|
+
*/
|
|
108
|
+
export interface ICacheStats {
|
|
109
|
+
/** Total number of cached entries */
|
|
110
|
+
totalEntries: number;
|
|
111
|
+
/** Number of fresh (non-expired) entries */
|
|
112
|
+
freshEntries: number;
|
|
113
|
+
/** Number of stale entries (expired but still usable) */
|
|
114
|
+
staleEntries: number;
|
|
115
|
+
/** Number of negative cache entries */
|
|
116
|
+
negativeEntries: number;
|
|
117
|
+
/** Total size of cached data in bytes */
|
|
118
|
+
totalSizeBytes: number;
|
|
119
|
+
/** Maximum allowed entries */
|
|
120
|
+
maxEntries: number;
|
|
121
|
+
/** Whether caching is enabled */
|
|
122
|
+
enabled: boolean;
|
|
123
|
+
}
|
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
import { DEFAULT_CACHE_CONFIG } from './interfaces.upstream.js';
|
|
2
|
+
/**
|
|
3
|
+
* In-memory cache for upstream responses.
|
|
4
|
+
*
|
|
5
|
+
* Features:
|
|
6
|
+
* - TTL-based expiration
|
|
7
|
+
* - Stale-while-revalidate support
|
|
8
|
+
* - Negative caching (404s)
|
|
9
|
+
* - Content-type aware caching
|
|
10
|
+
* - ETag support for conditional requests
|
|
11
|
+
*
|
|
12
|
+
* Note: This is an in-memory implementation. For production with persistence,
|
|
13
|
+
* extend this class to use RegistryStorage for S3-backed caching.
|
|
14
|
+
*/
|
|
15
|
+
export class UpstreamCache {
|
|
16
|
+
/** Cache storage */
|
|
17
|
+
cache = new Map();
|
|
18
|
+
/** Configuration */
|
|
19
|
+
config;
|
|
20
|
+
/** Maximum cache entries (prevents memory bloat) */
|
|
21
|
+
maxEntries;
|
|
22
|
+
/** Cleanup interval handle */
|
|
23
|
+
cleanupInterval = null;
|
|
24
|
+
constructor(config, maxEntries = 10000) {
|
|
25
|
+
this.config = { ...DEFAULT_CACHE_CONFIG, ...config };
|
|
26
|
+
this.maxEntries = maxEntries;
|
|
27
|
+
// Start periodic cleanup if caching is enabled
|
|
28
|
+
if (this.config.enabled) {
|
|
29
|
+
this.startCleanup();
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Check if caching is enabled.
|
|
34
|
+
*/
|
|
35
|
+
isEnabled() {
|
|
36
|
+
return this.config.enabled;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Get cached entry for a request context.
|
|
40
|
+
* Returns null if not found or expired (unless stale-while-revalidate).
|
|
41
|
+
*/
|
|
42
|
+
get(context) {
|
|
43
|
+
if (!this.config.enabled) {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
const key = this.buildCacheKey(context);
|
|
47
|
+
const entry = this.cache.get(key);
|
|
48
|
+
if (!entry) {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
const now = new Date();
|
|
52
|
+
// Check if entry is expired
|
|
53
|
+
if (entry.expiresAt && entry.expiresAt < now) {
|
|
54
|
+
// Check if we can serve stale content
|
|
55
|
+
if (this.config.staleWhileRevalidate && !entry.stale) {
|
|
56
|
+
const staleAge = (now.getTime() - entry.expiresAt.getTime()) / 1000;
|
|
57
|
+
if (staleAge <= this.config.staleMaxAgeSeconds) {
|
|
58
|
+
// Mark as stale and return
|
|
59
|
+
entry.stale = true;
|
|
60
|
+
return entry;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
// Entry is too old, remove it
|
|
64
|
+
this.cache.delete(key);
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
return entry;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Store a response in the cache.
|
|
71
|
+
*/
|
|
72
|
+
set(context, data, contentType, headers, upstreamId, options) {
|
|
73
|
+
if (!this.config.enabled) {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
// Enforce max entries limit
|
|
77
|
+
if (this.cache.size >= this.maxEntries) {
|
|
78
|
+
this.evictOldest();
|
|
79
|
+
}
|
|
80
|
+
const key = this.buildCacheKey(context);
|
|
81
|
+
const now = new Date();
|
|
82
|
+
// Determine TTL based on content type
|
|
83
|
+
const ttlSeconds = options?.ttlSeconds ?? this.determineTtl(context, contentType, headers);
|
|
84
|
+
const entry = {
|
|
85
|
+
data,
|
|
86
|
+
contentType,
|
|
87
|
+
headers,
|
|
88
|
+
cachedAt: now,
|
|
89
|
+
expiresAt: ttlSeconds > 0 ? new Date(now.getTime() + ttlSeconds * 1000) : undefined,
|
|
90
|
+
etag: headers['etag'] || options?.etag,
|
|
91
|
+
upstreamId,
|
|
92
|
+
stale: false,
|
|
93
|
+
};
|
|
94
|
+
this.cache.set(key, entry);
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Store a negative cache entry (404 response).
|
|
98
|
+
*/
|
|
99
|
+
setNegative(context, upstreamId) {
|
|
100
|
+
if (!this.config.enabled || this.config.negativeCacheTtlSeconds <= 0) {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
const key = this.buildCacheKey(context);
|
|
104
|
+
const now = new Date();
|
|
105
|
+
const entry = {
|
|
106
|
+
data: Buffer.from(''),
|
|
107
|
+
contentType: 'application/octet-stream',
|
|
108
|
+
headers: {},
|
|
109
|
+
cachedAt: now,
|
|
110
|
+
expiresAt: new Date(now.getTime() + this.config.negativeCacheTtlSeconds * 1000),
|
|
111
|
+
upstreamId,
|
|
112
|
+
stale: false,
|
|
113
|
+
};
|
|
114
|
+
this.cache.set(key, entry);
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Check if there's a negative cache entry for this context.
|
|
118
|
+
*/
|
|
119
|
+
hasNegative(context) {
|
|
120
|
+
const entry = this.get(context);
|
|
121
|
+
return entry !== null && entry.data.length === 0;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Invalidate a specific cache entry.
|
|
125
|
+
*/
|
|
126
|
+
invalidate(context) {
|
|
127
|
+
const key = this.buildCacheKey(context);
|
|
128
|
+
return this.cache.delete(key);
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Invalidate all entries matching a pattern.
|
|
132
|
+
* Useful for invalidating all versions of a package.
|
|
133
|
+
*/
|
|
134
|
+
invalidatePattern(pattern) {
|
|
135
|
+
let count = 0;
|
|
136
|
+
for (const key of this.cache.keys()) {
|
|
137
|
+
if (pattern.test(key)) {
|
|
138
|
+
this.cache.delete(key);
|
|
139
|
+
count++;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return count;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Invalidate all entries from a specific upstream.
|
|
146
|
+
*/
|
|
147
|
+
invalidateUpstream(upstreamId) {
|
|
148
|
+
let count = 0;
|
|
149
|
+
for (const [key, entry] of this.cache.entries()) {
|
|
150
|
+
if (entry.upstreamId === upstreamId) {
|
|
151
|
+
this.cache.delete(key);
|
|
152
|
+
count++;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return count;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Clear all cache entries.
|
|
159
|
+
*/
|
|
160
|
+
clear() {
|
|
161
|
+
this.cache.clear();
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Get cache statistics.
|
|
165
|
+
*/
|
|
166
|
+
getStats() {
|
|
167
|
+
let freshCount = 0;
|
|
168
|
+
let staleCount = 0;
|
|
169
|
+
let negativeCount = 0;
|
|
170
|
+
let totalSize = 0;
|
|
171
|
+
const now = new Date();
|
|
172
|
+
for (const entry of this.cache.values()) {
|
|
173
|
+
totalSize += entry.data.length;
|
|
174
|
+
if (entry.data.length === 0) {
|
|
175
|
+
negativeCount++;
|
|
176
|
+
}
|
|
177
|
+
else if (entry.stale || (entry.expiresAt && entry.expiresAt < now)) {
|
|
178
|
+
staleCount++;
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
freshCount++;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return {
|
|
185
|
+
totalEntries: this.cache.size,
|
|
186
|
+
freshEntries: freshCount,
|
|
187
|
+
staleEntries: staleCount,
|
|
188
|
+
negativeEntries: negativeCount,
|
|
189
|
+
totalSizeBytes: totalSize,
|
|
190
|
+
maxEntries: this.maxEntries,
|
|
191
|
+
enabled: this.config.enabled,
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Stop the cache and cleanup.
|
|
196
|
+
*/
|
|
197
|
+
stop() {
|
|
198
|
+
if (this.cleanupInterval) {
|
|
199
|
+
clearInterval(this.cleanupInterval);
|
|
200
|
+
this.cleanupInterval = null;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Build a unique cache key for a request context.
|
|
205
|
+
*/
|
|
206
|
+
buildCacheKey(context) {
|
|
207
|
+
// Include method, protocol, path, and sorted query params
|
|
208
|
+
const queryString = Object.keys(context.query)
|
|
209
|
+
.sort()
|
|
210
|
+
.map(k => `${k}=${context.query[k]}`)
|
|
211
|
+
.join('&');
|
|
212
|
+
return `${context.protocol}:${context.method}:${context.path}${queryString ? '?' + queryString : ''}`;
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Determine TTL based on content characteristics.
|
|
216
|
+
*/
|
|
217
|
+
determineTtl(context, contentType, headers) {
|
|
218
|
+
// Check for Cache-Control header
|
|
219
|
+
const cacheControl = headers['cache-control'];
|
|
220
|
+
if (cacheControl) {
|
|
221
|
+
const maxAgeMatch = cacheControl.match(/max-age=(\d+)/);
|
|
222
|
+
if (maxAgeMatch) {
|
|
223
|
+
return parseInt(maxAgeMatch[1], 10);
|
|
224
|
+
}
|
|
225
|
+
if (cacheControl.includes('no-store') || cacheControl.includes('no-cache')) {
|
|
226
|
+
return 0;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
// Check if content is immutable (content-addressable)
|
|
230
|
+
if (this.isImmutableContent(context, contentType)) {
|
|
231
|
+
return this.config.immutableTtlSeconds;
|
|
232
|
+
}
|
|
233
|
+
// Default TTL for mutable content
|
|
234
|
+
return this.config.defaultTtlSeconds;
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Check if content is immutable (content-addressable).
|
|
238
|
+
*/
|
|
239
|
+
isImmutableContent(context, contentType) {
|
|
240
|
+
// OCI blobs with digest are immutable
|
|
241
|
+
if (context.protocol === 'oci' && context.resourceType === 'blob') {
|
|
242
|
+
return true;
|
|
243
|
+
}
|
|
244
|
+
// NPM tarballs are immutable (versioned)
|
|
245
|
+
if (context.protocol === 'npm' && context.resourceType === 'tarball') {
|
|
246
|
+
return true;
|
|
247
|
+
}
|
|
248
|
+
// Maven artifacts with version are immutable
|
|
249
|
+
if (context.protocol === 'maven' && context.resourceType === 'artifact') {
|
|
250
|
+
return true;
|
|
251
|
+
}
|
|
252
|
+
// Cargo crate files are immutable
|
|
253
|
+
if (context.protocol === 'cargo' && context.resourceType === 'crate') {
|
|
254
|
+
return true;
|
|
255
|
+
}
|
|
256
|
+
// Composer dist files are immutable
|
|
257
|
+
if (context.protocol === 'composer' && context.resourceType === 'dist') {
|
|
258
|
+
return true;
|
|
259
|
+
}
|
|
260
|
+
// PyPI package files are immutable
|
|
261
|
+
if (context.protocol === 'pypi' && context.resourceType === 'package') {
|
|
262
|
+
return true;
|
|
263
|
+
}
|
|
264
|
+
// RubyGems .gem files are immutable
|
|
265
|
+
if (context.protocol === 'rubygems' && context.resourceType === 'gem') {
|
|
266
|
+
return true;
|
|
267
|
+
}
|
|
268
|
+
return false;
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* Evict oldest entries to make room for new ones.
|
|
272
|
+
*/
|
|
273
|
+
evictOldest() {
|
|
274
|
+
// Evict 10% of max entries
|
|
275
|
+
const evictCount = Math.ceil(this.maxEntries * 0.1);
|
|
276
|
+
let evicted = 0;
|
|
277
|
+
// First, try to evict stale entries
|
|
278
|
+
const now = new Date();
|
|
279
|
+
for (const [key, entry] of this.cache.entries()) {
|
|
280
|
+
if (evicted >= evictCount)
|
|
281
|
+
break;
|
|
282
|
+
if (entry.stale || (entry.expiresAt && entry.expiresAt < now)) {
|
|
283
|
+
this.cache.delete(key);
|
|
284
|
+
evicted++;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
// If not enough evicted, evict oldest by cachedAt
|
|
288
|
+
if (evicted < evictCount) {
|
|
289
|
+
const entries = Array.from(this.cache.entries())
|
|
290
|
+
.sort((a, b) => a[1].cachedAt.getTime() - b[1].cachedAt.getTime());
|
|
291
|
+
for (const [key] of entries) {
|
|
292
|
+
if (evicted >= evictCount)
|
|
293
|
+
break;
|
|
294
|
+
this.cache.delete(key);
|
|
295
|
+
evicted++;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
/**
|
|
300
|
+
* Start periodic cleanup of expired entries.
|
|
301
|
+
*/
|
|
302
|
+
startCleanup() {
|
|
303
|
+
// Run cleanup every minute
|
|
304
|
+
this.cleanupInterval = setInterval(() => {
|
|
305
|
+
this.cleanup();
|
|
306
|
+
}, 60000);
|
|
307
|
+
// Don't keep the process alive just for cleanup
|
|
308
|
+
if (this.cleanupInterval.unref) {
|
|
309
|
+
this.cleanupInterval.unref();
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* Remove all expired entries.
|
|
314
|
+
*/
|
|
315
|
+
cleanup() {
|
|
316
|
+
const now = new Date();
|
|
317
|
+
const staleDeadline = new Date(now.getTime() - this.config.staleMaxAgeSeconds * 1000);
|
|
318
|
+
for (const [key, entry] of this.cache.entries()) {
|
|
319
|
+
if (entry.expiresAt) {
|
|
320
|
+
// Remove if past stale deadline
|
|
321
|
+
if (entry.expiresAt < staleDeadline) {
|
|
322
|
+
this.cache.delete(key);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy51cHN0cmVhbWNhY2hlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vdHMvdXBzdHJlYW0vY2xhc3Nlcy51cHN0cmVhbWNhY2hlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUtBLE9BQU8sRUFBRSxvQkFBb0IsRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBRWhFOzs7Ozs7Ozs7Ozs7R0FZRztBQUNILE1BQU0sT0FBTyxhQUFhO0lBQ3hCLG9CQUFvQjtJQUNILEtBQUssR0FBNkIsSUFBSSxHQUFHLEVBQUUsQ0FBQztJQUU3RCxvQkFBb0I7SUFDSCxNQUFNLENBQXVCO0lBRTlDLG9EQUFvRDtJQUNuQyxVQUFVLENBQVM7SUFFcEMsOEJBQThCO0lBQ3RCLGVBQWUsR0FBMEMsSUFBSSxDQUFDO0lBRXRFLFlBQVksTUFBc0MsRUFBRSxhQUFxQixLQUFLO1FBQzVFLElBQUksQ0FBQyxNQUFNLEdBQUcsRUFBRSxHQUFHLG9CQUFvQixFQUFFLEdBQUcsTUFBTSxFQUFFLENBQUM7UUFDckQsSUFBSSxDQUFDLFVBQVUsR0FBRyxVQUFVLENBQUM7UUFFN0IsK0NBQStDO1FBQy9DLElBQUksSUFBSSxDQUFDLE1BQU0sQ0FBQyxPQUFPLEVBQUUsQ0FBQztZQUN4QixJQUFJLENBQUMsWUFBWSxFQUFFLENBQUM7UUFDdEIsQ0FBQztJQUNILENBQUM7SUFFRDs7T0FFRztJQUNJLFNBQVM7UUFDZCxPQUFPLElBQUksQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDO0lBQzdCLENBQUM7SUFFRDs7O09BR0c7SUFDSSxHQUFHLENBQUMsT0FBOEI7UUFDdkMsSUFBSSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsT0FBTyxFQUFFLENBQUM7WUFDekIsT0FBTyxJQUFJLENBQUM7UUFDZCxDQUFDO1FBRUQsTUFBTSxHQUFHLEdBQUcsSUFBSSxDQUFDLGFBQWEsQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUN4QyxNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsS0FB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
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export * from './interfaces.upstream.js';
|
|
2
|
+
export { CircuitBreaker, CircuitOpenError, withCircuitBreaker } from './classes.circuitbreaker.js';
|
|
3
|
+
export type { ICircuitBreakerMetrics } from './classes.circuitbreaker.js';
|
|
4
|
+
export { UpstreamCache } from './classes.upstreamcache.js';
|
|
5
|
+
export type { ICacheSetOptions, ICacheStats } from './classes.upstreamcache.js';
|
|
6
|
+
export { BaseUpstream } from './classes.baseupstream.js';
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
// Interfaces and types
|
|
2
|
+
export * from './interfaces.upstream.js';
|
|
3
|
+
// Classes
|
|
4
|
+
export { CircuitBreaker, CircuitOpenError, withCircuitBreaker } from './classes.circuitbreaker.js';
|
|
5
|
+
export { UpstreamCache } from './classes.upstreamcache.js';
|
|
6
|
+
export { BaseUpstream } from './classes.baseupstream.js';
|
|
7
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi90cy91cHN0cmVhbS9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSx1QkFBdUI7QUFDdkIsY0FBYywwQkFBMEIsQ0FBQztBQUV6QyxVQUFVO0FBQ1YsT0FBTyxFQUFFLGNBQWMsRUFBRSxnQkFBZ0IsRUFBRSxrQkFBa0IsRUFBRSxNQUFNLDZCQUE2QixDQUFDO0FBR25HLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUczRCxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sMkJBQTJCLENBQUMifQ==
|