import { expect, tap } from '@git.zone/tstest/tapbundle'; import { SmartRegistry } from '../ts/index.js'; import { createTestRegistry, createTestTokens, createTestPackument } from './helpers/registry.js'; let registry: SmartRegistry; let npmToken: string; let userId: string; // Test data const testPackageName = 'test-package'; const testVersion = '1.0.0'; const testTarballData = Buffer.from('fake tarball content', 'utf-8'); tap.test('NPM: should create registry instance', async () => { registry = await createTestRegistry(); const tokens = await createTestTokens(registry); npmToken = tokens.npmToken; userId = tokens.userId; expect(registry).toBeInstanceOf(SmartRegistry); expect(npmToken).toBeTypeOf('string'); }); tap.test('NPM: should handle user authentication (PUT /-/user/org.couchdb.user:{user})', async () => { const response = await registry.handleRequest({ method: 'PUT', path: '/npm/-/user/org.couchdb.user:testuser', headers: {}, query: {}, body: { name: 'testuser', password: 'testpass', }, }); expect(response.status).toEqual(201); expect(response.body).toHaveProperty('token'); expect((response.body as any).token).toBeTypeOf('string'); }); tap.test('NPM: should publish a package (PUT /{package})', async () => { const packument = createTestPackument(testPackageName, testVersion, testTarballData); const response = await registry.handleRequest({ method: 'PUT', path: `/npm/${testPackageName}`, headers: { Authorization: `Bearer ${npmToken}`, 'Content-Type': 'application/json', }, query: {}, body: packument, }); expect(response.status).toEqual(201); expect(response.body).toHaveProperty('ok'); expect((response.body as any).ok).toEqual(true); }); tap.test('NPM: should retrieve package metadata (GET /{package})', async () => { const response = await registry.handleRequest({ method: 'GET', path: `/npm/${testPackageName}`, headers: {}, query: {}, }); expect(response.status).toEqual(200); expect(response.body).toHaveProperty('name'); expect((response.body as any).name).toEqual(testPackageName); expect((response.body as any).versions).toHaveProperty(testVersion); expect((response.body as any)['dist-tags'].latest).toEqual(testVersion); }); tap.test('NPM: should retrieve specific version metadata (GET /{package}/{version})', async () => { const response = await registry.handleRequest({ method: 'GET', path: `/npm/${testPackageName}/${testVersion}`, headers: {}, query: {}, }); expect(response.status).toEqual(200); expect(response.body).toHaveProperty('version'); expect((response.body as any).version).toEqual(testVersion); expect((response.body as any).name).toEqual(testPackageName); }); tap.test('NPM: should download tarball (GET /{package}/-/{tarball})', async () => { const response = await registry.handleRequest({ method: 'GET', path: `/npm/${testPackageName}/-/${testPackageName}-${testVersion}.tgz`, headers: {}, query: {}, }); expect(response.status).toEqual(200); expect(response.body).toBeInstanceOf(Buffer); expect((response.body as Buffer).toString('utf-8')).toEqual('fake tarball content'); expect(response.headers['Content-Type']).toEqual('application/octet-stream'); }); tap.test('NPM: should publish a new version of the package', async () => { const newVersion = '1.1.0'; const newTarballData = Buffer.from('new version tarball', 'utf-8'); const packument = createTestPackument(testPackageName, newVersion, newTarballData); const response = await registry.handleRequest({ method: 'PUT', path: `/npm/${testPackageName}`, headers: { Authorization: `Bearer ${npmToken}`, 'Content-Type': 'application/json', }, query: {}, body: packument, }); expect(response.status).toEqual(201); // Verify the new version is available const getResponse = await registry.handleRequest({ method: 'GET', path: `/npm/${testPackageName}`, headers: {}, query: {}, }); expect(getResponse.status).toEqual(200); expect((getResponse.body as any).versions).toHaveProperty(newVersion); }); tap.test('NPM: should get dist-tags (GET /-/package/{pkg}/dist-tags)', async () => { const response = await registry.handleRequest({ method: 'GET', path: `/npm/-/package/${testPackageName}/dist-tags`, headers: {}, query: {}, }); expect(response.status).toEqual(200); expect(response.body).toHaveProperty('latest'); expect((response.body as any).latest).toBeTypeOf('string'); }); tap.test('NPM: should update dist-tag (PUT /-/package/{pkg}/dist-tags/{tag})', async () => { const response = await registry.handleRequest({ method: 'PUT', path: `/npm/-/package/${testPackageName}/dist-tags/beta`, headers: { Authorization: `Bearer ${npmToken}`, 'Content-Type': 'application/json', }, query: {}, body: '1.1.0', }); expect(response.status).toEqual(200); // Verify the tag was updated const getResponse = await registry.handleRequest({ method: 'GET', path: `/npm/${testPackageName}`, headers: {}, query: {}, }); expect((getResponse.body as any)['dist-tags'].beta).toEqual('1.1.0'); }); tap.test('NPM: should delete dist-tag (DELETE /-/package/{pkg}/dist-tags/{tag})', async () => { const response = await registry.handleRequest({ method: 'DELETE', path: `/npm/-/package/${testPackageName}/dist-tags/beta`, headers: { Authorization: `Bearer ${npmToken}`, }, query: {}, }); expect(response.status).toEqual(200); // Verify the tag was deleted const getResponse = await registry.handleRequest({ method: 'GET', path: `/npm/${testPackageName}`, headers: {}, query: {}, }); expect((getResponse.body as any)['dist-tags']).not.toHaveProperty('beta'); }); tap.test('NPM: should create a new token (POST /-/npm/v1/tokens)', async () => { const response = await registry.handleRequest({ method: 'POST', path: '/npm/-/npm/v1/tokens', headers: { Authorization: `Bearer ${npmToken}`, 'Content-Type': 'application/json', }, query: {}, body: { password: 'testpass', readonly: true, cidr_whitelist: [], }, }); expect(response.status).toEqual(200); expect(response.body).toHaveProperty('token'); expect((response.body as any).readonly).toEqual(true); }); tap.test('NPM: should list tokens (GET /-/npm/v1/tokens)', async () => { const response = await registry.handleRequest({ method: 'GET', path: '/npm/-/npm/v1/tokens', headers: { Authorization: `Bearer ${npmToken}`, }, query: {}, }); expect(response.status).toEqual(200); expect(response.body).toHaveProperty('objects'); expect((response.body as any).objects).toBeInstanceOf(Array); expect((response.body as any).objects.length).toBeGreaterThan(0); }); tap.test('NPM: should search packages (GET /-/v1/search)', async () => { const response = await registry.handleRequest({ method: 'GET', path: '/npm/-/v1/search', headers: {}, query: { text: 'test', size: '20', }, }); expect(response.status).toEqual(200); expect(response.body).toHaveProperty('objects'); expect((response.body as any).objects).toBeInstanceOf(Array); expect((response.body as any).total).toBeGreaterThan(0); }); tap.test('NPM: should search packages with specific query', async () => { const response = await registry.handleRequest({ method: 'GET', path: '/npm/-/v1/search', headers: {}, query: { text: testPackageName, }, }); expect(response.status).toEqual(200); const results = (response.body as any).objects; expect(results.length).toBeGreaterThan(0); expect(results[0].package.name).toEqual(testPackageName); }); tap.test('NPM: should unpublish a specific version (DELETE /{package}/-/{version})', async () => { const response = await registry.handleRequest({ method: 'DELETE', path: `/npm/${testPackageName}/-/${testVersion}`, headers: { Authorization: `Bearer ${npmToken}`, }, query: {}, }); expect(response.status).toEqual(200); // Verify the version was removed const getResponse = await registry.handleRequest({ method: 'GET', path: `/npm/${testPackageName}`, headers: {}, query: {}, }); expect((getResponse.body as any).versions).not.toHaveProperty(testVersion); }); tap.test('NPM: should unpublish entire package (DELETE /{package}/-rev/{rev})', async () => { const response = await registry.handleRequest({ method: 'DELETE', path: `/npm/${testPackageName}/-rev/1`, headers: { Authorization: `Bearer ${npmToken}`, }, query: {}, }); expect(response.status).toEqual(200); // Verify the package was removed const getResponse = await registry.handleRequest({ method: 'GET', path: `/npm/${testPackageName}`, headers: {}, query: {}, }); expect(getResponse.status).toEqual(404); }); tap.test('NPM: should return 404 for non-existent package', async () => { const response = await registry.handleRequest({ method: 'GET', path: '/npm/non-existent-package', headers: {}, query: {}, }); expect(response.status).toEqual(404); expect(response.body).toHaveProperty('error'); }); tap.test('NPM: should return 401 for unauthorized publish', async () => { const packument = createTestPackument('unauthorized-package', '1.0.0', testTarballData); const response = await registry.handleRequest({ method: 'PUT', path: '/npm/unauthorized-package', headers: { // No authorization header 'Content-Type': 'application/json', }, query: {}, body: packument, }); expect(response.status).toEqual(401); expect(response.body).toHaveProperty('error'); }); tap.test('NPM: should reject readonly token for write operations', async () => { // Create a readonly token const authManager = registry.getAuthManager(); const readonlyToken = await authManager.createNpmToken(userId, true); const packument = createTestPackument('readonly-test', '1.0.0', testTarballData); const response = await registry.handleRequest({ method: 'PUT', path: '/npm/readonly-test', headers: { Authorization: `Bearer ${readonlyToken}`, 'Content-Type': 'application/json', }, query: {}, body: packument, }); expect(response.status).toEqual(401); }); export default tap.start();