@push.rocks/smartregistry 2.2.3 → 2.4.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.d.ts +33 -2
- package/dist_ts/classes.smartregistry.js +45 -12
- 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/classes.authmanager.d.ts +30 -80
- package/dist_ts/core/classes.authmanager.js +63 -337
- package/dist_ts/core/classes.defaultauthprovider.d.ts +78 -0
- package/dist_ts/core/classes.defaultauthprovider.js +311 -0
- package/dist_ts/core/classes.registrystorage.d.ts +70 -4
- package/dist_ts/core/classes.registrystorage.js +165 -5
- package/dist_ts/core/index.d.ts +3 -0
- package/dist_ts/core/index.js +7 -2
- package/dist_ts/core/interfaces.auth.d.ts +83 -0
- package/dist_ts/core/interfaces.auth.js +2 -0
- package/dist_ts/core/interfaces.core.d.ts +38 -0
- package/dist_ts/core/interfaces.storage.d.ts +120 -0
- package/dist_ts/core/interfaces.storage.js +2 -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 +411 -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 +170 -0
- package/dist_ts/upstream/classes.upstreamcache.js +485 -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 +88 -11
- 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/classes.authmanager.ts +74 -412
- package/ts/core/classes.defaultauthprovider.ts +393 -0
- package/ts/core/classes.registrystorage.ts +199 -5
- package/ts/core/index.ts +8 -1
- package/ts/core/interfaces.auth.ts +91 -0
- package/ts/core/interfaces.core.ts +42 -0
- package/ts/core/interfaces.storage.ts +130 -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 +526 -0
- package/ts/upstream/classes.circuitbreaker.ts +238 -0
- package/ts/upstream/classes.upstreamcache.ts +626 -0
- package/ts/upstream/index.ts +11 -0
- package/ts/upstream/interfaces.upstream.ts +195 -0
|
@@ -3,6 +3,7 @@ import { BaseRegistry } from '../core/classes.baseregistry.js';
|
|
|
3
3
|
import { RegistryStorage } from '../core/classes.registrystorage.js';
|
|
4
4
|
import { AuthManager } from '../core/classes.authmanager.js';
|
|
5
5
|
import type { IRequestContext, IResponse, IAuthToken } from '../core/interfaces.core.js';
|
|
6
|
+
import type { IProtocolUpstreamConfig } from '../upstream/interfaces.upstream.js';
|
|
6
7
|
import type {
|
|
7
8
|
IRubyGemsMetadata,
|
|
8
9
|
IRubyGemsVersionMetadata,
|
|
@@ -12,6 +13,7 @@ import type {
|
|
|
12
13
|
ICompactIndexInfoEntry,
|
|
13
14
|
} from './interfaces.rubygems.js';
|
|
14
15
|
import * as helpers from './helpers.rubygems.js';
|
|
16
|
+
import { RubygemsUpstream } from './classes.rubygemsupstream.js';
|
|
15
17
|
|
|
16
18
|
/**
|
|
17
19
|
* RubyGems registry implementation
|
|
@@ -23,12 +25,14 @@ export class RubyGemsRegistry extends BaseRegistry {
|
|
|
23
25
|
private basePath: string = '/rubygems';
|
|
24
26
|
private registryUrl: string;
|
|
25
27
|
private logger: Smartlog;
|
|
28
|
+
private upstream: RubygemsUpstream | null = null;
|
|
26
29
|
|
|
27
30
|
constructor(
|
|
28
31
|
storage: RegistryStorage,
|
|
29
32
|
authManager: AuthManager,
|
|
30
33
|
basePath: string = '/rubygems',
|
|
31
|
-
registryUrl: string = 'http://localhost:5000/rubygems'
|
|
34
|
+
registryUrl: string = 'http://localhost:5000/rubygems',
|
|
35
|
+
upstreamConfig?: IProtocolUpstreamConfig
|
|
32
36
|
) {
|
|
33
37
|
super();
|
|
34
38
|
this.storage = storage;
|
|
@@ -48,6 +52,20 @@ export class RubyGemsRegistry extends BaseRegistry {
|
|
|
48
52
|
}
|
|
49
53
|
});
|
|
50
54
|
this.logger.enableConsole();
|
|
55
|
+
|
|
56
|
+
// Initialize upstream if configured
|
|
57
|
+
if (upstreamConfig?.enabled) {
|
|
58
|
+
this.upstream = new RubygemsUpstream(upstreamConfig, this.logger);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Clean up resources (timers, connections, etc.)
|
|
64
|
+
*/
|
|
65
|
+
public destroy(): void {
|
|
66
|
+
if (this.upstream) {
|
|
67
|
+
this.upstream.stop();
|
|
68
|
+
}
|
|
51
69
|
}
|
|
52
70
|
|
|
53
71
|
public async init(): Promise<void> {
|
|
@@ -215,7 +233,17 @@ export class RubyGemsRegistry extends BaseRegistry {
|
|
|
215
233
|
* Handle /info/{gem} endpoint (Compact Index)
|
|
216
234
|
*/
|
|
217
235
|
private async handleInfoFile(gemName: string): Promise<IResponse> {
|
|
218
|
-
|
|
236
|
+
let content = await this.storage.getRubyGemsInfo(gemName);
|
|
237
|
+
|
|
238
|
+
// Try upstream if not found locally
|
|
239
|
+
if (!content && this.upstream) {
|
|
240
|
+
const upstreamInfo = await this.upstream.fetchInfo(gemName);
|
|
241
|
+
if (upstreamInfo) {
|
|
242
|
+
// Cache locally
|
|
243
|
+
await this.storage.putRubyGemsInfo(gemName, upstreamInfo);
|
|
244
|
+
content = upstreamInfo;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
219
247
|
|
|
220
248
|
if (!content) {
|
|
221
249
|
return {
|
|
@@ -245,12 +273,21 @@ export class RubyGemsRegistry extends BaseRegistry {
|
|
|
245
273
|
return this.errorResponse(400, 'Invalid gem filename');
|
|
246
274
|
}
|
|
247
275
|
|
|
248
|
-
|
|
276
|
+
let gemData = await this.storage.getRubyGemsGem(
|
|
249
277
|
parsed.name,
|
|
250
278
|
parsed.version,
|
|
251
279
|
parsed.platform
|
|
252
280
|
);
|
|
253
281
|
|
|
282
|
+
// Try upstream if not found locally
|
|
283
|
+
if (!gemData && this.upstream) {
|
|
284
|
+
gemData = await this.upstream.fetchGem(parsed.name, parsed.version);
|
|
285
|
+
if (gemData) {
|
|
286
|
+
// Cache locally
|
|
287
|
+
await this.storage.putRubyGemsGem(parsed.name, parsed.version, gemData, parsed.platform);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
254
291
|
if (!gemData) {
|
|
255
292
|
return this.errorResponse(404, 'Gem not found');
|
|
256
293
|
}
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
import * as plugins from '../plugins.js';
|
|
2
|
+
import { BaseUpstream } from '../upstream/classes.baseupstream.js';
|
|
3
|
+
import type {
|
|
4
|
+
IProtocolUpstreamConfig,
|
|
5
|
+
IUpstreamFetchContext,
|
|
6
|
+
IUpstreamRegistryConfig,
|
|
7
|
+
} from '../upstream/interfaces.upstream.js';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* RubyGems-specific upstream implementation.
|
|
11
|
+
*
|
|
12
|
+
* Handles:
|
|
13
|
+
* - Compact Index format (/versions, /info/{gem}, /names)
|
|
14
|
+
* - Gem file (.gem) downloading
|
|
15
|
+
* - Gem spec fetching
|
|
16
|
+
* - HTTP Range requests for incremental updates
|
|
17
|
+
*/
|
|
18
|
+
export class RubygemsUpstream extends BaseUpstream {
|
|
19
|
+
protected readonly protocolName = 'rubygems';
|
|
20
|
+
|
|
21
|
+
constructor(
|
|
22
|
+
config: IProtocolUpstreamConfig,
|
|
23
|
+
logger?: plugins.smartlog.Smartlog,
|
|
24
|
+
) {
|
|
25
|
+
super(config, logger);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Fetch the /versions file (master list of all gems).
|
|
30
|
+
*/
|
|
31
|
+
public async fetchVersions(etag?: string): Promise<{ data: string; etag?: string } | null> {
|
|
32
|
+
const headers: Record<string, string> = {
|
|
33
|
+
'accept': 'text/plain',
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
if (etag) {
|
|
37
|
+
headers['if-none-match'] = etag;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const context: IUpstreamFetchContext = {
|
|
41
|
+
protocol: 'rubygems',
|
|
42
|
+
resource: '*',
|
|
43
|
+
resourceType: 'versions',
|
|
44
|
+
path: '/versions',
|
|
45
|
+
method: 'GET',
|
|
46
|
+
headers,
|
|
47
|
+
query: {},
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const result = await this.fetch(context);
|
|
51
|
+
|
|
52
|
+
if (!result || !result.success) {
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
let data: string;
|
|
57
|
+
if (Buffer.isBuffer(result.body)) {
|
|
58
|
+
data = result.body.toString('utf8');
|
|
59
|
+
} else if (typeof result.body === 'string') {
|
|
60
|
+
data = result.body;
|
|
61
|
+
} else {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return {
|
|
66
|
+
data,
|
|
67
|
+
etag: result.headers['etag'],
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Fetch gem info file (/info/{gemname}).
|
|
73
|
+
*/
|
|
74
|
+
public async fetchInfo(gemName: string): Promise<string | null> {
|
|
75
|
+
const context: IUpstreamFetchContext = {
|
|
76
|
+
protocol: 'rubygems',
|
|
77
|
+
resource: gemName,
|
|
78
|
+
resourceType: 'info',
|
|
79
|
+
path: `/info/${gemName}`,
|
|
80
|
+
method: 'GET',
|
|
81
|
+
headers: {
|
|
82
|
+
'accept': 'text/plain',
|
|
83
|
+
},
|
|
84
|
+
query: {},
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
const result = await this.fetch(context);
|
|
88
|
+
|
|
89
|
+
if (!result || !result.success) {
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (Buffer.isBuffer(result.body)) {
|
|
94
|
+
return result.body.toString('utf8');
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return typeof result.body === 'string' ? result.body : null;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Fetch the /names file (list of all gem names).
|
|
102
|
+
*/
|
|
103
|
+
public async fetchNames(): Promise<string | null> {
|
|
104
|
+
const context: IUpstreamFetchContext = {
|
|
105
|
+
protocol: 'rubygems',
|
|
106
|
+
resource: '*',
|
|
107
|
+
resourceType: 'names',
|
|
108
|
+
path: '/names',
|
|
109
|
+
method: 'GET',
|
|
110
|
+
headers: {
|
|
111
|
+
'accept': 'text/plain',
|
|
112
|
+
},
|
|
113
|
+
query: {},
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
const result = await this.fetch(context);
|
|
117
|
+
|
|
118
|
+
if (!result || !result.success) {
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (Buffer.isBuffer(result.body)) {
|
|
123
|
+
return result.body.toString('utf8');
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return typeof result.body === 'string' ? result.body : null;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Fetch a gem file.
|
|
131
|
+
*/
|
|
132
|
+
public async fetchGem(gemName: string, version: string): Promise<Buffer | null> {
|
|
133
|
+
const path = `/gems/${gemName}-${version}.gem`;
|
|
134
|
+
|
|
135
|
+
const context: IUpstreamFetchContext = {
|
|
136
|
+
protocol: 'rubygems',
|
|
137
|
+
resource: gemName,
|
|
138
|
+
resourceType: 'gem',
|
|
139
|
+
path,
|
|
140
|
+
method: 'GET',
|
|
141
|
+
headers: {
|
|
142
|
+
'accept': 'application/octet-stream',
|
|
143
|
+
},
|
|
144
|
+
query: {},
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
const result = await this.fetch(context);
|
|
148
|
+
|
|
149
|
+
if (!result || !result.success) {
|
|
150
|
+
return null;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return Buffer.isBuffer(result.body) ? result.body : Buffer.from(result.body);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Fetch gem spec (quick spec).
|
|
158
|
+
*/
|
|
159
|
+
public async fetchQuickSpec(gemName: string, version: string): Promise<Buffer | null> {
|
|
160
|
+
const path = `/quick/Marshal.4.8/${gemName}-${version}.gemspec.rz`;
|
|
161
|
+
|
|
162
|
+
const context: IUpstreamFetchContext = {
|
|
163
|
+
protocol: 'rubygems',
|
|
164
|
+
resource: gemName,
|
|
165
|
+
resourceType: 'spec',
|
|
166
|
+
path,
|
|
167
|
+
method: 'GET',
|
|
168
|
+
headers: {
|
|
169
|
+
'accept': 'application/octet-stream',
|
|
170
|
+
},
|
|
171
|
+
query: {},
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
const result = await this.fetch(context);
|
|
175
|
+
|
|
176
|
+
if (!result || !result.success) {
|
|
177
|
+
return null;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
return Buffer.isBuffer(result.body) ? result.body : Buffer.from(result.body);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Fetch gem versions JSON from API.
|
|
185
|
+
*/
|
|
186
|
+
public async fetchVersionsJson(gemName: string): Promise<any[] | null> {
|
|
187
|
+
const path = `/api/v1/versions/${gemName}.json`;
|
|
188
|
+
|
|
189
|
+
const context: IUpstreamFetchContext = {
|
|
190
|
+
protocol: 'rubygems',
|
|
191
|
+
resource: gemName,
|
|
192
|
+
resourceType: 'versions-json',
|
|
193
|
+
path,
|
|
194
|
+
method: 'GET',
|
|
195
|
+
headers: {
|
|
196
|
+
'accept': 'application/json',
|
|
197
|
+
},
|
|
198
|
+
query: {},
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
const result = await this.fetch(context);
|
|
202
|
+
|
|
203
|
+
if (!result || !result.success) {
|
|
204
|
+
return null;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
if (Buffer.isBuffer(result.body)) {
|
|
208
|
+
return JSON.parse(result.body.toString('utf8'));
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
return Array.isArray(result.body) ? result.body : null;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Override URL building for RubyGems-specific handling.
|
|
216
|
+
*/
|
|
217
|
+
protected buildUpstreamUrl(
|
|
218
|
+
upstream: IUpstreamRegistryConfig,
|
|
219
|
+
context: IUpstreamFetchContext,
|
|
220
|
+
): string {
|
|
221
|
+
let baseUrl = upstream.url;
|
|
222
|
+
|
|
223
|
+
// Remove trailing slash
|
|
224
|
+
if (baseUrl.endsWith('/')) {
|
|
225
|
+
baseUrl = baseUrl.slice(0, -1);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
return `${baseUrl}${context.path}`;
|
|
229
|
+
}
|
|
230
|
+
}
|