feat: add image derivative orchestration

Define thumbnail, medium, and large WebP derivative variants behind an injected renderer and write them through ImageStorage with deterministic keys. Add focused tests and document the remaining worker-backed renderer. Verification: npm test passed 70 tests and integration passed 14 tests. No build script is configured.
This commit is contained in:
2026-09-08 17:40:07 -04:00
parent f7152bcff3
commit 961ed44055
4 changed files with 79 additions and 2 deletions
@@ -0,0 +1,39 @@
import assert from 'node:assert/strict';
import test from 'node:test';
import { createImageDerivativeProcessor } from '../../src/infrastructure/images/image-derivative-processor.js';
test('renders and stores thumbnail, medium, and large derivatives in order', async () => {
const renderedWidths = [];
const stored = [];
const processor = createImageDerivativeProcessor({
imageStorage: {
async put(value) { stored.push(value); },
},
async renderer({ data, maxWidth }) {
renderedWidths.push(maxWidth);
return Buffer.concat([data, Buffer.from(`-${maxWidth}`)]);
},
});
const results = await processor.process({
sourceKey: 'inventory/item/front.jpg',
data: Buffer.from('source'),
});
assert.deepEqual(renderedWidths, [320, 1280, 2400]);
assert.deepEqual(results.map(({ name, key }) => ({ name, key })), [
{ name: 'thumbnail', key: 'inventory/item/front-thumbnail.webp' },
{ name: 'medium', key: 'inventory/item/front-medium.webp' },
{ name: 'large', key: 'inventory/item/front-large.webp' },
]);
assert.equal(stored.length, 3);
assert.equal(stored[1].data.toString(), 'source-1280');
});
test('requires a renderer implementation', () => {
assert.throws(
() => createImageDerivativeProcessor({ imageStorage: {} }),
/renderer is required/,
);
});