visual-journal / src /app /api /images /route-defaults.test.ts
gpt-image-playground deploy
Deploy b761290 to Docker Space
f250aec
Raw
History Blame Contribute Delete
20.6 kB
import {
PNG_BASE64,
imageFormRequest,
readSseEvents,
startHttpConnectProxy,
startImagesJsonUpstream,
startResponsesImageUpstream,
startStreamingImageUpstream,
startStreamingResponsesImageUpstream
} from './route-test-helpers';
import { registerRouteTestLifecycle } from './route-test-setup';
import assert from 'node:assert/strict';
import { describe, it } from 'node:test';
registerRouteTestLifecycle();
describe('POST /api/images backend defaults and security boundaries', { concurrency: false }, () => {
it('normalizes non-streamed page image bytes to the requested output format', async () => {
const { POST } = await import('./route');
const upstream = await startImagesJsonUpstream(async () => ({ data: [{ b64_json: PNG_BASE64 }] }));
try {
const response = await POST(
imageFormRequest({
apiBaseUrl: upstream.baseUrl,
apiKey: 'test-key',
stream: false,
streamMode: 'non_stream',
outputFormat: 'webp'
})
);
assert.equal(response.status, 200);
const body = (await response.json()) as { images?: Array<Record<string, unknown>> };
assert.equal(body.images?.[0]?.output_format, 'webp');
assert.equal(
Buffer.from(String(body.images?.[0]?.b64_json || ''), 'base64').toString('ascii', 8, 12),
'WEBP'
);
} finally {
await upstream.close();
}
});
it('uses IMAGE_GENERATION_BACKEND as the route default when the request omits imageBackend', async () => {
process.env.ENABLE_RESPONSES_IMAGE_BACKEND = 'true';
process.env.IMAGE_GENERATION_BACKEND = 'responses';
process.env.OPENAI_RESPONSES_API_MODEL = 'gpt-4.1';
const { POST } = await import('./route');
let upstreamBody = '';
const upstream = await startResponsesImageUpstream(async (body) => {
upstreamBody = body;
return {
output: [
{
type: 'image_generation_call',
status: 'completed',
result: PNG_BASE64
}
]
};
});
try {
const response = await POST(
imageFormRequest({
apiBaseUrl: upstream.baseUrl,
apiKey: 'test-key',
stream: false,
streamMode: 'non_stream'
})
);
assert.equal(response.status, 200);
const body = (await response.json()) as { images?: Array<Record<string, unknown>> };
assert.equal(body.images?.[0]?.b64_json, PNG_BASE64);
const upstreamJson = JSON.parse(upstreamBody) as Record<string, unknown>;
assert.equal(upstreamJson.model, 'gpt-4.1');
assert.equal(upstreamJson.stream, false);
} finally {
await upstream.close();
}
});
it('downloads same-origin GPT2Image URL results before persisting Images API JSON responses', async () => {
const { POST } = await import('./route');
let imageDownloadCount = 0;
const upstream = await startImagesJsonUpstream(async (_body, url) => {
if (url === '/generated/final.png') {
imageDownloadCount += 1;
return Buffer.from(PNG_BASE64, 'base64');
}
return { data: [{ url: '/generated/final.png' }] };
});
try {
const response = await POST(
imageFormRequest({
apiBaseUrl: upstream.baseUrl,
apiKey: 'test-key',
stream: false,
streamMode: 'non_stream'
})
);
assert.equal(response.status, 200);
const body = (await response.json()) as { images?: Array<Record<string, unknown>> };
assert.equal(body.images?.[0]?.b64_json, PNG_BASE64);
assert.equal(imageDownloadCount, 1);
} finally {
await upstream.close();
}
});
it('sends page API requests through the configured global upstream proxy', async () => {
const { POST } = await import('./route');
const upstream = await startImagesJsonUpstream(async () => ({ data: [{ b64_json: PNG_BASE64 }] }));
const proxy = await startHttpConnectProxy();
process.env.OPENAI_UPSTREAM_PROXY_URL = proxy.url;
try {
const response = await POST(
imageFormRequest({
apiBaseUrl: upstream.baseUrl,
apiKey: 'test-key',
stream: false,
streamMode: 'non_stream'
})
);
assert.equal(response.status, 200);
assert.ok(proxy.connectTargets.length > 0);
assert.ok(proxy.connectTargets.every((target) => target === new URL(upstream.baseUrl).host));
} finally {
await proxy.close();
await upstream.close();
}
});
it('uses a channel proxy instead of the global upstream proxy', async () => {
const { POST } = await import('./route');
const upstream = await startImagesJsonUpstream(async () => ({ data: [{ b64_json: PNG_BASE64 }] }));
const globalProxy = await startHttpConnectProxy();
const channelProxy = await startHttpConnectProxy();
process.env.OPENAI_UPSTREAM_PROXY_URL = globalProxy.url;
process.env.OPENAI_CHANNEL_1_ID = 'proxied-channel';
process.env.OPENAI_CHANNEL_1_BASE_URL = upstream.baseUrl;
process.env.OPENAI_CHANNEL_1_API_KEYS = 'channel-key';
process.env.OPENAI_CHANNEL_1_PROXY_URL = channelProxy.url;
process.env.OPENAI_CHANNEL_1_REQUEST_MODES = 'images-non-stream';
try {
const response = await POST(
imageFormRequest({
stream: false,
streamMode: 'non_stream'
})
);
assert.equal(response.status, 200);
assert.ok(channelProxy.connectTargets.length > 0);
assert.ok(channelProxy.connectTargets.every((target) => target === new URL(upstream.baseUrl).host));
assert.deepEqual(globalProxy.connectTargets, []);
} finally {
await channelProxy.close();
await globalProxy.close();
await upstream.close();
}
});
it('rejects cross-origin GPT2Image URL results before downloading them', async () => {
const { POST } = await import('./route');
const upstream = await startImagesJsonUpstream(async () => {
return { data: [{ url: 'https://other.example.test/generated/final.png' }] };
});
try {
const response = await POST(
imageFormRequest({
apiBaseUrl: upstream.baseUrl,
apiKey: 'test-key',
stream: false,
streamMode: 'non_stream'
})
);
assert.equal(response.status, 502);
const body = (await response.json()) as Record<string, unknown>;
assert.match(String(body.error), /同源/);
} finally {
await upstream.close();
}
});
it('applies the image backend env default to edit requests', async () => {
process.env.ENABLE_RESPONSES_IMAGE_BACKEND = 'true';
process.env.OPENAI_RESPONSES_API_MODEL = 'gpt-4.1';
process.env.IMAGE_GENERATION_BACKEND = 'responses';
const { POST } = await import('./route');
let upstreamBody = '';
const upstream = await startResponsesImageUpstream(async (body) => {
upstreamBody = body;
return {
output: [
{
type: 'image_generation_call',
status: 'completed',
result: PNG_BASE64
}
]
};
});
try {
const response = await POST(
imageFormRequest({
apiBaseUrl: upstream.baseUrl,
apiKey: 'test-key',
mode: 'edit',
stream: false,
streamMode: 'non_stream'
})
);
assert.equal(response.status, 200);
const body = (await response.json()) as { images?: Array<Record<string, unknown>> };
assert.equal(body.images?.[0]?.b64_json, PNG_BASE64);
const upstreamJson = JSON.parse(upstreamBody) as {
tools?: Array<Record<string, unknown>>;
input?: Array<{ content?: Array<Record<string, unknown>> }>;
};
assert.equal(upstreamJson.tools?.[0]?.type, 'image_generation');
assert.equal(upstreamJson.tools?.[0]?.action, 'edit');
assert.equal(
upstreamJson.input?.[0]?.content?.some((item) => item.type === 'input_image'),
true
);
} finally {
await upstream.close();
}
});
it('applies Responses streaming strategy env defaults to edit streams', async () => {
process.env.ENABLE_RESPONSES_IMAGE_BACKEND = 'true';
process.env.OPENAI_RESPONSES_API_MODEL = 'gpt-4.1';
process.env.IMAGE_GENERATION_BACKEND = 'responses';
process.env.IMAGE_STREAMING_STRATEGY = 'responses-sse';
const { POST } = await import('./route');
let upstreamBody = '';
const upstream = await startStreamingResponsesImageUpstream(async (body) => {
upstreamBody = body;
return [
{
event: 'response.output_item.done',
data: {
type: 'response.output_item.done',
item: { type: 'image_generation_call', status: 'completed', result: PNG_BASE64 }
}
}
];
});
try {
const response = await POST(
imageFormRequest({
apiBaseUrl: upstream.baseUrl,
apiKey: 'test-key',
mode: 'edit',
stream: true
})
);
assert.equal(response.status, 200);
assert.equal(response.headers.get('content-type'), 'text/event-stream');
const events = await readSseEvents(response);
assert.deepEqual(
events.map((event) => event.type),
['completed', 'done']
);
const upstreamJson = JSON.parse(upstreamBody) as Record<string, unknown>;
assert.equal(upstreamJson.stream, true);
assert.equal(
upstreamJson.tool_choice && (upstreamJson.tool_choice as Record<string, unknown>).type,
'image_generation'
);
assert.equal(Array.isArray(upstreamJson.tools), true);
} finally {
await upstream.close();
}
});
it('accepts snake-case Responses backend controls on edit page SSE requests', async () => {
process.env.ENABLE_RESPONSES_IMAGE_BACKEND = 'true';
process.env.OPENAI_RESPONSES_API_MODEL = 'gpt-4.1';
const { POST } = await import('./route');
let upstreamBody = '';
const upstream = await startStreamingResponsesImageUpstream(async (body) => {
upstreamBody = body;
return [
{
event: 'response.output_item.done',
data: {
type: 'response.output_item.done',
item: { type: 'image_generation_call', status: 'completed', result: PNG_BASE64 }
}
}
];
});
try {
const response = await POST(
imageFormRequest({
apiBaseUrl: upstream.baseUrl,
apiKey: 'test-key',
mode: 'edit',
stream: true,
imageBackend: 'responses-image-generation',
imageBackendField: 'image_backend',
imageStreamingStrategy: 'responses-sse',
imageStreamingStrategyField: 'image_streaming_strategy',
partialImages: '1'
})
);
assert.equal(response.status, 200);
assert.equal(response.headers.get('content-type'), 'text/event-stream');
const events = await readSseEvents(response);
assert.deepEqual(
events.map((event) => event.type),
['completed', 'done']
);
const upstreamJson = JSON.parse(upstreamBody) as Record<string, unknown>;
assert.equal(upstreamJson.stream, true);
assert.equal(
upstreamJson.tool_choice && (upstreamJson.tool_choice as Record<string, unknown>).type,
'image_generation'
);
} finally {
await upstream.close();
}
});
it('lets explicit edit backend and streaming strategy override env defaults', async () => {
process.env.ENABLE_RESPONSES_IMAGE_BACKEND = 'true';
process.env.OPENAI_RESPONSES_API_MODEL = 'gpt-4.1';
process.env.IMAGE_GENERATION_BACKEND = 'responses';
process.env.IMAGE_STREAMING_STRATEGY = 'responses-sse';
const { POST } = await import('./route');
let upstreamUrl = '';
let upstreamBody = '';
const upstream = await startStreamingImageUpstream(async (body, url) => {
upstreamUrl = url;
upstreamBody = body;
return [
{
event: 'image_edit.completed',
data: { type: 'image_edit.completed', b64_json: PNG_BASE64 }
}
];
});
try {
const response = await POST(
imageFormRequest({
apiBaseUrl: upstream.baseUrl,
apiKey: 'test-key',
mode: 'edit',
stream: true,
imageBackend: 'images-api',
imageStreamingStrategy: 'auto'
})
);
assert.equal(response.status, 200);
assert.equal(response.headers.get('content-type'), 'text/event-stream');
const events = await readSseEvents(response);
assert.deepEqual(
events.map((event) => event.type),
['completed', 'done']
);
assert.equal(upstreamUrl, '/v1/images/edits');
assert.match(upstreamBody, /name="stream"/);
assert.match(upstreamBody, /name="partial_images"/);
} finally {
await upstream.close();
}
});
it('rejects incompatible edit backend and streaming strategy defaults before contacting upstream', async () => {
process.env.ENABLE_RESPONSES_IMAGE_BACKEND = 'true';
process.env.OPENAI_RESPONSES_API_MODEL = 'gpt-4.1';
process.env.IMAGE_GENERATION_BACKEND = 'responses';
process.env.IMAGE_STREAMING_STRATEGY = 'newapi-keepalive-sse';
const { POST } = await import('./route');
let upstreamCalls = 0;
const upstream = await startStreamingImageUpstream(async () => {
upstreamCalls += 1;
return [
{
event: 'image_edit.completed',
data: { type: 'image_edit.completed', b64_json: PNG_BASE64 }
}
];
});
try {
const response = await POST(
imageFormRequest({
apiBaseUrl: upstream.baseUrl,
apiKey: 'test-key',
mode: 'edit',
stream: true
})
);
assert.equal(response.status, 400);
const body = (await response.json()) as Record<string, unknown>;
assert.match(String(body.error), /Responses image_generation/);
assert.equal(upstreamCalls, 0);
} finally {
await upstream.close();
}
});
it('keeps Images API edit streams available when env defaults stay on Images API', async () => {
process.env.IMAGE_GENERATION_BACKEND = 'images-api';
process.env.IMAGE_STREAMING_STRATEGY = 'auto';
const { POST } = await import('./route');
let upstreamUrl = '';
let upstreamBody = '';
const upstream = await startStreamingImageUpstream(async (body, url) => {
upstreamUrl = url;
upstreamBody = body;
return [
{
event: 'image_edit.completed',
data: { type: 'image_edit.completed', b64_json: PNG_BASE64 }
}
];
});
try {
const response = await POST(
imageFormRequest({
apiBaseUrl: upstream.baseUrl,
apiKey: 'test-key',
mode: 'edit',
stream: true
})
);
assert.equal(response.status, 200);
assert.equal(response.headers.get('content-type'), 'text/event-stream');
const events = await readSseEvents(response);
assert.deepEqual(
events.map((event) => event.type),
['completed', 'done']
);
assert.equal(upstreamUrl, '/v1/images/edits');
assert.match(upstreamBody, /name="stream"/);
assert.match(upstreamBody, /name="partial_images"/);
} finally {
await upstream.close();
}
});
it('reports invalid image upstream env configuration as a server error before contacting upstream', async () => {
process.env.IMAGE_STREAMING_STRATEGY = 'not-a-strategy';
const { POST } = await import('./route');
let upstreamCalls = 0;
const upstream = await startStreamingImageUpstream(async () => {
upstreamCalls += 1;
return [];
});
try {
const response = await POST(
imageFormRequest({
apiBaseUrl: upstream.baseUrl,
apiKey: 'test-key',
stream: false
})
);
assert.equal(response.status, 500);
const body = (await response.json()) as Record<string, unknown>;
assert.match(String(body.error), /IMAGE_STREAMING_STRATEGY/);
assert.equal(upstreamCalls, 0);
} finally {
await upstream.close();
}
});
it('rejects remote plain-http API base URLs before forwarding API keys', async () => {
const { POST } = await import('./route');
const response = await POST(
imageFormRequest({
apiBaseUrl: 'http://api.example.com/v1',
apiKey: 'test-key',
stream: false
})
);
assert.equal(response.status, 400);
const body = (await response.json()) as Record<string, unknown>;
assert.match(String(body.error), /远程 HTTP API URL/);
});
it('treats blank APP_PASSWORD as disabled for page SSE auth', async () => {
process.env.APP_PASSWORD = ' ';
const { POST } = await import('./route');
const upstream = await startStreamingImageUpstream(async () => [
{
event: 'image_generation.completed',
data: { type: 'image_generation.completed', b64_json: PNG_BASE64 }
}
]);
try {
const response = await POST(
imageFormRequest({
apiBaseUrl: upstream.baseUrl,
apiKey: 'test-key',
stream: true
})
);
assert.equal(response.status, 200);
const events = await readSseEvents(response);
assert.deepEqual(
events.map((event) => event.type),
['completed', 'done']
);
} finally {
await upstream.close();
}
});
});