@push.rocks/smartregistry 2.2.0 → 2.2.2
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/composer/classes.composerregistry.js +8 -5
- package/dist_ts/core/classes.authmanager.d.ts +22 -1
- package/dist_ts/core/classes.authmanager.js +85 -132
- package/dist_ts/core/helpers.buffer.d.ts +18 -0
- package/dist_ts/core/helpers.buffer.js +33 -0
- package/dist_ts/maven/classes.mavenregistry.js +3 -2
- package/dist_ts/npm/classes.npmregistry.js +9 -9
- package/dist_ts/oci/classes.ociregistry.js +2 -2
- package/dist_ts/pypi/classes.pypiregistry.js +5 -3
- package/dist_ts/rubygems/helpers.rubygems.js +3 -4
- package/package.json +1 -1
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/composer/classes.composerregistry.ts +8 -4
- package/ts/core/classes.authmanager.ts +95 -153
- package/ts/core/helpers.buffer.ts +34 -0
- package/ts/maven/classes.mavenregistry.ts +2 -1
- package/ts/npm/classes.npmregistry.ts +8 -8
- package/ts/oci/classes.ociregistry.ts +1 -1
- package/ts/pypi/classes.pypiregistry.ts +4 -2
- package/ts/rubygems/helpers.rubygems.ts +2 -3
|
@@ -52,37 +52,40 @@ export class AuthManager {
|
|
|
52
52
|
return token;
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
// ========================================================================
|
|
56
|
-
// NPM AUTHENTICATION
|
|
57
|
-
// ========================================================================
|
|
58
|
-
|
|
59
55
|
/**
|
|
60
|
-
*
|
|
56
|
+
* Generic protocol token creation (internal helper)
|
|
61
57
|
* @param userId - User ID
|
|
58
|
+
* @param protocol - Protocol type (npm, maven, composer, etc.)
|
|
62
59
|
* @param readonly - Whether the token is readonly
|
|
63
|
-
* @returns
|
|
60
|
+
* @returns UUID token string
|
|
64
61
|
*/
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
const scopes = readonly
|
|
71
|
-
|
|
62
|
+
private async createProtocolToken(
|
|
63
|
+
userId: string,
|
|
64
|
+
protocol: TRegistryProtocol,
|
|
65
|
+
readonly: boolean
|
|
66
|
+
): Promise<string> {
|
|
67
|
+
const scopes = readonly
|
|
68
|
+
? [`${protocol}:*:*:read`]
|
|
69
|
+
: [`${protocol}:*:*:*`];
|
|
70
|
+
return this.createUuidToken(userId, protocol, scopes, readonly);
|
|
72
71
|
}
|
|
73
72
|
|
|
74
73
|
/**
|
|
75
|
-
*
|
|
76
|
-
* @param token -
|
|
74
|
+
* Generic protocol token validation (internal helper)
|
|
75
|
+
* @param token - UUID token string
|
|
76
|
+
* @param protocol - Expected protocol type
|
|
77
77
|
* @returns Auth token object or null
|
|
78
78
|
*/
|
|
79
|
-
|
|
79
|
+
private async validateProtocolToken(
|
|
80
|
+
token: string,
|
|
81
|
+
protocol: TRegistryProtocol
|
|
82
|
+
): Promise<IAuthToken | null> {
|
|
80
83
|
if (!this.isValidUuid(token)) {
|
|
81
84
|
return null;
|
|
82
85
|
}
|
|
83
86
|
|
|
84
87
|
const authToken = this.tokenStore.get(token);
|
|
85
|
-
if (!authToken || authToken.type !==
|
|
88
|
+
if (!authToken || authToken.type !== protocol) {
|
|
86
89
|
return null;
|
|
87
90
|
}
|
|
88
91
|
|
|
@@ -95,12 +98,46 @@ export class AuthManager {
|
|
|
95
98
|
return authToken;
|
|
96
99
|
}
|
|
97
100
|
|
|
101
|
+
/**
|
|
102
|
+
* Generic protocol token revocation (internal helper)
|
|
103
|
+
* @param token - UUID token string
|
|
104
|
+
*/
|
|
105
|
+
private async revokeProtocolToken(token: string): Promise<void> {
|
|
106
|
+
this.tokenStore.delete(token);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// ========================================================================
|
|
110
|
+
// NPM AUTHENTICATION
|
|
111
|
+
// ========================================================================
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Create an NPM token
|
|
115
|
+
* @param userId - User ID
|
|
116
|
+
* @param readonly - Whether the token is readonly
|
|
117
|
+
* @returns NPM UUID token
|
|
118
|
+
*/
|
|
119
|
+
public async createNpmToken(userId: string, readonly: boolean = false): Promise<string> {
|
|
120
|
+
if (!this.config.npmTokens.enabled) {
|
|
121
|
+
throw new Error('NPM tokens are not enabled');
|
|
122
|
+
}
|
|
123
|
+
return this.createProtocolToken(userId, 'npm', readonly);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Validate an NPM token
|
|
128
|
+
* @param token - NPM UUID token
|
|
129
|
+
* @returns Auth token object or null
|
|
130
|
+
*/
|
|
131
|
+
public async validateNpmToken(token: string): Promise<IAuthToken | null> {
|
|
132
|
+
return this.validateProtocolToken(token, 'npm');
|
|
133
|
+
}
|
|
134
|
+
|
|
98
135
|
/**
|
|
99
136
|
* Revoke an NPM token
|
|
100
137
|
* @param token - NPM UUID token
|
|
101
138
|
*/
|
|
102
139
|
public async revokeNpmToken(token: string): Promise<void> {
|
|
103
|
-
this.
|
|
140
|
+
return this.revokeProtocolToken(token);
|
|
104
141
|
}
|
|
105
142
|
|
|
106
143
|
/**
|
|
@@ -265,8 +302,7 @@ export class AuthManager {
|
|
|
265
302
|
* @returns Maven UUID token
|
|
266
303
|
*/
|
|
267
304
|
public async createMavenToken(userId: string, readonly: boolean = false): Promise<string> {
|
|
268
|
-
|
|
269
|
-
return this.createUuidToken(userId, 'maven', scopes, readonly);
|
|
305
|
+
return this.createProtocolToken(userId, 'maven', readonly);
|
|
270
306
|
}
|
|
271
307
|
|
|
272
308
|
/**
|
|
@@ -275,22 +311,7 @@ export class AuthManager {
|
|
|
275
311
|
* @returns Auth token object or null
|
|
276
312
|
*/
|
|
277
313
|
public async validateMavenToken(token: string): Promise<IAuthToken | null> {
|
|
278
|
-
|
|
279
|
-
return null;
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
const authToken = this.tokenStore.get(token);
|
|
283
|
-
if (!authToken || authToken.type !== 'maven') {
|
|
284
|
-
return null;
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
// Check expiration if set
|
|
288
|
-
if (authToken.expiresAt && authToken.expiresAt < new Date()) {
|
|
289
|
-
this.tokenStore.delete(token);
|
|
290
|
-
return null;
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
return authToken;
|
|
314
|
+
return this.validateProtocolToken(token, 'maven');
|
|
294
315
|
}
|
|
295
316
|
|
|
296
317
|
/**
|
|
@@ -298,7 +319,7 @@ export class AuthManager {
|
|
|
298
319
|
* @param token - Maven UUID token
|
|
299
320
|
*/
|
|
300
321
|
public async revokeMavenToken(token: string): Promise<void> {
|
|
301
|
-
this.
|
|
322
|
+
return this.revokeProtocolToken(token);
|
|
302
323
|
}
|
|
303
324
|
|
|
304
325
|
// ========================================================================
|
|
@@ -312,8 +333,7 @@ export class AuthManager {
|
|
|
312
333
|
* @returns Composer UUID token
|
|
313
334
|
*/
|
|
314
335
|
public async createComposerToken(userId: string, readonly: boolean = false): Promise<string> {
|
|
315
|
-
|
|
316
|
-
return this.createUuidToken(userId, 'composer', scopes, readonly);
|
|
336
|
+
return this.createProtocolToken(userId, 'composer', readonly);
|
|
317
337
|
}
|
|
318
338
|
|
|
319
339
|
/**
|
|
@@ -322,22 +342,7 @@ export class AuthManager {
|
|
|
322
342
|
* @returns Auth token object or null
|
|
323
343
|
*/
|
|
324
344
|
public async validateComposerToken(token: string): Promise<IAuthToken | null> {
|
|
325
|
-
|
|
326
|
-
return null;
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
const authToken = this.tokenStore.get(token);
|
|
330
|
-
if (!authToken || authToken.type !== 'composer') {
|
|
331
|
-
return null;
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
// Check expiration if set
|
|
335
|
-
if (authToken.expiresAt && authToken.expiresAt < new Date()) {
|
|
336
|
-
this.tokenStore.delete(token);
|
|
337
|
-
return null;
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
return authToken;
|
|
345
|
+
return this.validateProtocolToken(token, 'composer');
|
|
341
346
|
}
|
|
342
347
|
|
|
343
348
|
/**
|
|
@@ -345,7 +350,7 @@ export class AuthManager {
|
|
|
345
350
|
* @param token - Composer UUID token
|
|
346
351
|
*/
|
|
347
352
|
public async revokeComposerToken(token: string): Promise<void> {
|
|
348
|
-
this.
|
|
353
|
+
return this.revokeProtocolToken(token);
|
|
349
354
|
}
|
|
350
355
|
|
|
351
356
|
// ========================================================================
|
|
@@ -359,8 +364,7 @@ export class AuthManager {
|
|
|
359
364
|
* @returns Cargo UUID token
|
|
360
365
|
*/
|
|
361
366
|
public async createCargoToken(userId: string, readonly: boolean = false): Promise<string> {
|
|
362
|
-
|
|
363
|
-
return this.createUuidToken(userId, 'cargo', scopes, readonly);
|
|
367
|
+
return this.createProtocolToken(userId, 'cargo', readonly);
|
|
364
368
|
}
|
|
365
369
|
|
|
366
370
|
/**
|
|
@@ -369,22 +373,7 @@ export class AuthManager {
|
|
|
369
373
|
* @returns Auth token object or null
|
|
370
374
|
*/
|
|
371
375
|
public async validateCargoToken(token: string): Promise<IAuthToken | null> {
|
|
372
|
-
|
|
373
|
-
return null;
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
const authToken = this.tokenStore.get(token);
|
|
377
|
-
if (!authToken || authToken.type !== 'cargo') {
|
|
378
|
-
return null;
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
// Check expiration if set
|
|
382
|
-
if (authToken.expiresAt && authToken.expiresAt < new Date()) {
|
|
383
|
-
this.tokenStore.delete(token);
|
|
384
|
-
return null;
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
return authToken;
|
|
376
|
+
return this.validateProtocolToken(token, 'cargo');
|
|
388
377
|
}
|
|
389
378
|
|
|
390
379
|
/**
|
|
@@ -392,7 +381,7 @@ export class AuthManager {
|
|
|
392
381
|
* @param token - Cargo UUID token
|
|
393
382
|
*/
|
|
394
383
|
public async revokeCargoToken(token: string): Promise<void> {
|
|
395
|
-
this.
|
|
384
|
+
return this.revokeProtocolToken(token);
|
|
396
385
|
}
|
|
397
386
|
|
|
398
387
|
// ========================================================================
|
|
@@ -406,8 +395,7 @@ export class AuthManager {
|
|
|
406
395
|
* @returns PyPI UUID token
|
|
407
396
|
*/
|
|
408
397
|
public async createPypiToken(userId: string, readonly: boolean = false): Promise<string> {
|
|
409
|
-
|
|
410
|
-
return this.createUuidToken(userId, 'pypi', scopes, readonly);
|
|
398
|
+
return this.createProtocolToken(userId, 'pypi', readonly);
|
|
411
399
|
}
|
|
412
400
|
|
|
413
401
|
/**
|
|
@@ -416,22 +404,7 @@ export class AuthManager {
|
|
|
416
404
|
* @returns Auth token object or null
|
|
417
405
|
*/
|
|
418
406
|
public async validatePypiToken(token: string): Promise<IAuthToken | null> {
|
|
419
|
-
|
|
420
|
-
return null;
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
const authToken = this.tokenStore.get(token);
|
|
424
|
-
if (!authToken || authToken.type !== 'pypi') {
|
|
425
|
-
return null;
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
// Check expiration if set
|
|
429
|
-
if (authToken.expiresAt && authToken.expiresAt < new Date()) {
|
|
430
|
-
this.tokenStore.delete(token);
|
|
431
|
-
return null;
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
return authToken;
|
|
407
|
+
return this.validateProtocolToken(token, 'pypi');
|
|
435
408
|
}
|
|
436
409
|
|
|
437
410
|
/**
|
|
@@ -439,7 +412,7 @@ export class AuthManager {
|
|
|
439
412
|
* @param token - PyPI UUID token
|
|
440
413
|
*/
|
|
441
414
|
public async revokePypiToken(token: string): Promise<void> {
|
|
442
|
-
this.
|
|
415
|
+
return this.revokeProtocolToken(token);
|
|
443
416
|
}
|
|
444
417
|
|
|
445
418
|
// ========================================================================
|
|
@@ -453,8 +426,7 @@ export class AuthManager {
|
|
|
453
426
|
* @returns RubyGems UUID token
|
|
454
427
|
*/
|
|
455
428
|
public async createRubyGemsToken(userId: string, readonly: boolean = false): Promise<string> {
|
|
456
|
-
|
|
457
|
-
return this.createUuidToken(userId, 'rubygems', scopes, readonly);
|
|
429
|
+
return this.createProtocolToken(userId, 'rubygems', readonly);
|
|
458
430
|
}
|
|
459
431
|
|
|
460
432
|
/**
|
|
@@ -463,22 +435,7 @@ export class AuthManager {
|
|
|
463
435
|
* @returns Auth token object or null
|
|
464
436
|
*/
|
|
465
437
|
public async validateRubyGemsToken(token: string): Promise<IAuthToken | null> {
|
|
466
|
-
|
|
467
|
-
return null;
|
|
468
|
-
}
|
|
469
|
-
|
|
470
|
-
const authToken = this.tokenStore.get(token);
|
|
471
|
-
if (!authToken || authToken.type !== 'rubygems') {
|
|
472
|
-
return null;
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
// Check expiration if set
|
|
476
|
-
if (authToken.expiresAt && authToken.expiresAt < new Date()) {
|
|
477
|
-
this.tokenStore.delete(token);
|
|
478
|
-
return null;
|
|
479
|
-
}
|
|
480
|
-
|
|
481
|
-
return authToken;
|
|
438
|
+
return this.validateProtocolToken(token, 'rubygems');
|
|
482
439
|
}
|
|
483
440
|
|
|
484
441
|
/**
|
|
@@ -486,7 +443,7 @@ export class AuthManager {
|
|
|
486
443
|
* @param token - RubyGems UUID token
|
|
487
444
|
*/
|
|
488
445
|
public async revokeRubyGemsToken(token: string): Promise<void> {
|
|
489
|
-
this.
|
|
446
|
+
return this.revokeProtocolToken(token);
|
|
490
447
|
}
|
|
491
448
|
|
|
492
449
|
// ========================================================================
|
|
@@ -495,57 +452,42 @@ export class AuthManager {
|
|
|
495
452
|
|
|
496
453
|
/**
|
|
497
454
|
* Validate any token (NPM, Maven, OCI, PyPI, RubyGems, Composer, Cargo)
|
|
455
|
+
* Optimized: O(1) lookup when protocol hint provided
|
|
498
456
|
* @param tokenString - Token string (UUID or JWT)
|
|
499
|
-
* @param protocol - Expected protocol type
|
|
457
|
+
* @param protocol - Expected protocol type (optional, improves performance)
|
|
500
458
|
* @returns Auth token object or null
|
|
501
459
|
*/
|
|
502
460
|
public async validateToken(
|
|
503
461
|
tokenString: string,
|
|
504
462
|
protocol?: TRegistryProtocol
|
|
505
463
|
): Promise<IAuthToken | null> {
|
|
506
|
-
//
|
|
507
|
-
if (
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
return npmToken;
|
|
512
|
-
}
|
|
513
|
-
|
|
514
|
-
// Try Maven token
|
|
515
|
-
const mavenToken = await this.validateMavenToken(tokenString);
|
|
516
|
-
if (mavenToken && (!protocol || protocol === 'maven')) {
|
|
517
|
-
return mavenToken;
|
|
518
|
-
}
|
|
519
|
-
|
|
520
|
-
// Try Composer token
|
|
521
|
-
const composerToken = await this.validateComposerToken(tokenString);
|
|
522
|
-
if (composerToken && (!protocol || protocol === 'composer')) {
|
|
523
|
-
return composerToken;
|
|
524
|
-
}
|
|
525
|
-
|
|
526
|
-
// Try Cargo token
|
|
527
|
-
const cargoToken = await this.validateCargoToken(tokenString);
|
|
528
|
-
if (cargoToken && (!protocol || protocol === 'cargo')) {
|
|
529
|
-
return cargoToken;
|
|
530
|
-
}
|
|
531
|
-
|
|
532
|
-
// Try PyPI token
|
|
533
|
-
const pypiToken = await this.validatePypiToken(tokenString);
|
|
534
|
-
if (pypiToken && (!protocol || protocol === 'pypi')) {
|
|
535
|
-
return pypiToken;
|
|
464
|
+
// OCI uses JWT (contains dots), not UUID - check first if OCI is expected
|
|
465
|
+
if (protocol === 'oci' || tokenString.includes('.')) {
|
|
466
|
+
const ociToken = await this.validateOciToken(tokenString);
|
|
467
|
+
if (ociToken && (!protocol || protocol === 'oci')) {
|
|
468
|
+
return ociToken;
|
|
536
469
|
}
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
if (rubygemsToken && (!protocol || protocol === 'rubygems')) {
|
|
541
|
-
return rubygemsToken;
|
|
470
|
+
// If protocol was explicitly OCI but validation failed, return null
|
|
471
|
+
if (protocol === 'oci') {
|
|
472
|
+
return null;
|
|
542
473
|
}
|
|
543
474
|
}
|
|
544
475
|
|
|
545
|
-
//
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
476
|
+
// UUID-based tokens: single O(1) Map lookup
|
|
477
|
+
if (this.isValidUuid(tokenString)) {
|
|
478
|
+
const authToken = this.tokenStore.get(tokenString);
|
|
479
|
+
if (authToken) {
|
|
480
|
+
// If protocol specified, verify it matches
|
|
481
|
+
if (protocol && authToken.type !== protocol) {
|
|
482
|
+
return null;
|
|
483
|
+
}
|
|
484
|
+
// Check expiration
|
|
485
|
+
if (authToken.expiresAt && authToken.expiresAt < new Date()) {
|
|
486
|
+
this.tokenStore.delete(tokenString);
|
|
487
|
+
return null;
|
|
488
|
+
}
|
|
489
|
+
return authToken;
|
|
490
|
+
}
|
|
549
491
|
}
|
|
550
492
|
|
|
551
493
|
return null;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared buffer utilities for consistent binary data handling across all registry types.
|
|
3
|
+
*
|
|
4
|
+
* This module addresses the common issue where `Buffer.isBuffer(Uint8Array)` returns `false`,
|
|
5
|
+
* which can cause data handling bugs when binary data arrives as Uint8Array instead of Buffer.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Check if value is binary data (Buffer or Uint8Array)
|
|
10
|
+
*/
|
|
11
|
+
export function isBinaryData(value: unknown): value is Buffer | Uint8Array {
|
|
12
|
+
return Buffer.isBuffer(value) || value instanceof Uint8Array;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Convert any binary-like data to Buffer.
|
|
17
|
+
* Handles Buffer, Uint8Array, string, and objects.
|
|
18
|
+
*
|
|
19
|
+
* @param data - The data to convert to Buffer
|
|
20
|
+
* @returns A Buffer containing the data
|
|
21
|
+
*/
|
|
22
|
+
export function toBuffer(data: unknown): Buffer {
|
|
23
|
+
if (Buffer.isBuffer(data)) {
|
|
24
|
+
return data;
|
|
25
|
+
}
|
|
26
|
+
if (data instanceof Uint8Array) {
|
|
27
|
+
return Buffer.from(data);
|
|
28
|
+
}
|
|
29
|
+
if (typeof data === 'string') {
|
|
30
|
+
return Buffer.from(data, 'utf-8');
|
|
31
|
+
}
|
|
32
|
+
// Fallback: serialize object to JSON
|
|
33
|
+
return Buffer.from(JSON.stringify(data));
|
|
34
|
+
}
|
|
@@ -7,6 +7,7 @@ import { BaseRegistry } from '../core/classes.baseregistry.js';
|
|
|
7
7
|
import type { RegistryStorage } from '../core/classes.registrystorage.js';
|
|
8
8
|
import type { AuthManager } from '../core/classes.authmanager.js';
|
|
9
9
|
import type { IRequestContext, IResponse, IAuthToken } from '../core/interfaces.core.js';
|
|
10
|
+
import { toBuffer } from '../core/helpers.buffer.js';
|
|
10
11
|
import type { IMavenCoordinate, IMavenMetadata, IChecksums } from './interfaces.maven.js';
|
|
11
12
|
import {
|
|
12
13
|
pathToGAV,
|
|
@@ -296,7 +297,7 @@ export class MavenRegistry extends BaseRegistry {
|
|
|
296
297
|
coordinate: IMavenCoordinate,
|
|
297
298
|
body: Buffer | any
|
|
298
299
|
): Promise<IResponse> {
|
|
299
|
-
const data =
|
|
300
|
+
const data = toBuffer(body);
|
|
300
301
|
|
|
301
302
|
// Validate POM if uploading .pom file
|
|
302
303
|
if (coordinate.extension === 'pom') {
|
|
@@ -113,7 +113,7 @@ export class NpmRegistry extends BaseRegistry {
|
|
|
113
113
|
const unpublishVersionMatch = path.match(/^\/(@?[^\/]+(?:\/[^\/]+)?)\/-\/([^\/]+)$/);
|
|
114
114
|
if (unpublishVersionMatch && context.method === 'DELETE') {
|
|
115
115
|
const [, packageName, version] = unpublishVersionMatch;
|
|
116
|
-
|
|
116
|
+
this.logger.log('debug', 'unpublishVersionMatch', { packageName, version });
|
|
117
117
|
return this.unpublishVersion(packageName, version, token);
|
|
118
118
|
}
|
|
119
119
|
|
|
@@ -121,7 +121,7 @@ export class NpmRegistry extends BaseRegistry {
|
|
|
121
121
|
const unpublishPackageMatch = path.match(/^\/(@?[^\/]+(?:\/[^\/]+)?)\/-rev\/([^\/]+)$/);
|
|
122
122
|
if (unpublishPackageMatch && context.method === 'DELETE') {
|
|
123
123
|
const [, packageName, rev] = unpublishPackageMatch;
|
|
124
|
-
|
|
124
|
+
this.logger.log('debug', 'unpublishPackageMatch', { packageName, rev });
|
|
125
125
|
return this.unpublishPackage(packageName, token);
|
|
126
126
|
}
|
|
127
127
|
|
|
@@ -129,7 +129,7 @@ export class NpmRegistry extends BaseRegistry {
|
|
|
129
129
|
const versionMatch = path.match(/^\/(@?[^\/]+(?:\/[^\/]+)?)\/([^\/]+)$/);
|
|
130
130
|
if (versionMatch) {
|
|
131
131
|
const [, packageName, version] = versionMatch;
|
|
132
|
-
|
|
132
|
+
this.logger.log('debug', 'versionMatch', { packageName, version });
|
|
133
133
|
return this.handlePackageVersion(packageName, version, token);
|
|
134
134
|
}
|
|
135
135
|
|
|
@@ -137,7 +137,7 @@ export class NpmRegistry extends BaseRegistry {
|
|
|
137
137
|
const packageMatch = path.match(/^\/(@?[^\/]+(?:\/[^\/]+)?)$/);
|
|
138
138
|
if (packageMatch) {
|
|
139
139
|
const packageName = packageMatch[1];
|
|
140
|
-
|
|
140
|
+
this.logger.log('debug', 'packageMatch', { packageName });
|
|
141
141
|
return this.handlePackage(context.method, packageName, context.body, context.query, token);
|
|
142
142
|
}
|
|
143
143
|
|
|
@@ -254,11 +254,11 @@ export class NpmRegistry extends BaseRegistry {
|
|
|
254
254
|
version: string,
|
|
255
255
|
token: IAuthToken | null
|
|
256
256
|
): Promise<IResponse> {
|
|
257
|
-
|
|
257
|
+
this.logger.log('debug', 'handlePackageVersion', { packageName, version });
|
|
258
258
|
const packument = await this.storage.getNpmPackument(packageName);
|
|
259
|
-
|
|
259
|
+
this.logger.log('debug', 'handlePackageVersion packument', { found: !!packument });
|
|
260
260
|
if (packument) {
|
|
261
|
-
|
|
261
|
+
this.logger.log('debug', 'handlePackageVersion versions', { versions: Object.keys(packument.versions || {}) });
|
|
262
262
|
}
|
|
263
263
|
if (!packument) {
|
|
264
264
|
return {
|
|
@@ -621,7 +621,7 @@ export class NpmRegistry extends BaseRegistry {
|
|
|
621
621
|
}
|
|
622
622
|
}
|
|
623
623
|
} catch (error) {
|
|
624
|
-
|
|
624
|
+
this.logger.log('error', 'handleSearch failed', { error: (error as Error).message });
|
|
625
625
|
}
|
|
626
626
|
|
|
627
627
|
// Apply pagination
|
|
@@ -738,7 +738,7 @@ export class OciRegistry extends BaseRegistry {
|
|
|
738
738
|
}
|
|
739
739
|
|
|
740
740
|
private generateUploadId(): string {
|
|
741
|
-
return `${Date.now()}-${Math.random().toString(36).
|
|
741
|
+
return `${Date.now()}-${Math.random().toString(36).substring(2, 11)}`;
|
|
742
742
|
}
|
|
743
743
|
|
|
744
744
|
private async calculateDigest(data: Buffer): Promise<string> {
|
|
@@ -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 { isBinaryData, toBuffer } from '../core/helpers.buffer.js';
|
|
6
7
|
import type {
|
|
7
8
|
IPypiPackageMetadata,
|
|
8
9
|
IPypiFile,
|
|
@@ -328,8 +329,9 @@ export class PypiRegistry extends BaseRegistry {
|
|
|
328
329
|
const version = formData.version;
|
|
329
330
|
// Support both: formData.content.filename (multipart parsed) and formData.filename (flat)
|
|
330
331
|
const filename = formData.content?.filename || formData.filename;
|
|
331
|
-
// Support both: formData.content.data (multipart parsed) and formData.content (Buffer directly)
|
|
332
|
-
const
|
|
332
|
+
// Support both: formData.content.data (multipart parsed) and formData.content (Buffer/Uint8Array directly)
|
|
333
|
+
const rawContent = formData.content?.data || (isBinaryData(formData.content) ? formData.content : null);
|
|
334
|
+
const fileData = rawContent ? toBuffer(rawContent) : null;
|
|
333
335
|
const filetype = formData.filetype; // 'bdist_wheel' or 'sdist'
|
|
334
336
|
const pyversion = formData.pyversion;
|
|
335
337
|
|
|
@@ -455,9 +455,8 @@ export async function extractGemMetadata(gemData: Buffer): Promise<{
|
|
|
455
455
|
}
|
|
456
456
|
|
|
457
457
|
return null;
|
|
458
|
-
} catch (
|
|
459
|
-
//
|
|
460
|
-
console.error('Failed to extract gem metadata:', error);
|
|
458
|
+
} catch (_error) {
|
|
459
|
+
// Error handled gracefully - return null and let caller handle missing metadata
|
|
461
460
|
return null;
|
|
462
461
|
}
|
|
463
462
|
}
|