import assert from 'node:assert/strict'; import crypto from 'node:crypto'; import test from 'node:test'; import { createImageMakeClient, createImageMakeClientFromEnv } from './image-make-client.mjs'; test('image_make client creates, polls, validates, downloads and acknowledges a job', async () => { const image = Buffer.concat([ Buffer.from('RIFF'), Buffer.alloc(4), Buffer.from('WEBP'), Buffer.from('test-image'), ]); const sha256 = crypto.createHash('sha256').update(image).digest('hex'); const calls = []; const fetchImpl = async (url, init) => { const path = new URL(url).pathname; calls.push({ path, init }); if (path === '/v1/generation-jobs') { return Response.json({ job_id: 'job-1', status: 'queued' }, { status: 201 }); } if (path === '/v1/generation-jobs/job-1' && init.method !== 'POST') { return Response.json({ job_id: 'job-1', status: 'succeeded', result: { download_url: '/v1/generation-jobs/job-1/result', sha256, width: 512, height: 512, }, }); } if (path.endsWith('/result')) { return new Response(image, { headers: { 'content-type': 'image/webp', 'x-artifact-sha256': sha256 }, }); } if (path.endsWith('/acknowledge')) return Response.json({ job_id: 'job-1' }); throw new Error(`Unexpected request ${path}`); }; const client = createImageMakeClient({ baseUrl: 'http://127.0.0.1:8080', token: 'test-token', fetchImpl, sleep: async () => {}, }); const result = await client.generateImage({ prompt: 'calm reading room', presetId: 'memind_square_illustration', idempotencyKey: 'imgreq-test', }); assert.equal(result.jobId, 'job-1'); assert.equal(result.sha256, sha256); assert.deepEqual(result.buffer, image); await client.acknowledge(result.jobId, 'asset-1'); assert.deepEqual(calls.map((call) => call.path), [ '/v1/generation-jobs', '/v1/generation-jobs/job-1', '/v1/generation-jobs/job-1/result', '/v1/generation-jobs/job-1/acknowledge', ]); assert.equal(calls[0].init.headers.authorization, 'Bearer test-token'); assert.equal(calls[0].init.headers['idempotency-key'], 'imgreq-test'); }); test('image_make client fails closed on checksum mismatch', async () => { const image = Buffer.concat([Buffer.from('RIFF'), Buffer.alloc(4), Buffer.from('WEBPbad')]); const client = createImageMakeClient({ baseUrl: 'http://127.0.0.1:8080', token: 'test-token', sleep: async () => {}, fetchImpl: async (url) => { const path = new URL(url).pathname; if (path === '/v1/generation-jobs') return Response.json({ job_id: 'job-1', status: 'running' }, { status: 201 }); if (path.endsWith('/result')) return new Response(image, { headers: { 'content-type': 'image/webp' } }); return Response.json({ job_id: 'job-1', status: 'succeeded', result: { download_url: '/v1/generation-jobs/job-1/result', sha256: '0'.repeat(64) } }); }, }); await assert.rejects( client.generateImage({ prompt: 'x', presetId: 'memind_square_illustration' }), { code: 'IMAGE_MAKE_CHECKSUM_MISMATCH' }, ); }); test('image_make client resolves a completed idempotent reuse through status_url', async () => { const image = Buffer.concat([Buffer.from('RIFF'), Buffer.alloc(4), Buffer.from('WEBPreused')]); const sha256 = crypto.createHash('sha256').update(image).digest('hex'); const calls = []; const client = createImageMakeClient({ baseUrl: 'http://127.0.0.1:8080', token: 'test-token', sleep: async () => {}, fetchImpl: async (url) => { const path = new URL(url).pathname; calls.push(path); if (path === '/v1/generation-jobs') { return Response.json({ job_id: 'job-reused', status: 'succeeded', status_url: '/v1/generation-jobs/job-reused', }); } if (path === '/v1/generation-jobs/job-reused') { return Response.json({ job_id: 'job-reused', status: 'succeeded', result: { download_url: '/v1/generation-jobs/job-reused/result', sha256, }, }); } if (path.endsWith('/result')) { return new Response(image, { headers: { 'content-type': 'image/webp' } }); } throw new Error(`Unexpected request ${path}`); }, }); const result = await client.generateImage({ prompt: 'reuse me', presetId: 'memind_dark_hero', idempotencyKey: 'imgreq-reused', }); assert.equal(result.jobId, 'job-reused'); assert.deepEqual(calls, [ '/v1/generation-jobs', '/v1/generation-jobs/job-reused', '/v1/generation-jobs/job-reused/result', ]); }); test('image_make client keeps polling while job is validating', async () => { const image = Buffer.concat([ Buffer.from('RIFF'), Buffer.alloc(4), Buffer.from('WEBP'), Buffer.from('validating'), ]); const sha256 = crypto.createHash('sha256').update(image).digest('hex'); let polls = 0; const client = createImageMakeClient({ baseUrl: 'http://127.0.0.1:8080', token: 'test-token', sleep: async () => {}, fetchImpl: async (url) => { const path = new URL(url).pathname; if (path === '/v1/generation-jobs') { return Response.json({ job_id: 'job-1', status: 'running' }, { status: 201 }); } if (path === '/v1/generation-jobs/job-1') { polls += 1; if (polls === 1) { return Response.json({ job_id: 'job-1', status: 'validating' }); } return Response.json({ job_id: 'job-1', status: 'succeeded', result: { download_url: '/v1/generation-jobs/job-1/result', sha256, width: 1664, height: 928, }, }); } if (path.endsWith('/result')) { return new Response(image, { headers: { 'content-type': 'image/webp', 'x-artifact-sha256': sha256 }, }); } throw new Error(`Unexpected request ${path}`); }, }); const result = await client.generateImage({ prompt: 'hangzhou snow', presetId: 'memind_dark_hero', }); assert.equal(result.jobId, 'job-1'); assert.equal(polls, 2); }); test('image_make env client stays disabled until URL and token are both configured', () => { assert.equal(createImageMakeClientFromEnv({}), null); assert.equal(createImageMakeClientFromEnv({ IMAGE_MAKE_BASE_URL: 'http://127.0.0.1:8080' }), null); });