@push.rocks/smartregistry 1.1.1 → 1.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 +79 -0
- package/dist_ts/cargo/classes.cargoregistry.js +490 -0
- package/dist_ts/cargo/index.d.ts +5 -0
- package/dist_ts/cargo/index.js +6 -0
- package/dist_ts/cargo/interfaces.cargo.d.ts +160 -0
- package/dist_ts/cargo/interfaces.cargo.js +6 -0
- package/dist_ts/classes.smartregistry.d.ts +2 -2
- package/dist_ts/classes.smartregistry.js +50 -2
- package/dist_ts/composer/classes.composerregistry.d.ts +26 -0
- package/dist_ts/composer/classes.composerregistry.js +366 -0
- package/dist_ts/composer/helpers.composer.d.ts +35 -0
- package/dist_ts/composer/helpers.composer.js +120 -0
- package/dist_ts/composer/index.d.ts +7 -0
- package/dist_ts/composer/index.js +8 -0
- package/dist_ts/composer/interfaces.composer.d.ts +102 -0
- package/dist_ts/composer/interfaces.composer.js +6 -0
- package/dist_ts/core/classes.authmanager.d.ts +46 -1
- package/dist_ts/core/classes.authmanager.js +121 -12
- package/dist_ts/core/classes.registrystorage.d.ts +103 -0
- package/dist_ts/core/classes.registrystorage.js +253 -1
- package/dist_ts/core/interfaces.core.d.ts +4 -1
- package/dist_ts/index.d.ts +4 -1
- package/dist_ts/index.js +8 -2
- package/dist_ts/maven/classes.mavenregistry.d.ts +35 -0
- package/dist_ts/maven/classes.mavenregistry.js +407 -0
- package/dist_ts/maven/helpers.maven.d.ts +68 -0
- package/dist_ts/maven/helpers.maven.js +286 -0
- package/dist_ts/maven/index.d.ts +6 -0
- package/dist_ts/maven/index.js +7 -0
- package/dist_ts/maven/interfaces.maven.d.ts +116 -0
- package/dist_ts/maven/interfaces.maven.js +6 -0
- package/package.json +3 -2
- package/readme.md +288 -14
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/cargo/classes.cargoregistry.ts +604 -0
- package/ts/cargo/index.ts +6 -0
- package/ts/cargo/interfaces.cargo.ts +169 -0
- package/ts/classes.smartregistry.ts +56 -2
- package/ts/composer/classes.composerregistry.ts +475 -0
- package/ts/composer/helpers.composer.ts +139 -0
- package/ts/composer/index.ts +8 -0
- package/ts/composer/interfaces.composer.ts +111 -0
- package/ts/core/classes.authmanager.ts +145 -12
- package/ts/core/classes.registrystorage.ts +334 -0
- package/ts/core/interfaces.core.ts +4 -1
- package/ts/index.ts +10 -1
- package/ts/maven/classes.mavenregistry.ts +580 -0
- package/ts/maven/helpers.maven.ts +346 -0
- package/ts/maven/index.ts +7 -0
- package/ts/maven/interfaces.maven.ts +127 -0
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Composer Registry Type Definitions
|
|
3
|
+
* Compliant with Composer v2 repository API
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Composer package metadata
|
|
8
|
+
*/
|
|
9
|
+
export interface IComposerPackage {
|
|
10
|
+
name: string; // vendor/package-name
|
|
11
|
+
version: string; // 1.0.0
|
|
12
|
+
version_normalized: string; // 1.0.0.0
|
|
13
|
+
type?: string; // library, project, metapackage
|
|
14
|
+
description?: string;
|
|
15
|
+
keywords?: string[];
|
|
16
|
+
homepage?: string;
|
|
17
|
+
license?: string[];
|
|
18
|
+
authors?: IComposerAuthor[];
|
|
19
|
+
require?: Record<string, string>;
|
|
20
|
+
'require-dev'?: Record<string, string>;
|
|
21
|
+
suggest?: Record<string, string>;
|
|
22
|
+
provide?: Record<string, string>;
|
|
23
|
+
conflict?: Record<string, string>;
|
|
24
|
+
replace?: Record<string, string>;
|
|
25
|
+
autoload?: IComposerAutoload;
|
|
26
|
+
'autoload-dev'?: IComposerAutoload;
|
|
27
|
+
dist?: IComposerDist;
|
|
28
|
+
source?: IComposerSource;
|
|
29
|
+
time?: string; // ISO 8601 timestamp
|
|
30
|
+
support?: Record<string, string>;
|
|
31
|
+
funding?: IComposerFunding[];
|
|
32
|
+
extra?: Record<string, any>;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Author information
|
|
37
|
+
*/
|
|
38
|
+
export interface IComposerAuthor {
|
|
39
|
+
name: string;
|
|
40
|
+
email?: string;
|
|
41
|
+
homepage?: string;
|
|
42
|
+
role?: string;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* PSR-4/PSR-0 autoloading configuration
|
|
47
|
+
*/
|
|
48
|
+
export interface IComposerAutoload {
|
|
49
|
+
'psr-4'?: Record<string, string | string[]>;
|
|
50
|
+
'psr-0'?: Record<string, string | string[]>;
|
|
51
|
+
classmap?: string[];
|
|
52
|
+
files?: string[];
|
|
53
|
+
'exclude-from-classmap'?: string[];
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Distribution information (ZIP download)
|
|
58
|
+
*/
|
|
59
|
+
export interface IComposerDist {
|
|
60
|
+
type: 'zip' | 'tar' | 'phar';
|
|
61
|
+
url: string;
|
|
62
|
+
reference?: string; // commit hash or tag
|
|
63
|
+
shasum?: string; // SHA-1 hash
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Source repository information
|
|
68
|
+
*/
|
|
69
|
+
export interface IComposerSource {
|
|
70
|
+
type: 'git' | 'svn' | 'hg';
|
|
71
|
+
url: string;
|
|
72
|
+
reference: string; // commit hash, branch, or tag
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Funding information
|
|
77
|
+
*/
|
|
78
|
+
export interface IComposerFunding {
|
|
79
|
+
type: string; // github, patreon, etc.
|
|
80
|
+
url: string;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Repository metadata (packages.json)
|
|
85
|
+
*/
|
|
86
|
+
export interface IComposerRepository {
|
|
87
|
+
packages?: Record<string, Record<string, IComposerPackage>>;
|
|
88
|
+
'metadata-url'?: string; // /p2/%package%.json
|
|
89
|
+
'available-packages'?: string[];
|
|
90
|
+
'available-package-patterns'?: string[];
|
|
91
|
+
'providers-url'?: string;
|
|
92
|
+
'notify-batch'?: string;
|
|
93
|
+
minified?: string; // "composer/2.0"
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Package metadata response (/p2/vendor/package.json)
|
|
98
|
+
*/
|
|
99
|
+
export interface IComposerPackageMetadata {
|
|
100
|
+
packages: Record<string, IComposerPackage[]>;
|
|
101
|
+
minified?: string;
|
|
102
|
+
lastModified?: string;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Error structure
|
|
107
|
+
*/
|
|
108
|
+
export interface IComposerError {
|
|
109
|
+
status: string;
|
|
110
|
+
message: string;
|
|
111
|
+
}
|
|
@@ -19,25 +19,28 @@ export class AuthManager {
|
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
// ========================================================================
|
|
22
|
-
// NPM
|
|
22
|
+
// UUID TOKEN CREATION (Base method for NPM, Maven, etc.)
|
|
23
23
|
// ========================================================================
|
|
24
24
|
|
|
25
25
|
/**
|
|
26
|
-
* Create
|
|
26
|
+
* Create a UUID-based token with custom scopes (base method)
|
|
27
27
|
* @param userId - User ID
|
|
28
|
+
* @param protocol - Protocol type
|
|
29
|
+
* @param scopes - Permission scopes
|
|
28
30
|
* @param readonly - Whether the token is readonly
|
|
29
|
-
* @returns
|
|
31
|
+
* @returns UUID token string
|
|
30
32
|
*/
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
private async createUuidToken(
|
|
34
|
+
userId: string,
|
|
35
|
+
protocol: TRegistryProtocol,
|
|
36
|
+
scopes: string[],
|
|
37
|
+
readonly: boolean = false
|
|
38
|
+
): Promise<string> {
|
|
36
39
|
const token = this.generateUuid();
|
|
37
40
|
const authToken: IAuthToken = {
|
|
38
|
-
type:
|
|
41
|
+
type: protocol,
|
|
39
42
|
userId,
|
|
40
|
-
scopes
|
|
43
|
+
scopes,
|
|
41
44
|
readonly,
|
|
42
45
|
metadata: {
|
|
43
46
|
created: new Date().toISOString(),
|
|
@@ -48,6 +51,25 @@ export class AuthManager {
|
|
|
48
51
|
return token;
|
|
49
52
|
}
|
|
50
53
|
|
|
54
|
+
// ========================================================================
|
|
55
|
+
// NPM AUTHENTICATION
|
|
56
|
+
// ========================================================================
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Create an NPM token
|
|
60
|
+
* @param userId - User ID
|
|
61
|
+
* @param readonly - Whether the token is readonly
|
|
62
|
+
* @returns NPM UUID token
|
|
63
|
+
*/
|
|
64
|
+
public async createNpmToken(userId: string, readonly: boolean = false): Promise<string> {
|
|
65
|
+
if (!this.config.npmTokens.enabled) {
|
|
66
|
+
throw new Error('NPM tokens are not enabled');
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const scopes = readonly ? ['npm:*:*:read'] : ['npm:*:*:*'];
|
|
70
|
+
return this.createUuidToken(userId, 'npm', scopes, readonly);
|
|
71
|
+
}
|
|
72
|
+
|
|
51
73
|
/**
|
|
52
74
|
* Validate an NPM token
|
|
53
75
|
* @param token - NPM UUID token
|
|
@@ -201,8 +223,106 @@ export class AuthManager {
|
|
|
201
223
|
return null;
|
|
202
224
|
}
|
|
203
225
|
|
|
226
|
+
// ========================================================================
|
|
227
|
+
// MAVEN AUTHENTICATION
|
|
228
|
+
// ========================================================================
|
|
229
|
+
|
|
204
230
|
/**
|
|
205
|
-
*
|
|
231
|
+
* Create a Maven token
|
|
232
|
+
* @param userId - User ID
|
|
233
|
+
* @param readonly - Whether the token is readonly
|
|
234
|
+
* @returns Maven UUID token
|
|
235
|
+
*/
|
|
236
|
+
public async createMavenToken(userId: string, readonly: boolean = false): Promise<string> {
|
|
237
|
+
const scopes = readonly ? ['maven:*:*:read'] : ['maven:*:*:*'];
|
|
238
|
+
return this.createUuidToken(userId, 'maven', scopes, readonly);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Validate a Maven token
|
|
243
|
+
* @param token - Maven UUID token
|
|
244
|
+
* @returns Auth token object or null
|
|
245
|
+
*/
|
|
246
|
+
public async validateMavenToken(token: string): Promise<IAuthToken | null> {
|
|
247
|
+
if (!this.isValidUuid(token)) {
|
|
248
|
+
return null;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
const authToken = this.tokenStore.get(token);
|
|
252
|
+
if (!authToken || authToken.type !== 'maven') {
|
|
253
|
+
return null;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// Check expiration if set
|
|
257
|
+
if (authToken.expiresAt && authToken.expiresAt < new Date()) {
|
|
258
|
+
this.tokenStore.delete(token);
|
|
259
|
+
return null;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
return authToken;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Revoke a Maven token
|
|
267
|
+
* @param token - Maven UUID token
|
|
268
|
+
*/
|
|
269
|
+
public async revokeMavenToken(token: string): Promise<void> {
|
|
270
|
+
this.tokenStore.delete(token);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// ========================================================================
|
|
274
|
+
// COMPOSER TOKEN MANAGEMENT
|
|
275
|
+
// ========================================================================
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Create a Composer token
|
|
279
|
+
* @param userId - User ID
|
|
280
|
+
* @param readonly - Whether the token is readonly
|
|
281
|
+
* @returns Composer UUID token
|
|
282
|
+
*/
|
|
283
|
+
public async createComposerToken(userId: string, readonly: boolean = false): Promise<string> {
|
|
284
|
+
const scopes = readonly ? ['composer:*:*:read'] : ['composer:*:*:*'];
|
|
285
|
+
return this.createUuidToken(userId, 'composer', scopes, readonly);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Validate a Composer token
|
|
290
|
+
* @param token - Composer UUID token
|
|
291
|
+
* @returns Auth token object or null
|
|
292
|
+
*/
|
|
293
|
+
public async validateComposerToken(token: string): Promise<IAuthToken | null> {
|
|
294
|
+
if (!this.isValidUuid(token)) {
|
|
295
|
+
return null;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
const authToken = this.tokenStore.get(token);
|
|
299
|
+
if (!authToken || authToken.type !== 'composer') {
|
|
300
|
+
return null;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// Check expiration if set
|
|
304
|
+
if (authToken.expiresAt && authToken.expiresAt < new Date()) {
|
|
305
|
+
this.tokenStore.delete(token);
|
|
306
|
+
return null;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
return authToken;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Revoke a Composer token
|
|
314
|
+
* @param token - Composer UUID token
|
|
315
|
+
*/
|
|
316
|
+
public async revokeComposerToken(token: string): Promise<void> {
|
|
317
|
+
this.tokenStore.delete(token);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
// ========================================================================
|
|
321
|
+
// UNIFIED AUTHENTICATION
|
|
322
|
+
// ========================================================================
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* Validate any token (NPM, Maven, or OCI)
|
|
206
326
|
* @param tokenString - Token string (UUID or JWT)
|
|
207
327
|
* @param protocol - Expected protocol type
|
|
208
328
|
* @returns Auth token object or null
|
|
@@ -211,12 +331,25 @@ export class AuthManager {
|
|
|
211
331
|
tokenString: string,
|
|
212
332
|
protocol?: TRegistryProtocol
|
|
213
333
|
): Promise<IAuthToken | null> {
|
|
214
|
-
// Try
|
|
334
|
+
// Try UUID-based tokens (NPM, Maven, Composer)
|
|
215
335
|
if (this.isValidUuid(tokenString)) {
|
|
336
|
+
// Try NPM token
|
|
216
337
|
const npmToken = await this.validateNpmToken(tokenString);
|
|
217
338
|
if (npmToken && (!protocol || protocol === 'npm')) {
|
|
218
339
|
return npmToken;
|
|
219
340
|
}
|
|
341
|
+
|
|
342
|
+
// Try Maven token
|
|
343
|
+
const mavenToken = await this.validateMavenToken(tokenString);
|
|
344
|
+
if (mavenToken && (!protocol || protocol === 'maven')) {
|
|
345
|
+
return mavenToken;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
// Try Composer token
|
|
349
|
+
const composerToken = await this.validateComposerToken(tokenString);
|
|
350
|
+
if (composerToken && (!protocol || protocol === 'composer')) {
|
|
351
|
+
return composerToken;
|
|
352
|
+
}
|
|
220
353
|
}
|
|
221
354
|
|
|
222
355
|
// Try OCI JWT
|
|
@@ -267,4 +267,338 @@ export class RegistryStorage implements IStorageBackend {
|
|
|
267
267
|
const safeName = packageName.replace('@', '').replace('/', '-');
|
|
268
268
|
return `npm/packages/${packageName}/${safeName}-${version}.tgz`;
|
|
269
269
|
}
|
|
270
|
+
|
|
271
|
+
// ========================================================================
|
|
272
|
+
// MAVEN STORAGE METHODS
|
|
273
|
+
// ========================================================================
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Get Maven artifact
|
|
277
|
+
*/
|
|
278
|
+
public async getMavenArtifact(
|
|
279
|
+
groupId: string,
|
|
280
|
+
artifactId: string,
|
|
281
|
+
version: string,
|
|
282
|
+
filename: string
|
|
283
|
+
): Promise<Buffer | null> {
|
|
284
|
+
const path = this.getMavenArtifactPath(groupId, artifactId, version, filename);
|
|
285
|
+
return this.getObject(path);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Store Maven artifact
|
|
290
|
+
*/
|
|
291
|
+
public async putMavenArtifact(
|
|
292
|
+
groupId: string,
|
|
293
|
+
artifactId: string,
|
|
294
|
+
version: string,
|
|
295
|
+
filename: string,
|
|
296
|
+
data: Buffer
|
|
297
|
+
): Promise<void> {
|
|
298
|
+
const path = this.getMavenArtifactPath(groupId, artifactId, version, filename);
|
|
299
|
+
return this.putObject(path, data);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Check if Maven artifact exists
|
|
304
|
+
*/
|
|
305
|
+
public async mavenArtifactExists(
|
|
306
|
+
groupId: string,
|
|
307
|
+
artifactId: string,
|
|
308
|
+
version: string,
|
|
309
|
+
filename: string
|
|
310
|
+
): Promise<boolean> {
|
|
311
|
+
const path = this.getMavenArtifactPath(groupId, artifactId, version, filename);
|
|
312
|
+
return this.objectExists(path);
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* Delete Maven artifact
|
|
317
|
+
*/
|
|
318
|
+
public async deleteMavenArtifact(
|
|
319
|
+
groupId: string,
|
|
320
|
+
artifactId: string,
|
|
321
|
+
version: string,
|
|
322
|
+
filename: string
|
|
323
|
+
): Promise<void> {
|
|
324
|
+
const path = this.getMavenArtifactPath(groupId, artifactId, version, filename);
|
|
325
|
+
return this.deleteObject(path);
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* Get Maven metadata (maven-metadata.xml)
|
|
330
|
+
*/
|
|
331
|
+
public async getMavenMetadata(
|
|
332
|
+
groupId: string,
|
|
333
|
+
artifactId: string
|
|
334
|
+
): Promise<Buffer | null> {
|
|
335
|
+
const path = this.getMavenMetadataPath(groupId, artifactId);
|
|
336
|
+
return this.getObject(path);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* Store Maven metadata (maven-metadata.xml)
|
|
341
|
+
*/
|
|
342
|
+
public async putMavenMetadata(
|
|
343
|
+
groupId: string,
|
|
344
|
+
artifactId: string,
|
|
345
|
+
data: Buffer
|
|
346
|
+
): Promise<void> {
|
|
347
|
+
const path = this.getMavenMetadataPath(groupId, artifactId);
|
|
348
|
+
return this.putObject(path, data);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/**
|
|
352
|
+
* Delete Maven metadata (maven-metadata.xml)
|
|
353
|
+
*/
|
|
354
|
+
public async deleteMavenMetadata(
|
|
355
|
+
groupId: string,
|
|
356
|
+
artifactId: string
|
|
357
|
+
): Promise<void> {
|
|
358
|
+
const path = this.getMavenMetadataPath(groupId, artifactId);
|
|
359
|
+
return this.deleteObject(path);
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
/**
|
|
363
|
+
* List Maven versions for an artifact
|
|
364
|
+
* Returns all version directories under the artifact path
|
|
365
|
+
*/
|
|
366
|
+
public async listMavenVersions(
|
|
367
|
+
groupId: string,
|
|
368
|
+
artifactId: string
|
|
369
|
+
): Promise<string[]> {
|
|
370
|
+
const groupPath = groupId.replace(/\./g, '/');
|
|
371
|
+
const prefix = `maven/artifacts/${groupPath}/${artifactId}/`;
|
|
372
|
+
|
|
373
|
+
const objects = await this.listObjects(prefix);
|
|
374
|
+
const versions = new Set<string>();
|
|
375
|
+
|
|
376
|
+
// Extract version from paths like: maven/artifacts/com/example/my-lib/1.0.0/my-lib-1.0.0.jar
|
|
377
|
+
for (const obj of objects) {
|
|
378
|
+
const relativePath = obj.substring(prefix.length);
|
|
379
|
+
const parts = relativePath.split('/');
|
|
380
|
+
if (parts.length >= 1 && parts[0]) {
|
|
381
|
+
versions.add(parts[0]);
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
return Array.from(versions).sort();
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
// ========================================================================
|
|
389
|
+
// MAVEN PATH HELPERS
|
|
390
|
+
// ========================================================================
|
|
391
|
+
|
|
392
|
+
private getMavenArtifactPath(
|
|
393
|
+
groupId: string,
|
|
394
|
+
artifactId: string,
|
|
395
|
+
version: string,
|
|
396
|
+
filename: string
|
|
397
|
+
): string {
|
|
398
|
+
const groupPath = groupId.replace(/\./g, '/');
|
|
399
|
+
return `maven/artifacts/${groupPath}/${artifactId}/${version}/${filename}`;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
private getMavenMetadataPath(groupId: string, artifactId: string): string {
|
|
403
|
+
const groupPath = groupId.replace(/\./g, '/');
|
|
404
|
+
return `maven/metadata/${groupPath}/${artifactId}/maven-metadata.xml`;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
// ========================================================================
|
|
408
|
+
// CARGO-SPECIFIC HELPERS
|
|
409
|
+
// ========================================================================
|
|
410
|
+
|
|
411
|
+
/**
|
|
412
|
+
* Get Cargo config.json
|
|
413
|
+
*/
|
|
414
|
+
public async getCargoConfig(): Promise<any | null> {
|
|
415
|
+
const data = await this.getObject('cargo/config.json');
|
|
416
|
+
return data ? JSON.parse(data.toString('utf-8')) : null;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
/**
|
|
420
|
+
* Store Cargo config.json
|
|
421
|
+
*/
|
|
422
|
+
public async putCargoConfig(config: any): Promise<void> {
|
|
423
|
+
const data = Buffer.from(JSON.stringify(config, null, 2), 'utf-8');
|
|
424
|
+
return this.putObject('cargo/config.json', data, { 'Content-Type': 'application/json' });
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
/**
|
|
428
|
+
* Get Cargo index file (newline-delimited JSON)
|
|
429
|
+
*/
|
|
430
|
+
public async getCargoIndex(crateName: string): Promise<any[] | null> {
|
|
431
|
+
const path = this.getCargoIndexPath(crateName);
|
|
432
|
+
const data = await this.getObject(path);
|
|
433
|
+
if (!data) return null;
|
|
434
|
+
|
|
435
|
+
// Parse newline-delimited JSON
|
|
436
|
+
const lines = data.toString('utf-8').split('\n').filter(line => line.trim());
|
|
437
|
+
return lines.map(line => JSON.parse(line));
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
/**
|
|
441
|
+
* Store Cargo index file
|
|
442
|
+
*/
|
|
443
|
+
public async putCargoIndex(crateName: string, entries: any[]): Promise<void> {
|
|
444
|
+
const path = this.getCargoIndexPath(crateName);
|
|
445
|
+
// Convert to newline-delimited JSON
|
|
446
|
+
const data = Buffer.from(entries.map(e => JSON.stringify(e)).join('\n') + '\n', 'utf-8');
|
|
447
|
+
return this.putObject(path, data, { 'Content-Type': 'text/plain' });
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
/**
|
|
451
|
+
* Get Cargo .crate file
|
|
452
|
+
*/
|
|
453
|
+
public async getCargoCrate(crateName: string, version: string): Promise<Buffer | null> {
|
|
454
|
+
const path = this.getCargoCratePath(crateName, version);
|
|
455
|
+
return this.getObject(path);
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
/**
|
|
459
|
+
* Store Cargo .crate file
|
|
460
|
+
*/
|
|
461
|
+
public async putCargoCrate(
|
|
462
|
+
crateName: string,
|
|
463
|
+
version: string,
|
|
464
|
+
crateFile: Buffer
|
|
465
|
+
): Promise<void> {
|
|
466
|
+
const path = this.getCargoCratePath(crateName, version);
|
|
467
|
+
return this.putObject(path, crateFile, { 'Content-Type': 'application/gzip' });
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
/**
|
|
471
|
+
* Check if Cargo crate exists
|
|
472
|
+
*/
|
|
473
|
+
public async cargoCrateExists(crateName: string, version: string): Promise<boolean> {
|
|
474
|
+
const path = this.getCargoCratePath(crateName, version);
|
|
475
|
+
return this.objectExists(path);
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
/**
|
|
479
|
+
* Delete Cargo crate (for cleanup, not for unpublishing)
|
|
480
|
+
*/
|
|
481
|
+
public async deleteCargoCrate(crateName: string, version: string): Promise<void> {
|
|
482
|
+
const path = this.getCargoCratePath(crateName, version);
|
|
483
|
+
return this.deleteObject(path);
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
// ========================================================================
|
|
487
|
+
// CARGO PATH HELPERS
|
|
488
|
+
// ========================================================================
|
|
489
|
+
|
|
490
|
+
private getCargoIndexPath(crateName: string): string {
|
|
491
|
+
const lower = crateName.toLowerCase();
|
|
492
|
+
const len = lower.length;
|
|
493
|
+
|
|
494
|
+
if (len === 1) {
|
|
495
|
+
return `cargo/index/1/${lower}`;
|
|
496
|
+
} else if (len === 2) {
|
|
497
|
+
return `cargo/index/2/${lower}`;
|
|
498
|
+
} else if (len === 3) {
|
|
499
|
+
return `cargo/index/3/${lower.charAt(0)}/${lower}`;
|
|
500
|
+
} else {
|
|
501
|
+
// 4+ characters: {first-two}/{second-two}/{name}
|
|
502
|
+
const prefix1 = lower.substring(0, 2);
|
|
503
|
+
const prefix2 = lower.substring(2, 4);
|
|
504
|
+
return `cargo/index/${prefix1}/${prefix2}/${lower}`;
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
private getCargoCratePath(crateName: string, version: string): string {
|
|
509
|
+
return `cargo/crates/${crateName}/${crateName}-${version}.crate`;
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
// ========================================================================
|
|
513
|
+
// COMPOSER-SPECIFIC HELPERS
|
|
514
|
+
// ========================================================================
|
|
515
|
+
|
|
516
|
+
/**
|
|
517
|
+
* Get Composer package metadata
|
|
518
|
+
*/
|
|
519
|
+
public async getComposerPackageMetadata(vendorPackage: string): Promise<any | null> {
|
|
520
|
+
const path = this.getComposerMetadataPath(vendorPackage);
|
|
521
|
+
const data = await this.getObject(path);
|
|
522
|
+
return data ? JSON.parse(data.toString('utf-8')) : null;
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
/**
|
|
526
|
+
* Store Composer package metadata
|
|
527
|
+
*/
|
|
528
|
+
public async putComposerPackageMetadata(vendorPackage: string, metadata: any): Promise<void> {
|
|
529
|
+
const path = this.getComposerMetadataPath(vendorPackage);
|
|
530
|
+
const data = Buffer.from(JSON.stringify(metadata, null, 2), 'utf-8');
|
|
531
|
+
return this.putObject(path, data, { 'Content-Type': 'application/json' });
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
/**
|
|
535
|
+
* Get Composer package ZIP
|
|
536
|
+
*/
|
|
537
|
+
public async getComposerPackageZip(vendorPackage: string, reference: string): Promise<Buffer | null> {
|
|
538
|
+
const path = this.getComposerZipPath(vendorPackage, reference);
|
|
539
|
+
return this.getObject(path);
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
/**
|
|
543
|
+
* Store Composer package ZIP
|
|
544
|
+
*/
|
|
545
|
+
public async putComposerPackageZip(vendorPackage: string, reference: string, zipData: Buffer): Promise<void> {
|
|
546
|
+
const path = this.getComposerZipPath(vendorPackage, reference);
|
|
547
|
+
return this.putObject(path, zipData, { 'Content-Type': 'application/zip' });
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
/**
|
|
551
|
+
* Check if Composer package metadata exists
|
|
552
|
+
*/
|
|
553
|
+
public async composerPackageMetadataExists(vendorPackage: string): Promise<boolean> {
|
|
554
|
+
const path = this.getComposerMetadataPath(vendorPackage);
|
|
555
|
+
return this.objectExists(path);
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
/**
|
|
559
|
+
* Delete Composer package metadata
|
|
560
|
+
*/
|
|
561
|
+
public async deleteComposerPackageMetadata(vendorPackage: string): Promise<void> {
|
|
562
|
+
const path = this.getComposerMetadataPath(vendorPackage);
|
|
563
|
+
return this.deleteObject(path);
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
/**
|
|
567
|
+
* Delete Composer package ZIP
|
|
568
|
+
*/
|
|
569
|
+
public async deleteComposerPackageZip(vendorPackage: string, reference: string): Promise<void> {
|
|
570
|
+
const path = this.getComposerZipPath(vendorPackage, reference);
|
|
571
|
+
return this.deleteObject(path);
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
/**
|
|
575
|
+
* List all Composer packages
|
|
576
|
+
*/
|
|
577
|
+
public async listComposerPackages(): Promise<string[]> {
|
|
578
|
+
const prefix = 'composer/packages/';
|
|
579
|
+
const objects = await this.listObjects(prefix);
|
|
580
|
+
const packages = new Set<string>();
|
|
581
|
+
|
|
582
|
+
// Extract vendor/package from paths like: composer/packages/vendor/package/metadata.json
|
|
583
|
+
for (const obj of objects) {
|
|
584
|
+
const match = obj.match(/^composer\/packages\/([^\/]+\/[^\/]+)\/metadata\.json$/);
|
|
585
|
+
if (match) {
|
|
586
|
+
packages.add(match[1]);
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
return Array.from(packages).sort();
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
// ========================================================================
|
|
594
|
+
// COMPOSER PATH HELPERS
|
|
595
|
+
// ========================================================================
|
|
596
|
+
|
|
597
|
+
private getComposerMetadataPath(vendorPackage: string): string {
|
|
598
|
+
return `composer/packages/${vendorPackage}/metadata.json`;
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
private getComposerZipPath(vendorPackage: string, reference: string): string {
|
|
602
|
+
return `composer/packages/${vendorPackage}/${reference}.zip`;
|
|
603
|
+
}
|
|
270
604
|
}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
/**
|
|
6
6
|
* Registry protocol types
|
|
7
7
|
*/
|
|
8
|
-
export type TRegistryProtocol = 'oci' | 'npm';
|
|
8
|
+
export type TRegistryProtocol = 'oci' | 'npm' | 'maven' | 'cargo' | 'composer';
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* Unified action types across protocols
|
|
@@ -89,6 +89,9 @@ export interface IRegistryConfig {
|
|
|
89
89
|
auth: IAuthConfig;
|
|
90
90
|
oci?: IProtocolConfig;
|
|
91
91
|
npm?: IProtocolConfig;
|
|
92
|
+
maven?: IProtocolConfig;
|
|
93
|
+
cargo?: IProtocolConfig;
|
|
94
|
+
composer?: IProtocolConfig;
|
|
92
95
|
}
|
|
93
96
|
|
|
94
97
|
/**
|
package/ts/index.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @push.rocks/smartregistry
|
|
3
|
-
* Composable registry supporting OCI and
|
|
3
|
+
* Composable registry supporting OCI, NPM, Maven, Cargo, and Composer protocols
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
// Main orchestrator
|
|
@@ -14,3 +14,12 @@ export * from './oci/index.js';
|
|
|
14
14
|
|
|
15
15
|
// NPM Registry
|
|
16
16
|
export * from './npm/index.js';
|
|
17
|
+
|
|
18
|
+
// Maven Registry
|
|
19
|
+
export * from './maven/index.js';
|
|
20
|
+
|
|
21
|
+
// Cargo Registry
|
|
22
|
+
export * from './cargo/index.js';
|
|
23
|
+
|
|
24
|
+
// Composer Registry
|
|
25
|
+
export * from './composer/index.js';
|