import { randomUUID, createHash } from 'node:crypto'; import { mkdir, mkdtemp, readFile, rm, writeFile } from 'node:fs/promises'; import { tmpdir } from 'node:os'; import { dirname, join } from 'node:path'; import { Readable } from 'node:stream'; import { ForbiddenException, NotFoundException, UnauthorizedException, ValidationPipe, VersioningType, } from '@nestjs/common'; import type { NestExpressApplication } from '@nestjs/platform-express'; import { Test } from '@nestjs/testing'; import { API_JSON_BODY_LIMIT } from '../../src/app.factory'; import { AppModule } from '../../src/app.module'; import { RequestContextService } from '../../src/infrastructure/request-context/request-context.service'; import { AssetsController } from '../../src/modules/assets/assets.controller'; import { AssetDownloadQueryDto } from '../../src/modules/assets/assets.dto'; import { DeviceAuthService } from '../../src/modules/auth/device-auth.service'; import { ArtworkController } from '../../src/modules/artwork/artwork.controller'; import { AppConfigService } from '../../src/modules/config/config.service'; import { DevicesController } from '../../src/modules/devices/devices.controller'; import { HealthController } from '../../src/modules/health/health.controller'; import { LibraryController } from '../../src/modules/library/library.controller'; import { LibraryTracksQueryDto } from '../../src/modules/library/library.dto'; import { SyncController } from '../../src/modules/sync/sync.controller'; import { UploadsController } from '../../src/modules/uploads/uploads.controller'; import { UploadsService } from '../../src/modules/uploads/uploads.service'; import { PrismaService } from '../../src/infrastructure/database/prisma.service'; function sampleMp3Bytes(seed: string): Buffer { return Buffer.concat([ Buffer.from('ID3', 'ascii'), Buffer.from([0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21]), Buffer.from(seed, 'utf8'), ]); } function sha256Hex(data: Buffer): string { return createHash('sha256').update(data).digest('hex'); } function applySelect>( record: T | null, select?: Record, ) { if (!record) { return null; } if (!select) { return record; } return Object.fromEntries( Object.entries(select) .filter(([, enabled]) => enabled) .map(([key]) => [key, record[key]]), ); } function createUploadRequest(data: Buffer): any { const request = Readable.from([data]) as any; request.headers = { 'content-type': 'audio/mpeg', 'content-length': String(data.length), }; return request; } async function streamToBuffer(stream: NodeJS.ReadableStream): Promise { const chunks: Buffer[] = []; for await (const chunkValue of stream) { chunks.push( Buffer.isBuffer(chunkValue) ? chunkValue : Buffer.from(chunkValue), ); } return Buffer.concat(chunks); } function createPrismaMock() { const users = new Map(); const devices = new Map(); const deviceSyncCursors = new Map(); const tracks = new Map(); const audioAssets = new Map(); const artworkAssets = new Map(); const uploadSessions = new Map(); const libraryEvents = new Map(); let nextLibraryEventId = 1n; const createUserRecord = (data: Record) => { const now = new Date(); return { id: data.id ?? randomUUID(), createdAt: data.createdAt ?? now, updatedAt: data.updatedAt ?? now, ...data, libraryCursor: data.libraryCursor == null ? 0n : BigInt(data.libraryCursor), }; }; const defaultUser = createUserRecord({ id: randomUUID(), slug: 'default-owner', displayName: 'Default Owner', isDefault: true, libraryCursor: 0n, }); users.set(defaultUser.id, defaultUser); const prismaMock: any = { $queryRawUnsafe: jest.fn().mockResolvedValue([{ '?column?': 1 }]), $transaction: jest.fn().mockImplementation(async (callback: any) => callback(prismaMock)), user: { upsert: jest.fn().mockImplementation(async ({ where, update, create }) => { const current = [...users.values()].find((user) => user.slug === where.slug) ?? null; if (current) { const updated = createUserRecord({ ...current, ...update, id: current.id, createdAt: current.createdAt, updatedAt: new Date(), libraryCursor: current.libraryCursor, }); users.set(updated.id, updated); return updated; } const created = createUserRecord(create); users.set(created.id, created); return created; }), create: jest.fn().mockImplementation(async ({ data }) => { const created = createUserRecord(data); users.set(created.id, created); return created; }), update: jest.fn().mockImplementation(async ({ where, data, select }) => { const current = users.get(where.id); if (!current) { throw new Error( `Test Prisma mock invariant failed: user ${where.id} not found for update`, ); } const incrementBy = BigInt(data.libraryCursor?.increment ?? 0); const updated = createUserRecord({ ...current, updatedAt: new Date(), libraryCursor: current.libraryCursor + incrementBy, }); users.set(where.id, updated); if (select?.libraryCursor) { return { libraryCursor: updated.libraryCursor, }; } return updated; }), }, device: { create: jest.fn().mockImplementation(async ({ data }) => { const record = { id: randomUUID(), createdAt: new Date(), updatedAt: new Date(), ...data, }; devices.set(record.id, record); return record; }), findUnique: jest.fn().mockImplementation(async ({ where, select }) => { if (where.id) { return applySelect(devices.get(where.id) ?? null, select); } if (where.tokenHash) { const matchingDevice = [...devices.values()].find( (device) => device.tokenHash === where.tokenHash, ) ?? null; return applySelect(matchingDevice, select); } return null; }), update: jest.fn().mockImplementation(async ({ where, data }) => { const current = devices.get(where.id); const updated = { ...current, ...data, updatedAt: new Date(), }; devices.set(where.id, updated); return updated; }), }, track: { findMany: jest.fn().mockImplementation(async ({ where }) => { return [...tracks.values()] .filter((track) => { const userMatches = where?.userId ? track.userId === where.userId : true; const statusMatches = where?.status ? track.status === where.status : true; const assetMatches = where?.primaryAudioAssetId?.not ? track.primaryAudioAssetId != null : true; return userMatches && statusMatches && assetMatches; }) .sort((lhs, rhs) => lhs.createdAt.getTime() - rhs.createdAt.getTime()) .map((track) => ({ ...track, primaryAudioAsset: track.primaryAudioAssetId ? audioAssets.get(track.primaryAudioAssetId) ?? null : null, artworkAsset: track.artworkAssetId ? artworkAssets.get(track.artworkAssetId) ?? null : null, })); }), findUnique: jest.fn().mockImplementation(async ({ where }) => { return tracks.get(where.id) ?? null; }), create: jest.fn().mockImplementation(async ({ data }) => { const now = new Date(); const record = { id: randomUUID(), primaryAudioAssetId: null, artworkAssetId: null, albumArtist: null, genre: null, discNumber: null, trackNumber: null, year: null, deletedAt: null, createdAt: now, updatedAt: now, ...data, }; tracks.set(record.id, record); return record; }), update: jest.fn().mockImplementation(async ({ where, data }) => { const current = tracks.get(where.id); const updated = { ...current, ...data, updatedAt: new Date(), }; tracks.set(where.id, updated); return updated; }), }, audioAsset: { findUnique: jest.fn().mockImplementation(async ({ where }) => { if (where.id) { return audioAssets.get(where.id) ?? null; } const composite = where.userId_sha256; if (!composite) { return null; } return ( [...audioAssets.values()].find( (asset) => asset.userId === composite.userId && asset.sha256 === composite.sha256, ) ?? null ); }), create: jest.fn().mockImplementation(async ({ data }) => { const record = { id: randomUUID(), bitRateKbps: null, sampleRateHz: null, channels: null, createdAt: new Date(), ...data, }; audioAssets.set(record.id, record); return record; }), update: jest.fn().mockImplementation(async ({ where, data }) => { const current = audioAssets.get(where.id); const updated = { ...current, ...data, }; audioAssets.set(where.id, updated); return updated; }), }, artworkAsset: { findUnique: jest.fn().mockImplementation(async ({ where }) => { return artworkAssets.get(where.id) ?? null; }), findFirst: jest.fn().mockImplementation(async ({ where }) => { return ( [...artworkAssets.values()].find( (asset) => asset.userId === where.userId && asset.sha256 === where.sha256, ) ?? null ); }), create: jest.fn().mockImplementation(async ({ data }) => { const record = { id: randomUUID(), createdAt: new Date(), ...data, }; artworkAssets.set(record.id, record); return record; }), update: jest.fn().mockImplementation(async ({ where, data }) => { const current = artworkAssets.get(where.id); const updated = { ...current, ...data, }; artworkAssets.set(where.id, updated); return updated; }), }, uploadSession: { create: jest.fn().mockImplementation(async ({ data }) => { const now = new Date(); const record = { createdAt: now, updatedAt: now, completedAt: null, finalizedAt: null, trackId: null, audioAssetId: null, ...data, }; uploadSessions.set(record.id, record); return record; }), findUnique: jest.fn().mockImplementation(async ({ where }) => { return uploadSessions.get(where.id) ?? null; }), update: jest.fn().mockImplementation(async ({ where, data }) => { const current = uploadSessions.get(where.id); const updated = { ...current, ...data, updatedAt: new Date(), }; uploadSessions.set(where.id, updated); return updated; }), }, libraryEvent: { create: jest.fn().mockImplementation(async ({ data }) => { const record = { id: nextLibraryEventId, payloadVersion: 1, createdAt: new Date(), ...data, }; libraryEvents.set(record.id, record); nextLibraryEventId += 1n; return record; }), findFirst: jest.fn().mockImplementation(async ({ where, orderBy }) => { const filteredEvents = [...libraryEvents.values()].filter((event) => where?.userId ? event.userId === where.userId : true, ); const direction = orderBy?.cursor ?? 'desc'; return filteredEvents .sort((lhs, rhs) => direction === 'asc' ? Number(lhs.cursor - rhs.cursor) : Number(rhs.cursor - lhs.cursor), )[0] ?? null; }), findMany: jest.fn().mockImplementation(async ({ where, take }) => { return [...libraryEvents.values()] .filter( (event) => (where?.userId ? event.userId === where.userId : true) && (where?.cursor?.gt != null ? event.cursor > where.cursor.gt : true), ) .sort((lhs, rhs) => Number(lhs.cursor - rhs.cursor)) .slice(0, take); }), }, deviceSyncCursor: { upsert: jest.fn().mockImplementation(async ({ where, update, create }) => { const current = deviceSyncCursors.get(where.deviceId); const nextRecord = current ? { ...current, ...update, updatedAt: new Date(), } : { ...create, updatedAt: new Date(), }; deviceSyncCursors.set(where.deviceId, nextRecord); return nextRecord; }), }, }; return { prismaMock, state: { defaultUser, users, devices, deviceSyncCursors, tracks, audioAssets, artworkAssets, uploadSessions, libraryEvents, }, }; } describe('Velody API wiring (e2e)', () => { let app: NestExpressApplication; let prismaMock: ReturnType['prismaMock']; let assetsController: AssetsController; let artworkController: ArtworkController; let healthController: HealthController; let devicesController: DevicesController; let libraryController: LibraryController; let syncController: SyncController; let uploadsController: UploadsController; let uploadsService: UploadsService; let requestContextService: RequestContextService; let deviceAuthService: DeviceAuthService; let prismaState: ReturnType['state']; let storageRoot: string; async function registerDeviceWithAuthorization( body: { platform: 'MACOS' | 'IPHONE'; deviceName: string; appVersion: string; }, authorizationHeader: string, ) { return requestContextService.run(async () => { await deviceAuthService.authenticateAuthorizationHeader( authorizationHeader, ); return devicesController.register(body); }); } function seedDevice(params: { userId: string; deviceAccessToken?: string; deviceId?: string; deviceName?: string; appVersion?: string; platform?: 'MACOS' | 'IPHONE'; tokenRevokedAt?: Date | null; }) { const deviceId = params.deviceId ?? randomUUID(); const deviceAccessToken = params.deviceAccessToken; prismaState.devices.set(deviceId, { id: deviceId, userId: params.userId, platform: params.platform ?? 'IPHONE', deviceName: params.deviceName ?? 'Seeded Device', appVersion: params.appVersion ?? '0.1.0', installTokenHash: `seeded-install-${deviceId}`, tokenHash: deviceAccessToken ? sha256Hex(Buffer.from(deviceAccessToken, 'utf8')) : undefined, tokenCreatedAt: deviceAccessToken ? new Date() : undefined, tokenRevokedAt: params.tokenRevokedAt ?? undefined, lastSeenAt: new Date(), createdAt: new Date(), updatedAt: new Date(), }); return { deviceId, deviceAccessToken, }; } async function runAsDevice( deviceAccessToken: string, callback: () => Promise, ): Promise { return requestContextService.run(async () => { await deviceAuthService.authenticateAuthorizationHeader( `Bearer ${deviceAccessToken}`, ); return callback(); }); } beforeEach(async () => { const prismaSetup = createPrismaMock(); prismaMock = prismaSetup.prismaMock; const { state } = prismaSetup; prismaState = state; storageRoot = await mkdtemp(join(tmpdir(), 'velody-e2e-')); const moduleRef = await Test.createTestingModule({ imports: [AppModule], }) .overrideProvider(AppConfigService) .useValue({ appVersion: '0.1.0', maxUploadSizeBytes: 1024 * 1024 * 1024, storageRoot, }) .overrideProvider(PrismaService) .useValue(prismaMock) .compile(); app = moduleRef.createNestApplication({ bodyParser: false }); app.useBodyParser('json', { limit: API_JSON_BODY_LIMIT }); app.useBodyParser('urlencoded', { extended: true, limit: API_JSON_BODY_LIMIT, }); app.setGlobalPrefix('api'); app.enableVersioning({ type: VersioningType.URI }); app.useGlobalPipes( new ValidationPipe({ whitelist: true, forbidNonWhitelisted: true, transform: true, }), ); await app.init(); assetsController = moduleRef.get(AssetsController); artworkController = moduleRef.get(ArtworkController); healthController = moduleRef.get(HealthController); devicesController = moduleRef.get(DevicesController); libraryController = moduleRef.get(LibraryController); syncController = moduleRef.get(SyncController); uploadsController = moduleRef.get(UploadsController); uploadsService = moduleRef.get(UploadsService); requestContextService = moduleRef.get(RequestContextService); deviceAuthService = moduleRef.get(DeviceAuthService); }); afterEach(async () => { if (app) { await app.close(); } await rm(storageRoot, { recursive: true, force: true }); }); it('returns health information', async () => { const response = await healthController.getHealth(); expect(response.database.status).toBe('up'); expect(response.storage.status).toBe('up'); expect(response.version).toBe('0.1.0'); }); it('creates the bootstrap default owner during application startup', () => { expect(prismaMock.user.upsert).toHaveBeenCalledWith({ where: { slug: 'default-owner', }, update: { displayName: 'Default Owner', isDefault: true, }, create: { slug: 'default-owner', displayName: 'Default Owner', isDefault: true, }, }); }); it('registers a device and accepts heartbeat', async () => { const registerResponse = await devicesController.register({ platform: 'MACOS', deviceName: 'Diya MacBook Pro', appVersion: '0.1.0', }); expect(registerResponse.deviceId).toBeDefined(); expect(registerResponse.deviceAccessToken).toBeDefined(); expect(registerResponse.bootstrapToken).toBeDefined(); expect(prismaState.devices.get(registerResponse.deviceId)?.userId).toBe( prismaState.defaultUser.id, ); expect(prismaState.devices.get(registerResponse.deviceId)?.tokenHash).toBe( sha256Hex(Buffer.from(registerResponse.deviceAccessToken, 'utf8')), ); expect(prismaState.devices.get(registerResponse.deviceId)?.tokenCreatedAt).toEqual( expect.any(Date), ); const heartbeatResponse = await runAsDevice( registerResponse.deviceAccessToken, () => devicesController.heartbeat({ deviceId: registerResponse.deviceId, appVersion: '0.1.1', }), ); expect(heartbeatResponse.ok).toBe(true); expect(prismaState.devices.get(registerResponse.deviceId)?.appVersion).toBe( '0.1.1', ); }); it('registers a linked device under the authenticated device owner when Authorization is present', async () => { const linkedOwnerId = randomUUID(); const existingDevice = seedDevice({ userId: linkedOwnerId, deviceAccessToken: 'linked-owner-access-token', deviceName: 'Existing Linked Owner Device', platform: 'MACOS', }); const response = await registerDeviceWithAuthorization( { platform: 'IPHONE', deviceName: 'Linked iPhone', appVersion: '0.1.0', }, `Bearer ${existingDevice.deviceAccessToken}`, ); expect(response.deviceId).toBeDefined(); expect(response.deviceAccessToken).toBeDefined(); expect(prismaState.devices.get(response.deviceId)?.userId).toBe( linkedOwnerId, ); expect(prismaState.devices.get(response.deviceId)?.userId).not.toBe( prismaState.defaultUser.id, ); }); it('returns 401 when register receives an invalid Authorization header', async () => { await expect( registerDeviceWithAuthorization( { platform: 'IPHONE', deviceName: 'Rejected iPhone', appVersion: '0.1.0', }, 'Bearer invalid-device-token', ), ).rejects.toBeInstanceOf(UnauthorizedException); }); it('rejects linked registration when the authenticating device token has been revoked', async () => { const revokedDevice = seedDevice({ userId: randomUUID(), deviceAccessToken: 'revoked-link-token', tokenRevokedAt: new Date('2026-06-09T10:00:00.000Z'), deviceName: 'Revoked Device', }); await expect( registerDeviceWithAuthorization( { platform: 'MACOS', deviceName: 'Blocked Mac', appVersion: '0.1.0', }, `Bearer ${revokedDevice.deviceAccessToken}`, ), ).rejects.toBeInstanceOf(UnauthorizedException); }); it('returns 401 when heartbeat is requested without Authorization', async () => { await expect( devicesController.heartbeat({ deviceId: randomUUID(), appVersion: '0.1.1', }), ).rejects.toBeInstanceOf(UnauthorizedException); }); it('returns 401 when sync bootstrap is requested without Authorization', async () => { await expect(syncController.bootstrap()).rejects.toBeInstanceOf( UnauthorizedException, ); }); it('returns 401 when upload prepare is requested without Authorization', async () => { const bytes = sampleMp3Bytes('missing-upload-auth'); await expect( uploadsController.prepare({ deviceId: randomUUID(), sha256: sha256Hex(bytes), originalFilename: 'missing-upload-auth.mp3', sizeBytes: bytes.length, }), ).rejects.toBeInstanceOf(UnauthorizedException); }); it('returns 401 when asset download is requested without Authorization', async () => { await expect( assetsController.download( randomUUID(), { deviceId: randomUUID() }, { setHeader() {} } as any, ), ).rejects.toBeInstanceOf(UnauthorizedException); }); it('returns 401 when artwork download is requested without Authorization', async () => { await expect( artworkController.download( randomUUID(), { deviceId: randomUUID() }, { setHeader() {} } as any, ), ).rejects.toBeInstanceOf(UnauthorizedException); }); it('returns 401 when a protected route receives an invalid Authorization header', async () => { await requestContextService.run(async () => { await expect( deviceAuthService.authenticateAuthorizationHeader( 'Bearer invalid-device-token', ), ).rejects.toBeInstanceOf(UnauthorizedException); }); }); it('uses the authenticated device for heartbeat even when the body deviceId is spoofed', async () => { const ownerDevice = await devicesController.register({ platform: 'MACOS', deviceName: 'Owner Mac', appVersion: '0.1.0', }); const foreignDeviceId = randomUUID(); prismaState.devices.set(foreignDeviceId, { id: foreignDeviceId, userId: randomUUID(), platform: 'MACOS', deviceName: 'Foreign Mac', appVersion: '0.1.0', installTokenHash: 'foreign-device-hash', lastSeenAt: new Date(), createdAt: new Date(), updatedAt: new Date(), }); const response = await runAsDevice(ownerDevice.deviceAccessToken, () => devicesController.heartbeat({ deviceId: foreignDeviceId, appVersion: '0.1.1', }), ); expect(response.ok).toBe(true); expect(prismaState.devices.get(ownerDevice.deviceId)?.appVersion).toBe( '0.1.1', ); expect(prismaState.devices.get(foreignDeviceId)?.appVersion).toBe('0.1.0'); }); it('returns sync bootstrap and changes payloads', async () => { const device = await devicesController.register({ platform: 'IPHONE', deviceName: 'Sync iPhone', appVersion: '0.1.0', }); const bootstrapResponse = await runAsDevice(device.deviceAccessToken, () => syncController.bootstrap(), ); const changesResponse = await runAsDevice(device.deviceAccessToken, () => syncController.changes({ cursor: '0' }), ); expect(bootstrapResponse.tracks).toEqual([]); expect(bootstrapResponse.nextCursor).toBe('0'); expect(changesResponse.events).toEqual([]); expect(changesResponse.nextCursor).toBe('0'); expect(changesResponse.hasMore).toBe(false); expect(changesResponse.requiresBootstrap).toBe(false); expect(prismaState.deviceSyncCursors.get(device.deviceId)).toMatchObject({ deviceId: device.deviceId, userId: prismaState.defaultUser.id, cursor: 0n, }); }); it('sync bootstrap and changes do not expose foreign-owner data', async () => { const device = await devicesController.register({ platform: 'IPHONE', deviceName: 'Scoped Sync iPhone', appVersion: '0.1.0', }); const foreignUserId = randomUUID(); const foreignTrackId = randomUUID(); prismaState.tracks.set(foreignTrackId, { id: foreignTrackId, userId: foreignUserId, primaryAudioAssetId: null, artworkAssetId: null, title: 'Foreign Bootstrap Track', artist: 'Elsewhere', album: null, albumArtist: null, genre: null, discNumber: null, trackNumber: null, year: null, durationMs: 180000, status: 'ACTIVE', deletedAt: null, createdAt: new Date('2026-05-29T08:00:00.000Z'), updatedAt: new Date('2026-05-29T08:01:00.000Z'), }); prismaState.libraryEvents.set(1n, { id: 1n, cursor: 1n, userId: foreignUserId, entityType: 'TRACK', entityId: foreignTrackId, action: 'CREATED', payload: { track: { trackId: foreignTrackId, title: 'Foreign Bootstrap Track', artist: 'Elsewhere', durationSeconds: 180, sha256: 'f'.repeat(64), assetId: randomUUID(), createdAt: '2026-05-29T08:00:00.000Z', updatedAt: '2026-05-29T08:01:00.000Z', artwork: null, }, }, payloadVersion: 1, createdAt: new Date('2026-05-29T08:02:00.000Z'), }); const bootstrapResponse = await runAsDevice(device.deviceAccessToken, () => syncController.bootstrap(), ); const changesResponse = await runAsDevice(device.deviceAccessToken, () => syncController.changes({ cursor: '0' }), ); expect(bootstrapResponse.tracks).toEqual([]); expect(changesResponse.events).toEqual([]); expect(changesResponse.nextCursor).toBe('0'); }); it('downloads audio asset bytes for the owning device user', async () => { const registerResponse = await devicesController.register({ platform: 'IPHONE', deviceName: 'Playback iPhone', appVersion: '0.1.0', }); const assetId = randomUUID(); const trackId = randomUUID(); const bytes = sampleMp3Bytes('owner-download'); const storageKey = join( 'users', prismaState.defaultUser.id, 'audio', 'owner-download.mp3', ); prismaState.audioAssets.set(assetId, { id: assetId, userId: prismaState.defaultUser.id, trackId, sha256: sha256Hex(bytes), storageKey, originalFilename: 'owner-download.mp3', mimeType: 'audio/mpeg', fileExtension: 'mp3', fileSizeBytes: BigInt(bytes.length), durationMs: 180000, sourceDeviceId: registerResponse.deviceId, createdAt: new Date('2026-05-29T08:00:00.000Z'), }); const filePath = join(storageRoot, storageKey); await mkdir(dirname(filePath), { recursive: true }); await writeFile(filePath, bytes); const headers = new Map(); const responseMock = { setHeader(name: string, value: string) { headers.set(name.toLowerCase(), String(value)); }, } as any; const streamable = await runAsDevice(registerResponse.deviceAccessToken, () => assetsController.download( assetId, { deviceId: registerResponse.deviceId }, responseMock, ), ); const downloadedBytes = await streamToBuffer(streamable.getStream()); expect(downloadedBytes.equals(bytes)).toBe(true); expect(headers.get('content-type')).toBe('audio/mpeg'); expect(headers.get('content-length')).toBe(String(bytes.length)); }); it('rejects unauthorized asset download requests for another user asset', async () => { const registerResponse = await devicesController.register({ platform: 'IPHONE', deviceName: 'Playback iPhone', appVersion: '0.1.0', }); const assetId = randomUUID(); const otherUserId = randomUUID(); prismaState.audioAssets.set(assetId, { id: assetId, userId: otherUserId, trackId: randomUUID(), sha256: 'sha-other', storageKey: join('users', otherUserId, 'audio', 'other.mp3'), originalFilename: 'other.mp3', mimeType: 'audio/mpeg', fileExtension: 'mp3', fileSizeBytes: BigInt(10), durationMs: 180000, sourceDeviceId: randomUUID(), createdAt: new Date('2026-05-29T08:00:00.000Z'), }); await expect( runAsDevice(registerResponse.deviceAccessToken, () => assetsController.download( assetId, { deviceId: registerResponse.deviceId }, { setHeader() {} } as any, ), ), ).rejects.toBeInstanceOf(ForbiddenException); }); it('handles missing audio asset files cleanly', async () => { const registerResponse = await devicesController.register({ platform: 'IPHONE', deviceName: 'Playback iPhone', appVersion: '0.1.0', }); const assetId = randomUUID(); prismaState.audioAssets.set(assetId, { id: assetId, userId: prismaState.defaultUser.id, trackId: randomUUID(), sha256: 'sha-missing-file', storageKey: join( 'users', prismaState.defaultUser.id, 'audio', 'missing-file.mp3', ), originalFilename: 'missing-file.mp3', mimeType: 'audio/mpeg', fileExtension: 'mp3', fileSizeBytes: BigInt(10), durationMs: 180000, sourceDeviceId: registerResponse.deviceId, createdAt: new Date('2026-05-29T08:00:00.000Z'), }); await expect( runAsDevice(registerResponse.deviceAccessToken, () => assetsController.download( assetId, { deviceId: registerResponse.deviceId }, { setHeader() {} } as any, ), ), ).rejects.toBeInstanceOf(NotFoundException); }); it('downloads artwork bytes for the owning device user with the stored image mime type', async () => { const registerResponse = await devicesController.register({ platform: 'IPHONE', deviceName: 'Artwork iPhone', appVersion: '0.1.0', }); const artworkId = randomUUID(); const trackId = randomUUID(); const bytes = Buffer.from( 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIW2P8z8DwHwAFgwJ/lBi4NwAAAABJRU5ErkJggg==', 'base64', ); const storageKey = join( 'users', prismaState.defaultUser.id, 'artwork', `${sha256Hex(bytes)}.png`, ); prismaState.artworkAssets.set(artworkId, { id: artworkId, userId: prismaState.defaultUser.id, sha256: sha256Hex(bytes), storageKey, mimeType: 'image/png', width: 1, height: 1, fileSizeBytes: BigInt(bytes.length), createdAt: new Date('2026-05-29T08:00:00.000Z'), tracks: [{ userId: prismaState.defaultUser.id }], }); prismaState.tracks.set(trackId, { id: trackId, userId: prismaState.defaultUser.id, primaryAudioAssetId: null, artworkAssetId: artworkId, title: 'Artwork Track', artist: 'Velody', album: null, albumArtist: null, genre: null, discNumber: null, trackNumber: null, year: null, durationMs: null, status: 'ACTIVE', deletedAt: null, createdAt: new Date('2026-05-29T08:00:00.000Z'), updatedAt: new Date('2026-05-29T08:02:00.000Z'), }); const filePath = join(storageRoot, storageKey); await mkdir(dirname(filePath), { recursive: true }); await writeFile(filePath, bytes); const headers = new Map(); const responseMock = { setHeader(name: string, value: string) { headers.set(name.toLowerCase(), String(value)); }, } as any; const streamable = await runAsDevice(registerResponse.deviceAccessToken, () => artworkController.download( artworkId, { deviceId: registerResponse.deviceId }, responseMock, ), ); const downloadedBytes = await streamToBuffer(streamable.getStream()); expect(downloadedBytes.equals(bytes)).toBe(true); expect(headers.get('content-type')).toBe('image/png'); expect(headers.get('content-length')).toBe(String(bytes.length)); }); it('rejects artwork download requests for another user artwork', async () => { const registerResponse = await devicesController.register({ platform: 'IPHONE', deviceName: 'Artwork iPhone', appVersion: '0.1.0', }); const artworkId = randomUUID(); const otherUserId = randomUUID(); prismaState.artworkAssets.set(artworkId, { id: artworkId, userId: otherUserId, sha256: 'sha-other-artwork', storageKey: join('users', otherUserId, 'artwork', 'sha-other-artwork.png'), mimeType: 'image/png', width: 1, height: 1, fileSizeBytes: BigInt(10), createdAt: new Date('2026-05-29T08:00:00.000Z'), }); await expect( runAsDevice(registerResponse.deviceAccessToken, () => artworkController.download( artworkId, { deviceId: registerResponse.deviceId }, { setHeader() {} } as any, ), ), ).rejects.toBeInstanceOf(ForbiddenException); }); it('returns not found when the requested artwork file is missing', async () => { const registerResponse = await devicesController.register({ platform: 'IPHONE', deviceName: 'Artwork iPhone', appVersion: '0.1.0', }); const artworkId = randomUUID(); prismaState.artworkAssets.set(artworkId, { id: artworkId, userId: prismaState.defaultUser.id, sha256: 'sha-missing-artwork', storageKey: join( 'users', prismaState.defaultUser.id, 'artwork', 'sha-missing-artwork.png', ), mimeType: 'image/png', width: 1, height: 1, fileSizeBytes: BigInt(10), createdAt: new Date('2026-05-29T08:00:00.000Z'), tracks: [{ userId: prismaState.defaultUser.id }], }); await expect( runAsDevice(registerResponse.deviceAccessToken, () => artworkController.download( artworkId, { deviceId: registerResponse.deviceId }, { setHeader() {} } as any, ), ), ).rejects.toBeInstanceOf(NotFoundException); }); it('rejects an invalid asset download device id query', async () => { const validationPipe = new ValidationPipe({ whitelist: true, forbidNonWhitelisted: true, transform: true, }); await expect( validationPipe.transform( { deviceId: 'not-a-uuid' }, { type: 'query', metatype: AssetDownloadQueryDto, data: '', }, ), ).rejects.toMatchObject({ response: { message: expect.arrayContaining(['deviceId must be a UUID']), }, }); }); it('returns remote library metadata for the requesting device owner', async () => { const primaryDevice = await devicesController.register({ platform: 'IPHONE', deviceName: 'iPhone', appVersion: '0.1.0', }); const secondUserId = randomUUID(); const secondaryDeviceId = randomUUID(); const primaryTrackId = randomUUID(); const primaryAssetId = randomUUID(); const primaryArtworkId = randomUUID(); const placeholderTrackId = randomUUID(); const placeholderAssetId = randomUUID(); const secondaryTrackId = randomUUID(); const secondaryAssetId = randomUUID(); prismaState.devices.set(secondaryDeviceId, { id: secondaryDeviceId, userId: secondUserId, platform: 'IPHONE', deviceName: 'Other iPhone', appVersion: '0.1.0', installTokenHash: 'other-device-hash', lastSeenAt: new Date(), createdAt: new Date(), updatedAt: new Date(), }); prismaState.audioAssets.set(primaryAssetId, { id: primaryAssetId, userId: prismaState.defaultUser.id, trackId: primaryTrackId, sha256: 'sha-default', storageKey: 'users/default/audio/sha-default.mp3', originalFilename: 'default.mp3', mimeType: 'audio/mpeg', fileExtension: 'mp3', fileSizeBytes: BigInt(42), durationMs: 245000, sourceDeviceId: primaryDevice.deviceId, createdAt: new Date('2026-05-29T08:00:00.000Z'), }); prismaState.artworkAssets.set(primaryArtworkId, { id: primaryArtworkId, userId: prismaState.defaultUser.id, sha256: 'artwork-sha-default', storageKey: `users/${prismaState.defaultUser.id}/artwork/artwork-sha-default.png`, mimeType: 'image/png', width: 512, height: 512, fileSizeBytes: BigInt(128), createdAt: new Date('2026-05-29T08:00:30.000Z'), tracks: [{ userId: prismaState.defaultUser.id }], }); prismaState.audioAssets.set(placeholderAssetId, { id: placeholderAssetId, userId: prismaState.defaultUser.id, trackId: placeholderTrackId, sha256: 'sha-no-artwork', storageKey: 'users/default/audio/sha-no-artwork.mp3', originalFilename: 'no-artwork.mp3', mimeType: 'audio/mpeg', fileExtension: 'mp3', fileSizeBytes: BigInt(64), durationMs: 201000, sourceDeviceId: primaryDevice.deviceId, createdAt: new Date('2026-05-29T08:00:45.000Z'), }); prismaState.audioAssets.set(secondaryAssetId, { id: secondaryAssetId, userId: secondUserId, trackId: secondaryTrackId, sha256: 'sha-other-user', storageKey: 'users/other/audio/sha-other-user.mp3', originalFilename: 'other.mp3', mimeType: 'audio/mpeg', fileExtension: 'mp3', fileSizeBytes: BigInt(24), durationMs: 180000, sourceDeviceId: secondaryDeviceId, createdAt: new Date('2026-05-29T08:01:00.000Z'), }); prismaState.tracks.set(primaryTrackId, { id: primaryTrackId, userId: prismaState.defaultUser.id, primaryAudioAssetId: primaryAssetId, artworkAssetId: primaryArtworkId, title: 'Default User Track', artist: 'Velody', album: null, albumArtist: null, genre: null, discNumber: null, trackNumber: null, year: null, durationMs: 245000, status: 'ACTIVE', deletedAt: null, createdAt: new Date('2026-05-29T08:00:00.000Z'), updatedAt: new Date('2026-05-29T08:02:00.000Z'), }); prismaState.tracks.set(secondaryTrackId, { id: secondaryTrackId, userId: secondUserId, primaryAudioAssetId: secondaryAssetId, artworkAssetId: null, title: 'Other User Track', artist: 'Elsewhere', album: null, albumArtist: null, genre: null, discNumber: null, trackNumber: null, year: null, durationMs: 180000, status: 'ACTIVE', deletedAt: null, createdAt: new Date('2026-05-29T08:01:00.000Z'), updatedAt: new Date('2026-05-29T08:03:00.000Z'), }); prismaState.tracks.set(placeholderTrackId, { id: placeholderTrackId, userId: prismaState.defaultUser.id, primaryAudioAssetId: placeholderAssetId, artworkAssetId: null, title: 'No Artwork Track', artist: 'Velody', album: null, albumArtist: null, genre: null, discNumber: null, trackNumber: null, year: null, durationMs: 201000, status: 'ACTIVE', deletedAt: null, createdAt: new Date('2026-05-29T08:00:45.000Z'), updatedAt: new Date('2026-05-29T08:02:30.000Z'), }); const response = await runAsDevice(primaryDevice.deviceAccessToken, () => libraryController.getTracks({ deviceId: primaryDevice.deviceId, }), ); expect(response).toEqual({ tracks: [ { trackId: primaryTrackId, title: 'Default User Track', artist: 'Velody', durationSeconds: 245, sha256: 'sha-default', assetId: primaryAssetId, createdAt: '2026-05-29T08:00:00.000Z', updatedAt: '2026-05-29T08:02:00.000Z', artwork: { artworkId: primaryArtworkId, sha256: 'artwork-sha-default', mimeType: 'image/png', width: 512, height: 512, }, }, { trackId: placeholderTrackId, title: 'No Artwork Track', artist: 'Velody', durationSeconds: 201, sha256: 'sha-no-artwork', assetId: placeholderAssetId, createdAt: '2026-05-29T08:00:45.000Z', updatedAt: '2026-05-29T08:02:30.000Z', artwork: null, }, ], }); }); it('rejects an invalid remote library device id query', async () => { const validationPipe = new ValidationPipe({ whitelist: true, forbidNonWhitelisted: true, transform: true, }); await expect( validationPipe.transform( { deviceId: 'not-a-uuid' }, { type: 'query', metatype: LibraryTracksQueryDto, data: '', }, ), ).rejects.toMatchObject({ response: { message: expect.arrayContaining(['deviceId must be a UUID']), }, }); }); it('authenticates remote library requests with a valid device token and ignores spoofed device ids', async () => { const ownerDevice = await devicesController.register({ platform: 'IPHONE', deviceName: 'Auth iPhone', appVersion: '0.1.0', }); const foreignUserId = randomUUID(); const foreignDeviceId = randomUUID(); const ownerTrackId = randomUUID(); const ownerAssetId = randomUUID(); const foreignTrackId = randomUUID(); const foreignAssetId = randomUUID(); prismaState.devices.set(foreignDeviceId, { id: foreignDeviceId, userId: foreignUserId, platform: 'IPHONE', deviceName: 'Spoofed Foreign iPhone', appVersion: '0.1.0', installTokenHash: 'spoofed-device-hash', tokenHash: sha256Hex(Buffer.from('foreign-device-token', 'utf8')), tokenCreatedAt: new Date(), lastSeenAt: new Date(), createdAt: new Date(), updatedAt: new Date(), }); prismaState.audioAssets.set(ownerAssetId, { id: ownerAssetId, userId: prismaState.defaultUser.id, trackId: ownerTrackId, sha256: 'owner-library-sha', storageKey: 'users/default/audio/owner-library-sha.mp3', originalFilename: 'owner-library.mp3', mimeType: 'audio/mpeg', fileExtension: 'mp3', fileSizeBytes: BigInt(42), durationMs: 183000, sourceDeviceId: ownerDevice.deviceId, createdAt: new Date('2026-05-29T08:00:00.000Z'), }); prismaState.audioAssets.set(foreignAssetId, { id: foreignAssetId, userId: foreignUserId, trackId: foreignTrackId, sha256: 'foreign-library-sha', storageKey: 'users/foreign/audio/foreign-library-sha.mp3', originalFilename: 'foreign-library.mp3', mimeType: 'audio/mpeg', fileExtension: 'mp3', fileSizeBytes: BigInt(42), durationMs: 204000, sourceDeviceId: foreignDeviceId, createdAt: new Date('2026-05-29T08:01:00.000Z'), }); prismaState.tracks.set(ownerTrackId, { id: ownerTrackId, userId: prismaState.defaultUser.id, primaryAudioAssetId: ownerAssetId, artworkAssetId: null, title: 'Authenticated Owner Track', artist: 'Velody', album: null, albumArtist: null, genre: null, discNumber: null, trackNumber: null, year: null, durationMs: 183000, status: 'ACTIVE', deletedAt: null, createdAt: new Date('2026-05-29T08:00:00.000Z'), updatedAt: new Date('2026-05-29T08:02:00.000Z'), }); prismaState.tracks.set(foreignTrackId, { id: foreignTrackId, userId: foreignUserId, primaryAudioAssetId: foreignAssetId, artworkAssetId: null, title: 'Foreign Track', artist: 'Elsewhere', album: null, albumArtist: null, genre: null, discNumber: null, trackNumber: null, year: null, durationMs: 204000, status: 'ACTIVE', deletedAt: null, createdAt: new Date('2026-05-29T08:03:00.000Z'), updatedAt: new Date('2026-05-29T08:04:00.000Z'), }); await requestContextService.run(async () => { await deviceAuthService.authenticateAuthorizationHeader( `Bearer ${ownerDevice.deviceAccessToken}`, ); await expect( libraryController.getTracks({ deviceId: foreignDeviceId, }), ).resolves.toEqual({ tracks: [ expect.objectContaining({ trackId: ownerTrackId, title: 'Authenticated Owner Track', assetId: ownerAssetId, }), ], }); }); }); it('lets linked devices under the same identity see the same library', async () => { const identityUserId = randomUUID(); const primaryDevice = seedDevice({ userId: identityUserId, deviceAccessToken: 'shared-library-primary-token', deviceName: 'Identity Mac', platform: 'MACOS', }); const linkResponse = await registerDeviceWithAuthorization( { platform: 'IPHONE', deviceName: 'Identity iPhone', appVersion: '0.1.0', }, `Bearer ${primaryDevice.deviceAccessToken}`, ); const linkedDeviceToken = linkResponse.deviceAccessToken; const linkedDeviceId = linkResponse.deviceId; const trackId = randomUUID(); const assetId = randomUUID(); prismaState.audioAssets.set(assetId, { id: assetId, userId: identityUserId, trackId, sha256: 'shared-library-sha', storageKey: `users/${identityUserId}/audio/shared-library-sha.mp3`, originalFilename: 'shared-library.mp3', mimeType: 'audio/mpeg', fileExtension: 'mp3', fileSizeBytes: BigInt(42), durationMs: 198000, sourceDeviceId: primaryDevice.deviceId, createdAt: new Date('2026-05-29T08:00:00.000Z'), }); prismaState.tracks.set(trackId, { id: trackId, userId: identityUserId, primaryAudioAssetId: assetId, artworkAssetId: null, title: 'Shared Library Track', artist: 'Velody', album: null, albumArtist: null, genre: null, discNumber: null, trackNumber: null, year: null, durationMs: 198000, status: 'ACTIVE', deletedAt: null, createdAt: new Date('2026-05-29T08:00:00.000Z'), updatedAt: new Date('2026-05-29T08:02:00.000Z'), }); const primaryLibrary = await runAsDevice( primaryDevice.deviceAccessToken!, () => libraryController.getTracks({}), ); const linkedLibrary = await runAsDevice(linkedDeviceToken, () => libraryController.getTracks({ deviceId: linkedDeviceId, }), ); expect(primaryLibrary.tracks).toEqual([ expect.objectContaining({ trackId, assetId, title: 'Shared Library Track', }), ]); expect(linkedLibrary.tracks).toEqual(primaryLibrary.tracks); }); it('returns 401 when library is requested without Authorization even if deviceId is supplied', async () => { const ownerDevice = await devicesController.register({ platform: 'IPHONE', deviceName: 'Legacy iPhone', appVersion: '0.1.0', }); await expect( libraryController.getTracks({ deviceId: ownerDevice.deviceId, }), ).rejects.toBeInstanceOf(UnauthorizedException); }); it('rejects invalid or revoked device tokens even when a legacy device id is supplied', async () => { const ownerDevice = await devicesController.register({ platform: 'IPHONE', deviceName: 'Rejected iPhone', appVersion: '0.1.0', }); await requestContextService.run(async () => { await expect( deviceAuthService.authenticateAuthorizationHeader( 'Bearer invalid-device-token', ), ).rejects.toBeInstanceOf(UnauthorizedException); }); prismaState.devices.set(ownerDevice.deviceId, { ...prismaState.devices.get(ownerDevice.deviceId), tokenRevokedAt: new Date('2026-06-09T10:00:00.000Z'), }); await requestContextService.run(async () => { await expect( deviceAuthService.authenticateAuthorizationHeader( `Bearer ${ownerDevice.deviceAccessToken}`, ), ).rejects.toBeInstanceOf(UnauthorizedException); }); }); it('rejects cross-owner asset and artwork downloads for authenticated tokens', async () => { const ownerDevice = await devicesController.register({ platform: 'IPHONE', deviceName: 'Owner iPhone', appVersion: '0.1.0', }); const foreignUserId = randomUUID(); const foreignDeviceId = randomUUID(); const foreignAssetId = randomUUID(); const foreignArtworkId = randomUUID(); prismaState.devices.set(foreignDeviceId, { id: foreignDeviceId, userId: foreignUserId, platform: 'IPHONE', deviceName: 'Foreign iPhone', appVersion: '0.1.0', installTokenHash: 'foreign-install-hash', tokenHash: sha256Hex(Buffer.from('foreign-access-token', 'utf8')), tokenCreatedAt: new Date(), lastSeenAt: new Date(), createdAt: new Date(), updatedAt: new Date(), }); prismaState.audioAssets.set(foreignAssetId, { id: foreignAssetId, userId: foreignUserId, trackId: randomUUID(), sha256: 'foreign-asset-sha', storageKey: 'users/foreign/audio/foreign-asset-sha.mp3', originalFilename: 'foreign-asset.mp3', mimeType: 'audio/mpeg', fileExtension: 'mp3', fileSizeBytes: BigInt(64), durationMs: 190000, sourceDeviceId: foreignDeviceId, createdAt: new Date(), }); prismaState.artworkAssets.set(foreignArtworkId, { id: foreignArtworkId, userId: foreignUserId, sha256: 'foreign-artwork-sha', storageKey: 'users/foreign/artwork/foreign-artwork-sha.png', mimeType: 'image/png', width: 512, height: 512, fileSizeBytes: BigInt(64), createdAt: new Date(), tracks: [], }); await requestContextService.run(async () => { await deviceAuthService.authenticateAuthorizationHeader( `Bearer ${ownerDevice.deviceAccessToken}`, ); await expect( assetsController.download( foreignAssetId, {}, { setHeader() {} } as any, ), ).rejects.toBeInstanceOf(ForbiddenException); await expect( artworkController.download( foreignArtworkId, {}, { setHeader() {} } as any, ), ).rejects.toBeInstanceOf(ForbiddenException); }); }); it('updates tokenLastUsedAt during authenticated heartbeat', async () => { const ownerDevice = await devicesController.register({ platform: 'MACOS', deviceName: 'Heartbeat Mac', appVersion: '0.1.0', }); expect(prismaState.devices.get(ownerDevice.deviceId)?.tokenLastUsedAt).toBeUndefined(); await requestContextService.run(async () => { await deviceAuthService.authenticateAuthorizationHeader( `Bearer ${ownerDevice.deviceAccessToken}`, ); const response = await devicesController.heartbeat({ appVersion: '0.1.1', }); expect(response.ok).toBe(true); }); expect(prismaState.devices.get(ownerDevice.deviceId)?.tokenLastUsedAt).toEqual( expect.any(Date), ); }); it('makes an upload from one device visible to another linked device under the same owner', async () => { const identityUserId = randomUUID(); prismaState.users.set( identityUserId, { id: identityUserId, slug: `identity-${identityUserId}`, displayName: 'Identity Owner', isDefault: false, libraryCursor: 0n, createdAt: new Date(), updatedAt: new Date(), }, ); const primaryDevice = seedDevice({ userId: identityUserId, deviceAccessToken: 'linked-upload-primary-token', deviceName: 'Upload Mac', platform: 'MACOS', }); const linkResponse = await registerDeviceWithAuthorization( { platform: 'IPHONE', deviceName: 'Upload iPhone', appVersion: '0.1.0', }, `Bearer ${primaryDevice.deviceAccessToken}`, ); const linkedDeviceToken = linkResponse.deviceAccessToken; const bytes = sampleMp3Bytes('linked-upload'); const sha256 = sha256Hex(bytes); const prepareResponse = await runAsDevice( primaryDevice.deviceAccessToken!, () => uploadsController.prepare({ sha256, originalFilename: 'linked-upload.mp3', sizeBytes: bytes.length, }), ); expect(prepareResponse.status).toBe('upload_required'); expect(prepareResponse.uploadId).toBeDefined(); await runAsDevice(primaryDevice.deviceAccessToken!, () => uploadsController.uploadFile( prepareResponse.uploadId!, createUploadRequest(bytes), ), ); const finalizeResponse = await runAsDevice( primaryDevice.deviceAccessToken!, () => uploadsController.finalize(prepareResponse.uploadId!, { title: 'Linked Upload Track', artist: 'Velody', durationMs: 123000, }), ); const linkedLibrary = await runAsDevice(linkedDeviceToken, () => libraryController.getTracks({}), ); expect(linkedLibrary.tracks).toEqual([ expect.objectContaining({ trackId: finalizeResponse.trackId, assetId: finalizeResponse.assetId, title: 'Linked Upload Track', }), ]); }); it('supports the MP3 upload pipeline through the Nest app wiring', async () => { const registerResponse = await devicesController.register({ platform: 'MACOS', deviceName: 'Upload Mac', appVersion: '0.1.0', }); const bytes = sampleMp3Bytes('e2e-upload'); const sha256 = sha256Hex(bytes); const prepareResponse = await runAsDevice(registerResponse.deviceAccessToken, () => uploadsController.prepare({ deviceId: registerResponse.deviceId, sha256, originalFilename: 'e2e-upload.mp3', sizeBytes: bytes.length, }), ); expect(prepareResponse.status).toBe('upload_required'); const uploadResponse = await runAsDevice(registerResponse.deviceAccessToken, () => uploadsService.uploadFile( prepareResponse.uploadId!, createUploadRequest(bytes), ), ); expect(uploadResponse.status).toBe('COMPLETED'); const finalizeResponse = await runAsDevice( registerResponse.deviceAccessToken, () => uploadsController.finalize(prepareResponse.uploadId!, { title: 'Uploaded Track', artist: 'Velody', album: 'Milestone 6', durationMs: 222000, }), ); expect(finalizeResponse.trackId).toBeDefined(); expect(finalizeResponse.assetId).toBeDefined(); const storedBytes = await readFile( join(storageRoot, 'users', prismaState.defaultUser.id, 'audio', `${sha256}.mp3`), ); expect(storedBytes.equals(bytes)).toBe(true); const duplicatePrepare = await runAsDevice( registerResponse.deviceAccessToken, () => uploadsController.prepare({ deviceId: registerResponse.deviceId, sha256, originalFilename: 'e2e-upload.mp3', sizeBytes: bytes.length, }), ); expect(duplicatePrepare.status).toBe('exists'); expect(duplicatePrepare.uploadId).toBeDefined(); expect(prismaState.audioAssets.size).toBe(1); expect(prismaState.libraryEvents.size).toBe(2); }); it('supports upload finalize with embedded artwork and exposes remote artwork metadata', async () => { const registerResponse = await devicesController.register({ platform: 'MACOS', deviceName: 'Artwork Upload Mac', appVersion: '0.1.0', }); const bytes = sampleMp3Bytes('e2e-upload-artwork'); const artworkBytes = Buffer.from( 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIW2P8z8DwHwAFgwJ/lBi4NwAAAABJRU5ErkJggg==', 'base64', ); const sha256 = sha256Hex(bytes); const artworkSha256 = sha256Hex(artworkBytes); const prepareResponse = await runAsDevice(registerResponse.deviceAccessToken, () => uploadsController.prepare({ deviceId: registerResponse.deviceId, sha256, originalFilename: 'e2e-upload-artwork.mp3', sizeBytes: bytes.length, }), ); expect(prepareResponse.status).toBe('upload_required'); const uploadResponse = await runAsDevice(registerResponse.deviceAccessToken, () => uploadsService.uploadFile( prepareResponse.uploadId!, createUploadRequest(bytes), ), ); expect(uploadResponse.status).toBe('COMPLETED'); const finalizeResponse = await runAsDevice( registerResponse.deviceAccessToken, () => uploadsController.finalize(prepareResponse.uploadId!, { title: 'Uploaded Artwork Track', artist: 'Velody', album: 'Milestone 8.1', durationMs: 222000, artwork: { dataBase64: artworkBytes.toString('base64'), sha256: artworkSha256, mimeType: 'image/png', width: 1, height: 1, }, }), ); expect(finalizeResponse.trackId).toBeDefined(); expect(prismaState.artworkAssets.size).toBe(1); const remoteLibrary = await runAsDevice(registerResponse.deviceAccessToken, () => libraryController.getTracks({ deviceId: registerResponse.deviceId, }), ); expect(remoteLibrary.tracks).toEqual([ expect.objectContaining({ trackId: finalizeResponse.trackId, artwork: { artworkId: expect.any(String), sha256: artworkSha256, mimeType: 'image/png', width: 1, height: 1, }, }), ]); const artworkAsset = [...prismaState.artworkAssets.values()][0]; const storedArtworkBytes = await readFile( join( storageRoot, 'users', prismaState.defaultUser.id, 'artwork', `${artworkSha256}.png`, ), ); expect(storedArtworkBytes.equals(artworkBytes)).toBe(true); const headers = new Map(); const responseMock = { setHeader(name: string, value: string) { headers.set(name.toLowerCase(), String(value)); }, } as any; const streamable = await runAsDevice(registerResponse.deviceAccessToken, () => artworkController.download( artworkAsset.id, { deviceId: registerResponse.deviceId }, responseMock, ), ); const downloadedArtworkBytes = await streamToBuffer(streamable.getStream()); expect(downloadedArtworkBytes.equals(artworkBytes)).toBe(true); expect(headers.get('content-type')).toBe('image/png'); }); it('attaches artwork through the deduped prepare exists path and returns non-null remote artwork metadata', async () => { const registerResponse = await devicesController.register({ platform: 'MACOS', deviceName: 'Deduped Artwork Upload Mac', appVersion: '0.1.0', }); const bytes = sampleMp3Bytes('e2e-deduped-artwork'); const artworkBytes = Buffer.from( 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIW2P8z8DwHwAFgwJ/lBi4NwAAAABJRU5ErkJggg==', 'base64', ); const sha256 = sha256Hex(bytes); const artworkSha256 = sha256Hex(artworkBytes); const firstPrepare = await runAsDevice(registerResponse.deviceAccessToken, () => uploadsController.prepare({ deviceId: registerResponse.deviceId, sha256, originalFilename: 'e2e-deduped-artwork.mp3', sizeBytes: bytes.length, }), ); expect(firstPrepare.status).toBe('upload_required'); const uploadResponse = await runAsDevice(registerResponse.deviceAccessToken, () => uploadsService.uploadFile( firstPrepare.uploadId!, createUploadRequest(bytes), ), ); expect(uploadResponse.status).toBe('COMPLETED'); const firstFinalize = await runAsDevice( registerResponse.deviceAccessToken, () => uploadsController.finalize(firstPrepare.uploadId!, { title: 'Deduped Artwork Track', artist: 'Velody', album: 'Milestone 8.1', durationMs: 222000, }), ); const secondPrepare = await runAsDevice( registerResponse.deviceAccessToken, () => uploadsController.prepare({ deviceId: registerResponse.deviceId, sha256, originalFilename: 'e2e-deduped-artwork.mp3', sizeBytes: bytes.length, }), ); expect(secondPrepare.status).toBe('exists'); expect(secondPrepare.uploadId).toBeDefined(); expect(prismaState.audioAssets.size).toBe(1); const secondFinalize = await runAsDevice( registerResponse.deviceAccessToken, () => uploadsController.finalize(secondPrepare.uploadId!, { title: 'Deduped Artwork Track', artist: 'Velody', album: 'Milestone 8.1', durationMs: 222000, artwork: { dataBase64: artworkBytes.toString('base64'), sha256: artworkSha256, mimeType: 'image/png', width: 1, height: 1, }, }), ); expect(secondFinalize.trackId).toBe(firstFinalize.trackId); expect(secondFinalize.assetId).toBe(firstFinalize.assetId); expect(prismaState.artworkAssets.size).toBe(1); const remoteLibrary = await runAsDevice(registerResponse.deviceAccessToken, () => libraryController.getTracks({ deviceId: registerResponse.deviceId, }), ); expect(remoteLibrary.tracks).toEqual([ expect.objectContaining({ trackId: firstFinalize.trackId, artwork: { artworkId: expect.any(String), sha256: artworkSha256, mimeType: 'image/png', width: 1, height: 1, }, }), ]); }); });