@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.
Files changed (51) hide show
  1. package/dist_ts/00_commitinfo_data.js +1 -1
  2. package/dist_ts/cargo/classes.cargoregistry.d.ts +79 -0
  3. package/dist_ts/cargo/classes.cargoregistry.js +490 -0
  4. package/dist_ts/cargo/index.d.ts +5 -0
  5. package/dist_ts/cargo/index.js +6 -0
  6. package/dist_ts/cargo/interfaces.cargo.d.ts +160 -0
  7. package/dist_ts/cargo/interfaces.cargo.js +6 -0
  8. package/dist_ts/classes.smartregistry.d.ts +2 -2
  9. package/dist_ts/classes.smartregistry.js +50 -2
  10. package/dist_ts/composer/classes.composerregistry.d.ts +26 -0
  11. package/dist_ts/composer/classes.composerregistry.js +366 -0
  12. package/dist_ts/composer/helpers.composer.d.ts +35 -0
  13. package/dist_ts/composer/helpers.composer.js +120 -0
  14. package/dist_ts/composer/index.d.ts +7 -0
  15. package/dist_ts/composer/index.js +8 -0
  16. package/dist_ts/composer/interfaces.composer.d.ts +102 -0
  17. package/dist_ts/composer/interfaces.composer.js +6 -0
  18. package/dist_ts/core/classes.authmanager.d.ts +46 -1
  19. package/dist_ts/core/classes.authmanager.js +121 -12
  20. package/dist_ts/core/classes.registrystorage.d.ts +103 -0
  21. package/dist_ts/core/classes.registrystorage.js +253 -1
  22. package/dist_ts/core/interfaces.core.d.ts +4 -1
  23. package/dist_ts/index.d.ts +4 -1
  24. package/dist_ts/index.js +8 -2
  25. package/dist_ts/maven/classes.mavenregistry.d.ts +35 -0
  26. package/dist_ts/maven/classes.mavenregistry.js +407 -0
  27. package/dist_ts/maven/helpers.maven.d.ts +68 -0
  28. package/dist_ts/maven/helpers.maven.js +286 -0
  29. package/dist_ts/maven/index.d.ts +6 -0
  30. package/dist_ts/maven/index.js +7 -0
  31. package/dist_ts/maven/interfaces.maven.d.ts +116 -0
  32. package/dist_ts/maven/interfaces.maven.js +6 -0
  33. package/package.json +3 -2
  34. package/readme.md +288 -14
  35. package/ts/00_commitinfo_data.ts +1 -1
  36. package/ts/cargo/classes.cargoregistry.ts +604 -0
  37. package/ts/cargo/index.ts +6 -0
  38. package/ts/cargo/interfaces.cargo.ts +169 -0
  39. package/ts/classes.smartregistry.ts +56 -2
  40. package/ts/composer/classes.composerregistry.ts +475 -0
  41. package/ts/composer/helpers.composer.ts +139 -0
  42. package/ts/composer/index.ts +8 -0
  43. package/ts/composer/interfaces.composer.ts +111 -0
  44. package/ts/core/classes.authmanager.ts +145 -12
  45. package/ts/core/classes.registrystorage.ts +334 -0
  46. package/ts/core/interfaces.core.ts +4 -1
  47. package/ts/index.ts +10 -1
  48. package/ts/maven/classes.mavenregistry.ts +580 -0
  49. package/ts/maven/helpers.maven.ts +346 -0
  50. package/ts/maven/index.ts +7 -0
  51. 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 AUTHENTICATION
22
+ // UUID TOKEN CREATION (Base method for NPM, Maven, etc.)
23
23
  // ========================================================================
24
24
 
25
25
  /**
26
- * Create an NPM token
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 NPM UUID token
31
+ * @returns UUID token string
30
32
  */
31
- public async createNpmToken(userId: string, readonly: boolean = false): Promise<string> {
32
- if (!this.config.npmTokens.enabled) {
33
- throw new Error('NPM tokens are not enabled');
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: 'npm',
41
+ type: protocol,
39
42
  userId,
40
- scopes: readonly ? ['npm:*:*:read'] : ['npm:*:*:*'],
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
- * Validate any token (NPM or OCI)
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 NPM token first (UUID format)
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 NPM protocols
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';