Summary
aimock already has rich support for OpenAI / Gemini / Anthropic / Bedrock / Cohere / Ollama formats (including images, audio, video). It would be a great fit to also speak fal.ai's API — both for sync (https://fal.run/{owner}/{model}) and queue (https://queue.fal.run/...) endpoints, plus storage (rest.fal.ai/rest.alpha.fal.ai).
Adding fal as a RecordProviderKey would let teams using @fal-ai/client directly or @tanstack/ai-fal route their AI traffic through aimock the same way they do for LLM providers today, instead of having to mount a custom handler.
Use case
We're building an e2e test for a video generation app that calls fal.ai for image/motion/music generation through @tanstack/ai-fal. We already use aimock for OpenRouter — having fal in the same record-and-replay system would mean a single fixtures directory, a single port, and consistent ergonomics across providers.
For now we mount a custom fal handler via LLMock.mount('/fal', ...) and have the app point fal-client at http://localhost:4010/fal via requestMiddleware. Working sketch (record/replay, body-hash keyed):
// e2e/mocks/fal-handler.ts (sketch)
const FAL_HOSTS = new Set([
'fal.run',
'queue.fal.run',
'rest.fal.ai',
'rest.alpha.fal.ai',
'gateway.fal.ai',
]);
// Server-side fal-client doesn't honor proxyUrl (browser-only middleware),
// so we install requestMiddleware that rewrites the URL and forwards the
// original host as a header.
fal.config({
requestMiddleware: async (req) => {
const original = new URL(req.url);
if (!FAL_HOSTS.has(original.hostname)) return req;
const rewritten = new URL(process.env.FAL_PROXY_URL!);
rewritten.pathname = (rewritten.pathname.replace(/\/\$/, '')) + original.pathname;
rewritten.search = original.search;
return {
...req,
url: rewritten.toString(),
headers: { ...(req.headers ?? {}), 'x-fal-target-host': original.hostname },
};
},
});
This works but it'd be much cleaner as a built-in.
Surface to support
Auth is `Authorization: Key {FAL_KEY}`.
Suggested API
Mirror the existing format options:
new LLMock({
record: {
providers: {
openai: 'https://openrouter.ai/api/v1',
fal: 'https://fal.run', // or omit upstream URL — it's in the request hostname
},
fixturePath: './fixtures',
},
});
mock.onFalRun(/flux/, { images: [{ url: '...' }] });
mock.onFalQueue(/kling/, { request_id: '...', /* ... */ });
For async/queue calls aimock would need to keep a small in-memory state map per request_id (similar to what `video.ts` already does for video-state).
Forwarding pattern
When proxying server-side, fal-client doesn't natively support `proxyUrl` (`withProxy` no-ops outside the browser — see middleware.ts). The `x-fal-target-host` request middleware pattern (sketch above) is the simplest workaround we found, and aimock could document/enable it directly.
Happy to help
We have a working handler already. If a maintainer is open to it, I can put up a PR that adds `src/fal.ts` alongside the existing provider modules — happy to follow whatever conventions you'd prefer for fixture format / handler shape.
Summary
aimock already has rich support for OpenAI / Gemini / Anthropic / Bedrock / Cohere / Ollama formats (including images, audio, video). It would be a great fit to also speak fal.ai's API — both for sync (
https://fal.run/{owner}/{model}) and queue (https://queue.fal.run/...) endpoints, plus storage (rest.fal.ai/rest.alpha.fal.ai).Adding
falas aRecordProviderKeywould let teams using@fal-ai/clientdirectly or@tanstack/ai-falroute their AI traffic through aimock the same way they do for LLM providers today, instead of having to mount a custom handler.Use case
We're building an e2e test for a video generation app that calls fal.ai for image/motion/music generation through
@tanstack/ai-fal. We already use aimock for OpenRouter — having fal in the same record-and-replay system would mean a single fixtures directory, a single port, and consistent ergonomics across providers.For now we mount a custom fal handler via
LLMock.mount('/fal', ...)and have the app point fal-client athttp://localhost:4010/falviarequestMiddleware. Working sketch (record/replay, body-hash keyed):This works but it'd be much cleaner as a built-in.
Surface to support
Auth is `Authorization: Key {FAL_KEY}`.
Suggested API
Mirror the existing format options:
For async/queue calls aimock would need to keep a small in-memory state map per request_id (similar to what `video.ts` already does for video-state).
Forwarding pattern
When proxying server-side, fal-client doesn't natively support `proxyUrl` (`withProxy` no-ops outside the browser — see middleware.ts). The `x-fal-target-host` request middleware pattern (sketch above) is the simplest workaround we found, and aimock could document/enable it directly.
Happy to help
We have a working handler already. If a maintainer is open to it, I can put up a PR that adds `src/fal.ts` alongside the existing provider modules — happy to follow whatever conventions you'd prefer for fixture format / handler shape.