@push.rocks/smartregistry 1.1.1

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 (52) hide show
  1. package/dist_ts/00_commitinfo_data.d.ts +8 -0
  2. package/dist_ts/00_commitinfo_data.js +9 -0
  3. package/dist_ts/classes.smartregistry.d.ts +45 -0
  4. package/dist_ts/classes.smartregistry.js +113 -0
  5. package/dist_ts/core/classes.authmanager.d.ts +108 -0
  6. package/dist_ts/core/classes.authmanager.js +315 -0
  7. package/dist_ts/core/classes.baseregistry.d.ts +28 -0
  8. package/dist_ts/core/classes.baseregistry.js +6 -0
  9. package/dist_ts/core/classes.registrystorage.d.ts +109 -0
  10. package/dist_ts/core/classes.registrystorage.js +226 -0
  11. package/dist_ts/core/index.d.ts +7 -0
  12. package/dist_ts/core/index.js +10 -0
  13. package/dist_ts/core/interfaces.core.d.ts +142 -0
  14. package/dist_ts/core/interfaces.core.js +5 -0
  15. package/dist_ts/index.d.ts +8 -0
  16. package/dist_ts/index.js +13 -0
  17. package/dist_ts/npm/classes.npmregistry.d.ts +36 -0
  18. package/dist_ts/npm/classes.npmregistry.js +717 -0
  19. package/dist_ts/npm/index.d.ts +5 -0
  20. package/dist_ts/npm/index.js +6 -0
  21. package/dist_ts/npm/interfaces.npm.d.ts +245 -0
  22. package/dist_ts/npm/interfaces.npm.js +6 -0
  23. package/dist_ts/oci/classes.ociregistry.d.ts +43 -0
  24. package/dist_ts/oci/classes.ociregistry.js +565 -0
  25. package/dist_ts/oci/index.d.ts +5 -0
  26. package/dist_ts/oci/index.js +6 -0
  27. package/dist_ts/oci/interfaces.oci.d.ts +103 -0
  28. package/dist_ts/oci/interfaces.oci.js +5 -0
  29. package/dist_ts/paths.d.ts +1 -0
  30. package/dist_ts/paths.js +3 -0
  31. package/dist_ts/plugins.d.ts +6 -0
  32. package/dist_ts/plugins.js +9 -0
  33. package/npmextra.json +18 -0
  34. package/package.json +49 -0
  35. package/readme.hints.md +3 -0
  36. package/readme.md +486 -0
  37. package/ts/00_commitinfo_data.ts +8 -0
  38. package/ts/classes.smartregistry.ts +129 -0
  39. package/ts/core/classes.authmanager.ts +388 -0
  40. package/ts/core/classes.baseregistry.ts +36 -0
  41. package/ts/core/classes.registrystorage.ts +270 -0
  42. package/ts/core/index.ts +11 -0
  43. package/ts/core/interfaces.core.ts +159 -0
  44. package/ts/index.ts +16 -0
  45. package/ts/npm/classes.npmregistry.ts +890 -0
  46. package/ts/npm/index.ts +6 -0
  47. package/ts/npm/interfaces.npm.ts +263 -0
  48. package/ts/oci/classes.ociregistry.ts +734 -0
  49. package/ts/oci/index.ts +6 -0
  50. package/ts/oci/interfaces.oci.ts +101 -0
  51. package/ts/paths.ts +5 -0
  52. package/ts/plugins.ts +11 -0
@@ -0,0 +1,717 @@
1
+ import { Smartlog } from '@push.rocks/smartlog';
2
+ import { BaseRegistry } from '../core/classes.baseregistry.js';
3
+ import { RegistryStorage } from '../core/classes.registrystorage.js';
4
+ import { AuthManager } from '../core/classes.authmanager.js';
5
+ /**
6
+ * NPM Registry implementation
7
+ * Compliant with npm registry API
8
+ */
9
+ export class NpmRegistry extends BaseRegistry {
10
+ storage;
11
+ authManager;
12
+ basePath = '/npm';
13
+ registryUrl;
14
+ logger;
15
+ constructor(storage, authManager, basePath = '/npm', registryUrl = 'http://localhost:5000/npm') {
16
+ super();
17
+ this.storage = storage;
18
+ this.authManager = authManager;
19
+ this.basePath = basePath;
20
+ this.registryUrl = registryUrl;
21
+ // Initialize logger
22
+ this.logger = new Smartlog({
23
+ logContext: {
24
+ company: 'push.rocks',
25
+ companyunit: 'smartregistry',
26
+ containerName: 'npm-registry',
27
+ environment: process.env.NODE_ENV || 'development',
28
+ runtime: 'node',
29
+ zone: 'npm'
30
+ }
31
+ });
32
+ this.logger.enableConsole();
33
+ }
34
+ async init() {
35
+ // NPM registry initialization
36
+ }
37
+ getBasePath() {
38
+ return this.basePath;
39
+ }
40
+ async handleRequest(context) {
41
+ const path = context.path.replace(this.basePath, '');
42
+ // Extract token from Authorization header
43
+ const authHeader = context.headers['authorization'] || context.headers['Authorization'];
44
+ const tokenString = authHeader?.replace(/^Bearer\s+/i, '');
45
+ const token = tokenString ? await this.authManager.validateToken(tokenString, 'npm') : null;
46
+ this.logger.log('debug', `handleRequest: ${context.method} ${path}`, {
47
+ method: context.method,
48
+ path,
49
+ hasAuth: !!token
50
+ });
51
+ // Registry root
52
+ if (path === '/' || path === '') {
53
+ return this.handleRegistryInfo();
54
+ }
55
+ // Search: /-/v1/search
56
+ if (path.startsWith('/-/v1/search')) {
57
+ return this.handleSearch(context.query);
58
+ }
59
+ // User authentication: /-/user/org.couchdb.user:{username}
60
+ const userMatch = path.match(/^\/-\/user\/org\.couchdb\.user:(.+)$/);
61
+ if (userMatch) {
62
+ return this.handleUserAuth(context.method, userMatch[1], context.body, token);
63
+ }
64
+ // Token operations: /-/npm/v1/tokens
65
+ if (path.startsWith('/-/npm/v1/tokens')) {
66
+ return this.handleTokens(context.method, path, context.body, token);
67
+ }
68
+ // Dist-tags: /-/package/{package}/dist-tags
69
+ const distTagsMatch = path.match(/^\/-\/package\/(@?[^\/]+(?:\/[^\/]+)?)\/dist-tags(?:\/(.+))?$/);
70
+ if (distTagsMatch) {
71
+ const [, packageName, tag] = distTagsMatch;
72
+ return this.handleDistTags(context.method, packageName, tag, context.body, token);
73
+ }
74
+ // Tarball download: /{package}/-/{filename}.tgz
75
+ const tarballMatch = path.match(/^\/(@?[^\/]+(?:\/[^\/]+)?)\/-\/(.+\.tgz)$/);
76
+ if (tarballMatch) {
77
+ const [, packageName, filename] = tarballMatch;
78
+ return this.handleTarballDownload(packageName, filename, token);
79
+ }
80
+ // Unpublish specific version: DELETE /{package}/-/{version}
81
+ const unpublishVersionMatch = path.match(/^\/(@?[^\/]+(?:\/[^\/]+)?)\/-\/([^\/]+)$/);
82
+ if (unpublishVersionMatch && context.method === 'DELETE') {
83
+ const [, packageName, version] = unpublishVersionMatch;
84
+ console.log(`[unpublishVersionMatch] packageName=${packageName}, version=${version}`);
85
+ return this.unpublishVersion(packageName, version, token);
86
+ }
87
+ // Unpublish entire package: DELETE /{package}/-rev/{rev}
88
+ const unpublishPackageMatch = path.match(/^\/(@?[^\/]+(?:\/[^\/]+)?)\/-rev\/([^\/]+)$/);
89
+ if (unpublishPackageMatch && context.method === 'DELETE') {
90
+ const [, packageName, rev] = unpublishPackageMatch;
91
+ console.log(`[unpublishPackageMatch] packageName=${packageName}, rev=${rev}`);
92
+ return this.unpublishPackage(packageName, token);
93
+ }
94
+ // Package version: /{package}/{version}
95
+ const versionMatch = path.match(/^\/(@?[^\/]+(?:\/[^\/]+)?)\/([^\/]+)$/);
96
+ if (versionMatch) {
97
+ const [, packageName, version] = versionMatch;
98
+ console.log(`[versionMatch] matched! packageName=${packageName}, version=${version}`);
99
+ return this.handlePackageVersion(packageName, version, token);
100
+ }
101
+ // Package operations: /{package}
102
+ const packageMatch = path.match(/^\/(@?[^\/]+(?:\/[^\/]+)?)$/);
103
+ if (packageMatch) {
104
+ const packageName = packageMatch[1];
105
+ console.log(`[packageMatch] matched! packageName=${packageName}`);
106
+ return this.handlePackage(context.method, packageName, context.body, context.query, token);
107
+ }
108
+ return {
109
+ status: 404,
110
+ headers: { 'Content-Type': 'application/json' },
111
+ body: this.createError('E404', 'Not found'),
112
+ };
113
+ }
114
+ async checkPermission(token, resource, action) {
115
+ if (!token)
116
+ return false;
117
+ return this.authManager.authorize(token, `npm:package:${resource}`, action);
118
+ }
119
+ // ========================================================================
120
+ // REQUEST HANDLERS
121
+ // ========================================================================
122
+ handleRegistryInfo() {
123
+ return {
124
+ status: 200,
125
+ headers: { 'Content-Type': 'application/json' },
126
+ body: {
127
+ db_name: 'registry',
128
+ doc_count: 0,
129
+ doc_del_count: 0,
130
+ update_seq: 0,
131
+ purge_seq: 0,
132
+ compact_running: false,
133
+ disk_size: 0,
134
+ data_size: 0,
135
+ instance_start_time: Date.now().toString(),
136
+ disk_format_version: 0,
137
+ committed_update_seq: 0,
138
+ },
139
+ };
140
+ }
141
+ async handlePackage(method, packageName, body, query, token) {
142
+ switch (method) {
143
+ case 'GET':
144
+ return this.getPackument(packageName, token, query);
145
+ case 'PUT':
146
+ return this.publishPackage(packageName, body, token);
147
+ case 'DELETE':
148
+ return this.unpublishPackage(packageName, token);
149
+ default:
150
+ return {
151
+ status: 405,
152
+ headers: {},
153
+ body: this.createError('EBADREQUEST', 'Method not allowed'),
154
+ };
155
+ }
156
+ }
157
+ async getPackument(packageName, token, query) {
158
+ const packument = await this.storage.getNpmPackument(packageName);
159
+ this.logger.log('debug', `getPackument: ${packageName}`, {
160
+ packageName,
161
+ found: !!packument,
162
+ versions: packument ? Object.keys(packument.versions).length : 0
163
+ });
164
+ if (!packument) {
165
+ return {
166
+ status: 404,
167
+ headers: { 'Content-Type': 'application/json' },
168
+ body: this.createError('E404', `Package '${packageName}' not found`),
169
+ };
170
+ }
171
+ // Check if abbreviated version requested
172
+ const accept = query['accept'] || '';
173
+ if (accept.includes('application/vnd.npm.install-v1+json')) {
174
+ // Return abbreviated packument
175
+ const abbreviated = {
176
+ name: packument.name,
177
+ modified: packument.time?.modified || new Date().toISOString(),
178
+ 'dist-tags': packument['dist-tags'],
179
+ versions: packument.versions,
180
+ };
181
+ return {
182
+ status: 200,
183
+ headers: { 'Content-Type': 'application/vnd.npm.install-v1+json' },
184
+ body: abbreviated,
185
+ };
186
+ }
187
+ return {
188
+ status: 200,
189
+ headers: { 'Content-Type': 'application/json' },
190
+ body: packument,
191
+ };
192
+ }
193
+ async handlePackageVersion(packageName, version, token) {
194
+ console.log(`[handlePackageVersion] packageName=${packageName}, version=${version}`);
195
+ const packument = await this.storage.getNpmPackument(packageName);
196
+ console.log(`[handlePackageVersion] packument found:`, !!packument);
197
+ if (packument) {
198
+ console.log(`[handlePackageVersion] versions:`, Object.keys(packument.versions || {}));
199
+ }
200
+ if (!packument) {
201
+ return {
202
+ status: 404,
203
+ headers: { 'Content-Type': 'application/json' },
204
+ body: this.createError('E404', 'Package not found'),
205
+ };
206
+ }
207
+ // Resolve version (could be "latest" or actual version)
208
+ let actualVersion = version;
209
+ if (version === 'latest') {
210
+ actualVersion = packument['dist-tags']?.latest;
211
+ if (!actualVersion) {
212
+ return {
213
+ status: 404,
214
+ headers: {},
215
+ body: this.createError('E404', 'No latest version'),
216
+ };
217
+ }
218
+ }
219
+ const versionData = packument.versions[actualVersion];
220
+ if (!versionData) {
221
+ return {
222
+ status: 404,
223
+ headers: {},
224
+ body: this.createError('E404', 'Version not found'),
225
+ };
226
+ }
227
+ return {
228
+ status: 200,
229
+ headers: { 'Content-Type': 'application/json' },
230
+ body: versionData,
231
+ };
232
+ }
233
+ async publishPackage(packageName, body, token) {
234
+ this.logger.log('info', `publishPackage: ${packageName}`, {
235
+ packageName,
236
+ versions: Object.keys(body.versions || {}),
237
+ hasAuth: !!token
238
+ });
239
+ const hasPermission = await this.checkPermission(token, packageName, 'write');
240
+ if (!hasPermission) {
241
+ this.logger.log('warn', `publishPackage: unauthorized`, { packageName, userId: token?.userId });
242
+ }
243
+ if (!hasPermission) {
244
+ return {
245
+ status: 401,
246
+ headers: {},
247
+ body: this.createError('EUNAUTHORIZED', 'Unauthorized'),
248
+ };
249
+ }
250
+ if (!body || !body.versions || !body._attachments) {
251
+ return {
252
+ status: 400,
253
+ headers: {},
254
+ body: this.createError('EBADREQUEST', 'Invalid publish request'),
255
+ };
256
+ }
257
+ // Get existing packument or create new one
258
+ let packument = await this.storage.getNpmPackument(packageName);
259
+ const isNew = !packument;
260
+ if (isNew) {
261
+ packument = {
262
+ _id: packageName,
263
+ name: packageName,
264
+ description: body.description,
265
+ 'dist-tags': body['dist-tags'] || { latest: Object.keys(body.versions)[0] },
266
+ versions: {},
267
+ time: {
268
+ created: new Date().toISOString(),
269
+ modified: new Date().toISOString(),
270
+ },
271
+ maintainers: body.maintainers || [],
272
+ readme: body.readme,
273
+ };
274
+ }
275
+ // Process each new version
276
+ for (const [version, versionData] of Object.entries(body.versions)) {
277
+ // Check if version already exists
278
+ if (packument.versions[version]) {
279
+ return {
280
+ status: 403,
281
+ headers: {},
282
+ body: this.createError('EPUBLISHCONFLICT', `Version ${version} already exists`),
283
+ };
284
+ }
285
+ // Find attachment for this version
286
+ const attachmentKey = Object.keys(body._attachments).find(key => key.includes(version));
287
+ if (!attachmentKey) {
288
+ return {
289
+ status: 400,
290
+ headers: {},
291
+ body: this.createError('EBADREQUEST', `No tarball for version ${version}`),
292
+ };
293
+ }
294
+ const attachment = body._attachments[attachmentKey];
295
+ // Decode base64 tarball
296
+ const tarballBuffer = Buffer.from(attachment.data, 'base64');
297
+ // Calculate shasum
298
+ const crypto = await import('crypto');
299
+ const shasum = crypto.createHash('sha1').update(tarballBuffer).digest('hex');
300
+ const integrity = `sha512-${crypto.createHash('sha512').update(tarballBuffer).digest('base64')}`;
301
+ // Store tarball
302
+ await this.storage.putNpmTarball(packageName, version, tarballBuffer);
303
+ // Update version data with dist info
304
+ const safeName = packageName.replace('@', '').replace('/', '-');
305
+ versionData.dist = {
306
+ tarball: `${this.registryUrl}/${packageName}/-/${safeName}-${version}.tgz`,
307
+ shasum,
308
+ integrity,
309
+ fileCount: 0,
310
+ unpackedSize: tarballBuffer.length,
311
+ };
312
+ versionData._id = `${packageName}@${version}`;
313
+ versionData._npmUser = token ? { name: token.userId, email: '' } : undefined;
314
+ // Add version to packument
315
+ packument.versions[version] = versionData;
316
+ if (packument.time) {
317
+ packument.time[version] = new Date().toISOString();
318
+ packument.time.modified = new Date().toISOString();
319
+ }
320
+ }
321
+ // Update dist-tags
322
+ if (body['dist-tags']) {
323
+ packument['dist-tags'] = { ...packument['dist-tags'], ...body['dist-tags'] };
324
+ }
325
+ // Save packument
326
+ await this.storage.putNpmPackument(packageName, packument);
327
+ this.logger.log('success', `publishPackage: saved ${packageName}`, {
328
+ packageName,
329
+ versions: Object.keys(packument.versions),
330
+ distTags: packument['dist-tags']
331
+ });
332
+ return {
333
+ status: 201,
334
+ headers: { 'Content-Type': 'application/json' },
335
+ body: { ok: true, id: packageName, rev: packument._rev || '1-' + Date.now() },
336
+ };
337
+ }
338
+ async unpublishVersion(packageName, version, token) {
339
+ if (!await this.checkPermission(token, packageName, 'delete')) {
340
+ return {
341
+ status: 401,
342
+ headers: {},
343
+ body: this.createError('EUNAUTHORIZED', 'Unauthorized'),
344
+ };
345
+ }
346
+ const packument = await this.storage.getNpmPackument(packageName);
347
+ if (!packument) {
348
+ return {
349
+ status: 404,
350
+ headers: {},
351
+ body: this.createError('E404', 'Package not found'),
352
+ };
353
+ }
354
+ // Check if version exists
355
+ if (!packument.versions[version]) {
356
+ return {
357
+ status: 404,
358
+ headers: {},
359
+ body: this.createError('E404', 'Version not found'),
360
+ };
361
+ }
362
+ // Delete tarball
363
+ await this.storage.deleteNpmTarball(packageName, version);
364
+ // Remove version from packument
365
+ delete packument.versions[version];
366
+ if (packument.time) {
367
+ delete packument.time[version];
368
+ packument.time.modified = new Date().toISOString();
369
+ }
370
+ // Update latest tag if this was the latest version
371
+ if (packument['dist-tags']?.latest === version) {
372
+ const remainingVersions = Object.keys(packument.versions);
373
+ if (remainingVersions.length > 0) {
374
+ packument['dist-tags'].latest = remainingVersions[remainingVersions.length - 1];
375
+ }
376
+ else {
377
+ delete packument['dist-tags'].latest;
378
+ }
379
+ }
380
+ // Save updated packument
381
+ await this.storage.putNpmPackument(packageName, packument);
382
+ return {
383
+ status: 200,
384
+ headers: { 'Content-Type': 'application/json' },
385
+ body: { ok: true },
386
+ };
387
+ }
388
+ async unpublishPackage(packageName, token) {
389
+ if (!await this.checkPermission(token, packageName, 'delete')) {
390
+ return {
391
+ status: 401,
392
+ headers: {},
393
+ body: this.createError('EUNAUTHORIZED', 'Unauthorized'),
394
+ };
395
+ }
396
+ const packument = await this.storage.getNpmPackument(packageName);
397
+ if (!packument) {
398
+ return {
399
+ status: 404,
400
+ headers: {},
401
+ body: this.createError('E404', 'Package not found'),
402
+ };
403
+ }
404
+ // Delete all tarballs
405
+ for (const version of Object.keys(packument.versions)) {
406
+ await this.storage.deleteNpmTarball(packageName, version);
407
+ }
408
+ // Delete packument
409
+ await this.storage.deleteNpmPackument(packageName);
410
+ return {
411
+ status: 200,
412
+ headers: { 'Content-Type': 'application/json' },
413
+ body: { ok: true },
414
+ };
415
+ }
416
+ async handleTarballDownload(packageName, filename, token) {
417
+ // Extract version from filename: package-name-1.0.0.tgz
418
+ const versionMatch = filename.match(/-([\d.]+(?:-[a-z0-9.]+)?)\.tgz$/);
419
+ if (!versionMatch) {
420
+ return {
421
+ status: 400,
422
+ headers: {},
423
+ body: this.createError('EBADREQUEST', 'Invalid tarball filename'),
424
+ };
425
+ }
426
+ const version = versionMatch[1];
427
+ const tarball = await this.storage.getNpmTarball(packageName, version);
428
+ if (!tarball) {
429
+ return {
430
+ status: 404,
431
+ headers: {},
432
+ body: this.createError('E404', 'Tarball not found'),
433
+ };
434
+ }
435
+ return {
436
+ status: 200,
437
+ headers: {
438
+ 'Content-Type': 'application/octet-stream',
439
+ 'Content-Length': tarball.length.toString(),
440
+ },
441
+ body: tarball,
442
+ };
443
+ }
444
+ async handleSearch(query) {
445
+ const text = query.text || '';
446
+ const size = parseInt(query.size || '20', 10);
447
+ const from = parseInt(query.from || '0', 10);
448
+ this.logger.log('debug', `handleSearch: query="${text}"`, { text, size, from });
449
+ // Simple search implementation
450
+ const results = [];
451
+ try {
452
+ // List all package paths
453
+ const packagePaths = await this.storage.listObjects('npm/packages/');
454
+ // Extract unique package names from paths (format: npm/packages/{packageName}/...)
455
+ const packageNames = new Set();
456
+ for (const path of packagePaths) {
457
+ const match = path.match(/^npm\/packages\/([^\/]+)\/index\.json$/);
458
+ if (match) {
459
+ packageNames.add(match[1]);
460
+ }
461
+ }
462
+ this.logger.log('debug', `handleSearch: found ${packageNames.size} packages`, {
463
+ totalPackages: packageNames.size,
464
+ pathsScanned: packagePaths.length
465
+ });
466
+ // Load packuments and filter by search text
467
+ for (const packageName of packageNames) {
468
+ if (!text || packageName.toLowerCase().includes(text.toLowerCase())) {
469
+ const packument = await this.storage.getNpmPackument(packageName);
470
+ if (packument) {
471
+ const latestVersion = packument['dist-tags']?.latest;
472
+ const versionData = latestVersion ? packument.versions[latestVersion] : null;
473
+ results.push({
474
+ package: {
475
+ name: packument.name,
476
+ version: latestVersion || '0.0.0',
477
+ description: packument.description || versionData?.description || '',
478
+ keywords: versionData?.keywords || [],
479
+ date: packument.time?.modified || new Date().toISOString(),
480
+ links: {},
481
+ author: versionData?.author || {},
482
+ publisher: versionData?._npmUser || {},
483
+ maintainers: packument.maintainers || [],
484
+ },
485
+ score: {
486
+ final: 1.0,
487
+ detail: {
488
+ quality: 1.0,
489
+ popularity: 1.0,
490
+ maintenance: 1.0,
491
+ },
492
+ },
493
+ searchScore: 1.0,
494
+ });
495
+ }
496
+ }
497
+ }
498
+ }
499
+ catch (error) {
500
+ console.error('[handleSearch] Error:', error);
501
+ }
502
+ // Apply pagination
503
+ const paginatedResults = results.slice(from, from + size);
504
+ const response = {
505
+ objects: paginatedResults,
506
+ total: results.length,
507
+ time: new Date().toISOString(),
508
+ };
509
+ return {
510
+ status: 200,
511
+ headers: { 'Content-Type': 'application/json' },
512
+ body: response,
513
+ };
514
+ }
515
+ async handleUserAuth(method, username, body, token) {
516
+ if (method !== 'PUT') {
517
+ return {
518
+ status: 405,
519
+ headers: {},
520
+ body: this.createError('EBADREQUEST', 'Method not allowed'),
521
+ };
522
+ }
523
+ if (!body || !body.name || !body.password) {
524
+ return {
525
+ status: 400,
526
+ headers: {},
527
+ body: this.createError('EBADREQUEST', 'Invalid request'),
528
+ };
529
+ }
530
+ // Authenticate user
531
+ const userId = await this.authManager.authenticate({
532
+ username: body.name,
533
+ password: body.password,
534
+ });
535
+ if (!userId) {
536
+ return {
537
+ status: 401,
538
+ headers: {},
539
+ body: this.createError('EUNAUTHORIZED', 'Invalid credentials'),
540
+ };
541
+ }
542
+ // Create NPM token
543
+ const npmToken = await this.authManager.createNpmToken(userId, false);
544
+ return {
545
+ status: 201,
546
+ headers: { 'Content-Type': 'application/json' },
547
+ body: {
548
+ ok: true,
549
+ id: `org.couchdb.user:${username}`,
550
+ rev: '1-' + Date.now(),
551
+ token: npmToken,
552
+ },
553
+ };
554
+ }
555
+ async handleTokens(method, path, body, token) {
556
+ if (!token) {
557
+ return {
558
+ status: 401,
559
+ headers: {},
560
+ body: this.createError('EUNAUTHORIZED', 'Unauthorized'),
561
+ };
562
+ }
563
+ // List tokens: GET /-/npm/v1/tokens
564
+ if (path === '/-/npm/v1/tokens' && method === 'GET') {
565
+ return this.listTokens(token);
566
+ }
567
+ // Create token: POST /-/npm/v1/tokens
568
+ if (path === '/-/npm/v1/tokens' && method === 'POST') {
569
+ return this.createToken(body, token);
570
+ }
571
+ // Delete token: DELETE /-/npm/v1/tokens/token/{key}
572
+ const deleteMatch = path.match(/^\/-\/npm\/v1\/tokens\/token\/(.+)$/);
573
+ if (deleteMatch && method === 'DELETE') {
574
+ return this.deleteToken(deleteMatch[1], token);
575
+ }
576
+ return {
577
+ status: 404,
578
+ headers: {},
579
+ body: this.createError('E404', 'Not found'),
580
+ };
581
+ }
582
+ async listTokens(token) {
583
+ const tokens = await this.authManager.listUserTokens(token.userId);
584
+ const response = {
585
+ objects: tokens.map(t => ({
586
+ token: '********',
587
+ key: t.key,
588
+ readonly: t.readonly,
589
+ created: t.created,
590
+ updated: t.created,
591
+ })),
592
+ total: tokens.length,
593
+ urls: {},
594
+ };
595
+ return {
596
+ status: 200,
597
+ headers: { 'Content-Type': 'application/json' },
598
+ body: response,
599
+ };
600
+ }
601
+ async createToken(body, token) {
602
+ if (!body || !body.password) {
603
+ return {
604
+ status: 400,
605
+ headers: {},
606
+ body: this.createError('EBADREQUEST', 'Password required'),
607
+ };
608
+ }
609
+ // Verify password (simplified - in production, verify against stored password)
610
+ const readonly = body.readonly || false;
611
+ const newToken = await this.authManager.createNpmToken(token.userId, readonly);
612
+ return {
613
+ status: 200,
614
+ headers: { 'Content-Type': 'application/json' },
615
+ body: {
616
+ token: newToken,
617
+ key: 'sha512-' + newToken.substring(0, 16) + '...',
618
+ cidr_whitelist: body.cidr_whitelist || [],
619
+ readonly,
620
+ created: new Date().toISOString(),
621
+ updated: new Date().toISOString(),
622
+ },
623
+ };
624
+ }
625
+ async deleteToken(key, token) {
626
+ // In production, lookup token by key hash and delete
627
+ return {
628
+ status: 200,
629
+ headers: { 'Content-Type': 'application/json' },
630
+ body: { ok: true },
631
+ };
632
+ }
633
+ async handleDistTags(method, packageName, tag, body, token) {
634
+ const packument = await this.storage.getNpmPackument(packageName);
635
+ if (!packument) {
636
+ return {
637
+ status: 404,
638
+ headers: {},
639
+ body: this.createError('E404', 'Package not found'),
640
+ };
641
+ }
642
+ // GET /-/package/{package}/dist-tags
643
+ if (method === 'GET' && !tag) {
644
+ return {
645
+ status: 200,
646
+ headers: { 'Content-Type': 'application/json' },
647
+ body: packument['dist-tags'] || {},
648
+ };
649
+ }
650
+ // PUT /-/package/{package}/dist-tags/{tag}
651
+ if (method === 'PUT' && tag) {
652
+ if (!await this.checkPermission(token, packageName, 'write')) {
653
+ return {
654
+ status: 401,
655
+ headers: {},
656
+ body: this.createError('EUNAUTHORIZED', 'Unauthorized'),
657
+ };
658
+ }
659
+ if (typeof body !== 'string') {
660
+ return {
661
+ status: 400,
662
+ headers: {},
663
+ body: this.createError('EBADREQUEST', 'Version string required'),
664
+ };
665
+ }
666
+ packument['dist-tags'] = packument['dist-tags'] || {};
667
+ packument['dist-tags'][tag] = body;
668
+ await this.storage.putNpmPackument(packageName, packument);
669
+ return {
670
+ status: 200,
671
+ headers: { 'Content-Type': 'application/json' },
672
+ body: { ok: true },
673
+ };
674
+ }
675
+ // DELETE /-/package/{package}/dist-tags/{tag}
676
+ if (method === 'DELETE' && tag) {
677
+ if (!await this.checkPermission(token, packageName, 'write')) {
678
+ return {
679
+ status: 401,
680
+ headers: {},
681
+ body: this.createError('EUNAUTHORIZED', 'Unauthorized'),
682
+ };
683
+ }
684
+ if (tag === 'latest') {
685
+ return {
686
+ status: 403,
687
+ headers: {},
688
+ body: this.createError('EFORBIDDEN', 'Cannot delete latest tag'),
689
+ };
690
+ }
691
+ if (packument['dist-tags'] && packument['dist-tags'][tag]) {
692
+ delete packument['dist-tags'][tag];
693
+ await this.storage.putNpmPackument(packageName, packument);
694
+ }
695
+ return {
696
+ status: 200,
697
+ headers: { 'Content-Type': 'application/json' },
698
+ body: { ok: true },
699
+ };
700
+ }
701
+ return {
702
+ status: 405,
703
+ headers: {},
704
+ body: this.createError('EBADREQUEST', 'Method not allowed'),
705
+ };
706
+ }
707
+ // ========================================================================
708
+ // HELPER METHODS
709
+ // ========================================================================
710
+ createError(code, message) {
711
+ return {
712
+ error: code,
713
+ reason: message,
714
+ };
715
+ }
716
+ }
717
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5ucG1yZWdpc3RyeS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3RzL25wbS9jbGFzc2VzLm5wbXJlZ2lzdHJ5LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUNoRCxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFDL0QsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLG9DQUFvQyxDQUFDO0FBQ3JFLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxnQ0FBZ0MsQ0FBQztBQWM3RDs7O0dBR0c7QUFDSCxNQUFNLE9BQU8sV0FBWSxTQUFRLFlBQVk7SUFDbkMsT0FBTyxDQUFrQjtJQUN6QixXQUFXLENBQWM7SUFDekIsUUFBUSxHQUFXLE1BQU0sQ0FBQztJQUMxQixXQUFXLENBQVM7SUFDcEIsTUFBTSxDQUFXO0lBRXpCLFlBQ0UsT0FBd0IsRUFDeEIsV0FBd0IsRUFDeEIsV0FBbUIsTUFBTSxFQUN6QixjQUFzQiwyQkFBMkI7UUFFakQsS0FBSyxFQUFFLENBQUM7UUFDUixJQUFJLENBQUMsT0FBTyxHQUFHLE9BQU8sQ0FBQztRQUN2QixJQUFJLENBQUMsV0FBVyxHQUFHLFdBQVcsQ0FBQztRQUMvQixJQUFJLENBQUMsUUFBUSxHQUFHLFFBQVEsQ0FBQztRQUN6QixJQUFJLENBQUMsV0FBVyxHQUFHLFdBQVcsQ0FBQztRQUUvQixvQkFBb0I7UUFDcEIsSUFBSSxDQUFDLE1BQU0sR0FBRyxJQUFJLFFBQVEsQ0FBQztZQUN6QixVQUFVLEVBQUU7Z0JBQ1YsT0FBTyxFQUFFLFlBQVk7Z0JBQ3JCLFdBQVcsRUFBRSxlQUFlO2dCQUM1QixhQUFhLEVBQUUsY0FBYztnQkFDN0IsV0FBVyxFQUFHLE9BQU8sQ0FBQyxHQUFHLENBQUMsUUFBZ0IsSUFBSSxhQUFhO2dCQUMzRCxPQUFPLEVBQUUsTUFBTTtnQkFDZixJQUFJLEVBQUUsS0FBSzth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