import assert from 'node:assert/strict'; import { mkdtemp, rm } from 'node:fs/promises'; import os from 'node:os'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; import test from 'node:test'; import { createImageStorageContract } from '../../src/infrastructure/images/image-storage.js'; import { createLocalImageStorage, resolveProjectImageStorageRoot } from '../../src/infrastructure/images/local-image-storage.js'; test('local image storage round-trips and deletes binary data', async () => { const root = await mkdtemp(path.join(os.tmpdir(), 'pokemon-images-')); const storage = createLocalImageStorage(root); try { await storage.put({ key: 'inventory/item-1/front.jpg', data: Buffer.from('image-bytes') }); assert.deepEqual(await storage.get('inventory/item-1/front.jpg'), Buffer.from('image-bytes')); await storage.delete('inventory/item-1/front.jpg'); await assert.rejects(() => storage.get('inventory/item-1/front.jpg'), { code: 'ENOENT' }); } finally { await rm(root, { recursive: true, force: true }); } }); test('local image storage rejects traversal and duplicate writes', async () => { const root = await mkdtemp(path.join(os.tmpdir(), 'pokemon-images-')); const storage = createLocalImageStorage(root); try { await assert.rejects( () => storage.put({ key: '../outside.jpg', data: Buffer.from('image-bytes') }), /escapes the storage root/, ); await storage.put({ key: 'same.jpg', data: Buffer.from('first') }); await assert.rejects( () => storage.put({ key: 'same.jpg', data: Buffer.from('second') }), { code: 'EEXIST' }, ); } finally { await rm(root, { recursive: true, force: true }); } }); test('relative storage roots resolve from the project root regardless of the process cwd', () => { const apiSource = new URL('../../src/app/server.js', import.meta.url); const workerSource = new URL('../../../worker/src/worker-runtime.js', import.meta.url); const expectedRoot = fileURLToPath(new URL('../../../../', import.meta.url)); assert.equal(resolveProjectImageStorageRoot('.local/image-storage', apiSource), path.join(expectedRoot, '.local/image-storage')); assert.equal(resolveProjectImageStorageRoot('.local/image-storage', workerSource), path.join(expectedRoot, '.local/image-storage')); assert.equal(resolveProjectImageStorageRoot('/tmp/custom-image-storage', apiSource), '/tmp/custom-image-storage'); }); test('image storage contracts reject incomplete adapters', () => { assert.throws( () => createImageStorageContract({ put() {} }), /must implement get\(\)/, ); });