import { createHash, randomBytes } from 'node:crypto'; import { describe, expect, it } from 'vitest'; import { fromBase64, tarballHashes } from '../src/integrity.js'; import { isValidName, nameToRkey, rkeyToName } from '../src/lexicon.js'; import { blobRef, parsePackageRecord, recordBlobCids, serializePackageRecord, } from '../src/record.js'; describe('names', () => { it('accepts npm-shaped package names', () => { for (const name of [ 'lodash', 'my-pkg', 'a.b_c~d', '@scope/name', '@my-org/my.pkg', ]) { expect(isValidName(name), name).toBe(true); } }); it('refuses names outside the grammar', () => { for (const name of [ '', 'UPPER', '.dot', '_under', '@scope', '@scope/a/b', '@/name', 'a b', 'a'.repeat(215), ]) { expect(isValidName(name), name).toBe(false); } }); it('round-trips names through record keys', () => { expect(nameToRkey('@scope/name')).toBe('scope:name'); expect(rkeyToName('scope:name')).toBe('@scope/name'); expect(nameToRkey('plain')).toBe('plain'); expect(rkeyToName('plain')).toBe('plain'); expect(rkeyToName(nameToRkey('@a/b.c'))).toBe('@a/b.c'); }); }); describe('integrity', () => { it('matches what node crypto computes', async () => { const bytes = new Uint8Array(randomBytes(4096)); const { integrity, shasum } = await tarballHashes(bytes); expect(integrity).toBe( `sha512-${createHash('sha512').update(bytes).digest('base64')}`, ); expect(shasum).toBe(createHash('sha1').update(bytes).digest('hex')); }); it('round-trips base64', () => { const bytes = new Uint8Array(randomBytes(300)); expect(fromBase64(Buffer.from(bytes).toString('base64'))).toEqual(bytes); }); }); describe('record', () => { const record = { name: '@scope/pkg', distTags: [{ tag: 'latest', version: '1.2.0' }], versions: [ { version: '1.2.0', tarball: blobRef('btarballcid', 'application/octet-stream', 900), manifest: blobRef('bmanifestcid', 'application/json', 300), integrity: 'sha512-abc', shasum: 'deadbeef', publishedAt: '2026-08-20T00:00:00.000Z', }, ], createdAt: '2026-08-20T00:00:00.000Z', }; it('round-trips through serialization', () => { const parsed = parsePackageRecord(serializePackageRecord(record)); expect(parsed?.name).toBe('@scope/pkg'); expect(parsed?.distTags).toEqual(record.distTags); expect(parsed?.versions).toEqual(record.versions); }); it('collects every referenced blob CID once', () => { expect(recordBlobCids(record).sort()).toEqual([ 'bmanifestcid', 'btarballcid', ]); }); it('parses nothing from a malformed value', () => { expect(parsePackageRecord(null)).toBeNull(); expect(parsePackageRecord({ name: 5 })).toBeNull(); }); it('drops a version entry missing its blobs', () => { const parsed = parsePackageRecord({ name: 'pkg', distTags: [], versions: [{ version: '1.0.0', integrity: 'sha512-x' }], createdAt: record.createdAt, }); expect(parsed?.versions).toEqual([]); }); });