import test from 'node:test'; import assert from 'node:assert/strict'; import http from 'node:http'; import { once } from 'node:events'; import { validateBaseUrl, validateGeneration, listModels, generateImages } from '../lib/engine.mjs'; const apiKey = 'secret-do-not-echo'; const input = { model: 'explicit-third-party-model', prompt: 'a blue bird' }; const png = Buffer.from('iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAwMCAO+jRZkAAAAASUVORK5CYII=', 'base64'); const json = (res, value) => { res.setHeader('Content-Type', 'application/json'); res.end(JSON.stringify(value)); }; async function server(t, handler) { const failures = []; const instance = http.createServer((req, res) => { Promise.resolve().then(() => handler(req, res)).catch(error => { failures.push(error); res.destroy(); }); }); instance.listen(0, '127.0.0.1'); await once(instance, 'listening'); t.after(async () => { const closed = new Promise(resolve => instance.close(resolve)); instance.closeAllConnections(); await closed; if (failures.length) throw failures[0]; }); return `http://127.0.0.1:${instance.address().port}`; } async function requestJson(req) { const chunks = []; for await (const chunk of req) chunks.push(chunk); return JSON.parse(Buffer.concat(chunks).toString()); } test('base URL normalization preserves API prefix and rejects unsafe parts', () => { assert.equal(validateBaseUrl(' HTTPS://EXAMPLE.COM/v1/// '), 'https://example.com/v1'); for (const value of ['', null, '/v1', 'ftp://example.com', 'https://a:b@example.com', 'https://example.com?x=1', 'https://example.com#x', 'https://example.com?', 'https://example.com#']) { assert.throws(() => validateBaseUrl(value)); } }); test('generation requires explicit fields and sends only specified supported options', () => { assert.deepEqual(validateGeneration({ ...input, ignored: true }), { ...input, n: 1 }); const options = { ...input, n: 4, size: '1536x1024', quality: 'high', background: 'transparent', output_format: 'webp' }; assert.deepEqual(validateGeneration(options), options); assert.equal(validateGeneration({ ...input, size: 'auto' }).size, 'auto'); for (const change of [{ model: undefined }, { model: ' ' }, { model: 'x'.repeat(201) }, { prompt: '' }, { prompt: 'x'.repeat(32001) }, { n: 0 }, { n: 5 }, { n: 1.5 }, { n: '1' }, { n: null }, { size: '1024X1024' }, { quality: 'best' }, { background: null }, { output_format: 'gif' }]) { assert.throws(() => validateGeneration({ ...input, ...change })); } assert.throws(() => validateGeneration(null)); assert.equal(validateGeneration({ model: 'm'.repeat(200), prompt: 'p'.repeat(32000) }).n, 1); }); test('listModels uses exact API prefix, GET and bearer authentication', async t => { const base = await server(t, (req, res) => { assert.equal(req.method, 'GET'); assert.equal(req.url, '/custom/v1/models'); assert.equal(req.headers.authorization, `Bearer ${apiKey}`); json(res, { data: [{ id: 'model-b' }, { id: 'model-a' }] }); }); assert.deepEqual(await listModels({ baseUrl: `${base}/custom/v1///`, apiKey }), ['model-b', 'model-a']); }); test('generation posts explicit model, omits optional defaults and decodes base64', async t => { let requests = 0; const baseUrl = await server(t, async (req, res) => { requests++; assert.equal(req.url, '/images/generations'); assert.equal(req.method, 'POST'); assert.equal(req.headers.authorization, `Bearer ${apiKey}`); assert.equal(req.headers['content-type'], 'application/json'); assert.deepEqual(await requestJson(req), { ...input, n: 1 }); json(res, { model: 'provider-model', data: [{ b64_json: png.toString('base64'), revised_prompt: 'revised bird' }] }); }); const result = await generateImages({ baseUrl, apiKey, input }); assert.deepEqual(result, { ...input, images: [{ data: png, mediaType: 'image/png', revisedPrompt: 'revised bird' }] }); assert.equal(requests, 1); }); test('URL images never receive bearer auth and bytes determine media type', async t => { let downloads = 0; const imageBase = await server(t, (req, res) => { downloads++; assert.equal(req.url, '/asset?signature=public-token'); assert.equal(req.headers.authorization, undefined); res.setHeader('Content-Type', 'text/html'); res.end(png); }); const baseUrl = await server(t, (req, res) => json(res, { data: [{ url: `${imageBase}/asset?signature=public-token` }] })); const result = await generateImages({ baseUrl, apiKey, input }); assert.deepEqual(result.images, [{ data: png, mediaType: 'image/png' }]); assert.equal(downloads, 1); }); test('recognizes JPEG, WebP and GIF signatures', async t => { const fixtures = [Buffer.from([255, 216, 255, 224, 0, 0]), Buffer.from('RIFF\x04\0\0\0WEBP', 'latin1'), Buffer.from('GIF89a\x01\0\x01\0', 'latin1')]; const baseUrl = await server(t, (req, res) => json(res, { data: fixtures.map(data => ({ b64_json: data.toString('base64') })) })); const result = await generateImages({ baseUrl, apiKey, input: { ...input, n: 3 } }); assert.deepEqual(result.images.map(image => image.mediaType), ['image/jpeg', 'image/webp', 'image/gif']); }); test('HTTP errors expose status but never provider payload or key, with no retries', async t => { let count = 0; const baseUrl = await server(t, (req, res) => { count++; res.writeHead(429); res.end(`provider-private ${apiKey}`); }); await assert.rejects(generateImages({ baseUrl, apiKey, input }), error => { assert.match(error.message, /HTTP 429/); assert.doesNotMatch(error.message, /secret-do-not-echo|provider-private/); assert.equal(error.cause, undefined); return true; }); assert.equal(count, 1); }); test('API redirects are rejected without contacting redirect destination', async t => { let redirected = 0; const target = await server(t, (req, res) => { redirected++; json(res, { data: [] }); }); const baseUrl = await server(t, (req, res) => { res.writeHead(302, { Location: `${target}/models` }); res.end(); }); await assert.rejects(listModels({ baseUrl, apiKey }), /network request failed/); assert.equal(redirected, 0); }); test('malformed JSON and model lists are rejected without raw response echo', async t => { let payload = 'private-provider-body'; const baseUrl = await server(t, (req, res) => res.end(payload)); await assert.rejects(listModels({ baseUrl, apiKey }), /malformed JSON/); for (const value of [null, {}, { data: [null] }, { data: [{ id: 4 }] }, { data: [{ id: ' ' }] }]) { payload = JSON.stringify(value); await assert.rejects(listModels({ baseUrl, apiKey }), /malformed model list/); } }); test('invalid base64, invalid bytes and malformed image responses fail', async t => { let payload; const baseUrl = await server(t, (req, res) => json(res, payload)); for (const value of [null, {}, { data: [] }, { data: [null] }, { data: [{}] }, { data: [{ revised_prompt: 1, b64_json: png.toString('base64') }] }]) { payload = value; await assert.rejects(generateImages({ baseUrl, apiKey, input })); } for (const value of ['', '!!!!', 'aGk', 'aGk=\n', 'Zh==', 123, null]) { payload = { data: [{ b64_json: value }] }; await assert.rejects(generateImages({ baseUrl, apiKey, input }), /invalid base64/); } payload = { data: [{ b64_json: Buffer.from('not an image').toString('base64') }] }; await assert.rejects(generateImages({ baseUrl, apiKey, input }), /not a supported/); for (const url of ['file:///secret', 'http://user:password@localhost/image', '/relative']) { payload = { data: [{ url }] }; await assert.rejects(generateImages({ baseUrl, apiKey, input }), /invalid image URL/); } }); test('response Content-Length above 64 MB is rejected before buffering', async t => { const baseUrl = await server(t, (req, res) => { res.writeHead(200, { 'Content-Length': 64 * 1024 * 1024 + 1 }); res.flushHeaders(); }); await assert.rejects(listModels({ baseUrl, apiKey }), /64 MB response limit/); }); test('streamed responses enforce 64 MB even without Content-Length', async t => { const block = Buffer.alloc(1024 * 1024, 32); const baseUrl = await server(t, async (req, res) => { for (let i = 0; i < 65; i++) { if (res.destroyed) return; if (!res.write(block)) { await new Promise(resolve => { const done = () => { res.off('drain', done); res.off('close', done); resolve(); }; res.once('drain', done); res.once('close', done); }); } } res.end(); }); await assert.rejects(listModels({ baseUrl, apiKey }), /64 MB response limit/); }); test('caller abort interrupts pending API request and sanitizes abort reason', async t => { const controller = new AbortController(); const baseUrl = await server(t, () => controller.abort(new Error(apiKey))); await assert.rejects(listModels({ baseUrl, apiKey, signal: controller.signal }), /^Error: Request aborted\.$/); }); test('caller abort also interrupts image download', async t => { const controller = new AbortController(); const imageBase = await server(t, (req, res) => { res.writeHead(200); res.write(png.subarray(0, 4)); controller.abort(); }); const baseUrl = await server(t, (req, res) => json(res, { data: [{ url: `${imageBase}/slow` }] })); await assert.rejects(generateImages({ baseUrl, apiKey, input, signal: controller.signal }), /Request aborted/); }); test('specified generation options are preserved on the wire', async t => { const specified = { ...input, n: 2, size: 'auto', quality: 'hd', background: 'opaque', output_format: 'jpeg' }; const baseUrl = await server(t, async (req, res) => { assert.deepEqual(await requestJson(req), specified); json(res, { data: [{ b64_json: png.toString('base64') }] }); }); await generateImages({ baseUrl, apiKey, input: specified }); }); test('180 second timeout aborts a stalled request', async t => { const baseUrl = await server(t, () => {}); const original = globalThis.setTimeout; let configuredTimeout; t.mock.method(globalThis, 'setTimeout', (callback, milliseconds, ...args) => { if (milliseconds === 180_000) { configuredTimeout = milliseconds; return original(callback, 20, ...args); } return original(callback, milliseconds, ...args); }); await assert.rejects(listModels({ baseUrl, apiKey }), /timed out after 180 seconds/); assert.equal(configuredTimeout, 180_000); }); test('pre-aborted signal does not send an API request', async t => { let count = 0; const baseUrl = await server(t, (req, res) => { count++; json(res, { data: [] }); }); await assert.rejects(listModels({ baseUrl, apiKey, signal: AbortSignal.abort(apiKey) }), /Request aborted/); assert.equal(count, 0); });