getaiapi 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1326,8 +1326,11 @@ async function generate(request) {
|
|
|
1326
1326
|
|
|
1327
1327
|
// src/discovery.ts
|
|
1328
1328
|
function listModels(filters) {
|
|
1329
|
-
|
|
1330
|
-
|
|
1329
|
+
let models = loadRegistry();
|
|
1330
|
+
if (filters?.accessible) {
|
|
1331
|
+
const auth = new AuthManager();
|
|
1332
|
+
models = auth.listAvailableModels(models);
|
|
1333
|
+
}
|
|
1331
1334
|
if (filters?.category) {
|
|
1332
1335
|
models = models.filter((m) => m.category === filters.category);
|
|
1333
1336
|
}
|
|
@@ -1360,4 +1363,4 @@ export {
|
|
|
1360
1363
|
listModels,
|
|
1361
1364
|
getModel
|
|
1362
1365
|
};
|
|
1363
|
-
//# sourceMappingURL=chunk-
|
|
1366
|
+
//# sourceMappingURL=chunk-DXIDQGB2.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/gateway.ts","../src/errors.ts","../src/auth.ts","../src/resolver.ts","../src/mapper.ts","../src/categories/text-to-image.ts","../src/categories/image-edit.ts","../src/categories/text-to-video.ts","../src/categories/image-to-video.ts","../src/categories/upscale-image.ts","../src/categories/text-to-audio.ts","../src/categories/audio-to-text.ts","../src/categories/remove-background.ts","../src/categories/index.ts","../src/adapters/fal-ai.ts","../src/adapters/replicate.ts","../src/adapters/wavespeed.ts","../src/retry.ts","../src/discovery.ts"],"sourcesContent":["import { randomUUID } from 'crypto'\nimport { AuthManager } from './auth.js'\nimport { resolveModel } from './resolver.js'\nimport { mapInput, mapOutput } from './mapper.js'\nimport { getCategoryTemplate } from './categories/index.js'\nimport { falAiAdapter } from './adapters/fal-ai.js'\nimport { replicateAdapter } from './adapters/replicate.js'\nimport { wavespeedAdapter } from './adapters/wavespeed.js'\nimport type { GenerateRequest, GenerateResponse, ProviderAdapter, ProviderName } from './types.js'\nimport { ValidationError, ProviderError } from './errors.js'\nimport { withRetry } from './retry.js'\n\n// Adapter registry\nconst adapters: Record<string, ProviderAdapter> = {\n 'fal-ai': falAiAdapter,\n 'replicate': replicateAdapter,\n 'wavespeed': wavespeedAdapter,\n}\n\nexport async function generate(request: GenerateRequest): Promise<GenerateResponse> {\n const startTime = Date.now()\n\n // 1. Validate request\n if (!request.model) throw new ValidationError('model', 'model is required')\n\n // 2. Auth - check available providers\n const auth = new AuthManager()\n\n // 3. Resolve model\n const model = resolveModel(request.model, auth.availableProviders())\n\n // 4. Pick provider (first available)\n const availableBindings = model.providers.filter(p =>\n auth.availableProviders().includes(p.provider) && adapters[p.provider]\n )\n if (availableBindings.length === 0) {\n throw new ValidationError(\n 'model',\n `No adapter available for model \"${model.canonical_name}\". Available providers: ${model.providers.map(p => p.provider).join(', ')}`,\n )\n }\n const binding = availableBindings[0]\n\n // 5. Get category template\n const template = getCategoryTemplate(model.category)\n if (!template) {\n throw new ValidationError('model', `No category template for \"${model.category}\" yet`)\n }\n\n // 6. Map input\n const providerParams = mapInput(request, binding, template)\n\n // 7. Get adapter and auth key\n const adapter = adapters[binding.provider]\n const apiKey = auth.getKey(binding.provider)\n\n // 8. Submit with retry, then poll\n const timeoutMs = (request.options?.timeout as number | undefined) ?? template.default_timeout_ms\n const submitted = await withRetry(\n () => adapter.submit(binding.endpoint, providerParams, apiKey),\n { timeoutMs },\n )\n\n let result = submitted\n while (result.status === 'processing' || result.status === 'pending') {\n await new Promise(resolve => setTimeout(resolve, 1000))\n result = await adapter.poll(submitted.id, apiKey, binding.endpoint)\n }\n\n if (result.status === 'failed') {\n throw new ProviderError(\n binding.provider,\n model.canonical_name,\n 0,\n result.error || 'Generation failed',\n )\n }\n\n // 9. Map output\n const outputs = mapOutput(result.output, binding.output_map)\n\n // 10. Build response\n return {\n id: randomUUID(),\n model: model.canonical_name,\n provider: binding.provider,\n status: 'completed',\n outputs,\n metadata: {\n inference_time_ms: Date.now() - startTime,\n seed: typeof result.output === 'object' && result.output !== null\n ? (result.output as Record<string, unknown>).seed as number | undefined\n : undefined,\n safety_flagged: typeof result.output === 'object' && result.output !== null\n ? (\n Array.isArray((result.output as Record<string, unknown>).has_nsfw_concepts)\n ? ((result.output as Record<string, unknown>).has_nsfw_concepts as boolean[]).some((v: boolean) => v)\n : undefined\n )\n : undefined,\n },\n }\n}\n","import type { ProviderName } from \"./types.js\";\n\nexport class GetAIApiError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"GetAIApiError\";\n }\n}\n\nexport class AuthError extends GetAIApiError {\n readonly provider: ProviderName;\n readonly envVar: string;\n\n constructor(provider: ProviderName, envVar: string) {\n super(`Missing or invalid API key for ${provider}. Set the ${envVar} environment variable.`);\n this.name = \"AuthError\";\n this.provider = provider;\n this.envVar = envVar;\n }\n}\n\nexport class ModelNotFoundError extends GetAIApiError {\n readonly query: string;\n readonly suggestions: string[];\n\n constructor(query: string, suggestions: string[] = []) {\n const hint =\n suggestions.length > 0\n ? ` Did you mean: ${suggestions.join(\", \")}?`\n : \"\";\n super(`Model \"${query}\" not found.${hint}`);\n this.name = \"ModelNotFoundError\";\n this.query = query;\n this.suggestions = suggestions;\n }\n}\n\nexport class ValidationError extends GetAIApiError {\n readonly field: string;\n\n constructor(field: string, message: string) {\n super(`Validation error on \"${field}\": ${message}`);\n this.name = \"ValidationError\";\n this.field = field;\n }\n}\n\nexport class ProviderError extends GetAIApiError {\n readonly provider: ProviderName;\n readonly model: string;\n readonly statusCode: number;\n readonly raw: unknown;\n\n constructor(\n provider: ProviderName,\n model: string,\n statusCode: number,\n raw: unknown,\n ) {\n super(\n `Provider ${provider} returned status ${statusCode} for model \"${model}\".`,\n );\n this.name = \"ProviderError\";\n this.provider = provider;\n this.model = model;\n this.statusCode = statusCode;\n this.raw = raw;\n }\n}\n\nexport class TimeoutError extends GetAIApiError {\n readonly provider: ProviderName;\n readonly model: string;\n readonly timeoutMs: number;\n\n constructor(provider: ProviderName, model: string, timeoutMs: number) {\n super(\n `Generation timed out after ${timeoutMs}ms for model \"${model}\" on ${provider}.`,\n );\n this.name = \"TimeoutError\";\n this.provider = provider;\n this.model = model;\n this.timeoutMs = timeoutMs;\n }\n}\n\nexport class RateLimitError extends GetAIApiError {\n readonly provider: ProviderName;\n readonly retryAfterMs: number;\n\n constructor(provider: ProviderName, retryAfterMs: number) {\n super(\n `Rate limited by ${provider}. Retry after ${retryAfterMs}ms.`,\n );\n this.name = \"RateLimitError\";\n this.provider = provider;\n this.retryAfterMs = retryAfterMs;\n }\n}\n","import type { ProviderName, ModelEntry } from \"./types.js\";\nimport { AuthError } from \"./errors.js\";\n\nconst ENV_MAP: Record<ProviderName, string> = {\n \"fal-ai\": \"FAL_KEY\",\n replicate: \"REPLICATE_API_TOKEN\",\n wavespeed: \"WAVESPEED_API_KEY\",\n};\n\nexport class AuthManager {\n private keys: Map<string, string>;\n\n constructor() {\n this.keys = new Map();\n for (const [provider, envVar] of Object.entries(ENV_MAP)) {\n const key = process.env[envVar]?.trim();\n if (key) this.keys.set(provider, key);\n }\n }\n\n availableProviders(): ProviderName[] {\n return [...this.keys.keys()] as ProviderName[];\n }\n\n getKey(provider: ProviderName): string {\n const key = this.keys.get(provider);\n if (!key) {\n throw new AuthError(provider, ENV_MAP[provider]);\n }\n return key;\n }\n\n canAccess(model: ModelEntry): boolean {\n return model.providers.some((p) => this.keys.has(p.provider));\n }\n\n listAvailableModels(registry: ModelEntry[]): ModelEntry[] {\n return registry.filter((m) => this.canAccess(m));\n }\n}\n","import { readFileSync } from \"fs\";\nimport { resolve, dirname } from \"path\";\nimport { fileURLToPath } from \"url\";\nimport type { ModelEntry, ProviderName } from \"./types.js\";\nimport { ModelNotFoundError } from \"./errors.js\";\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\n\nlet registryCache: ModelEntry[] | null = null;\n\n/**\n * Reads and parses registry/registry.json.\n * Caches the result so the file is only loaded once.\n */\nexport function loadRegistry(): ModelEntry[] {\n if (registryCache) {\n return registryCache;\n }\n\n // Try resolving from project root (works both from src/ and dist/)\n // Walk up from current file to find the registry directory\n let dir = __dirname;\n for (let i = 0; i < 5; i++) {\n const candidate = resolve(dir, \"registry\", \"registry.json\");\n try {\n const raw = readFileSync(candidate, \"utf-8\");\n registryCache = JSON.parse(raw) as ModelEntry[];\n return registryCache;\n } catch {\n dir = dirname(dir);\n }\n }\n\n throw new Error(\n \"Could not find registry/registry.json. Searched upward from: \" + __dirname,\n );\n}\n\n/**\n * Normalizes a model name for fuzzy matching.\n * - Lowercase\n * - Strip all non-alphanumeric characters\n * - Strip leading 'v' from version numbers (e.g., \"v4.5\" -> \"45\")\n */\nexport function normalizeModelName(input: string): string {\n return input\n .toLowerCase()\n .replace(/[^a-z0-9]/g, \"\")\n .replace(/(?<=\\d)v(?=\\d)/g, \"\") // v between digits (unlikely but safe)\n .replace(/v(?=\\d)/g, \"\"); // v before digits\n}\n\n/**\n * Resolves a user's model name query to a matching ModelEntry.\n *\n * Resolution order:\n * 1. Exact canonical match\n * 2. Exact alias match\n * 3. Normalized canonical match\n * 4. Normalized alias match\n * 5. No match -> throw ModelNotFoundError with suggestions\n */\nexport function resolveModel(\n query: string,\n availableProviders?: ProviderName[],\n): ModelEntry {\n if (!query || typeof query !== \"string\" || query.trim() === \"\") {\n throw new ModelNotFoundError(\"Model name is required\");\n }\n\n const trimmedQuery = query.trim();\n const registry = loadRegistry();\n\n let matched: ModelEntry | undefined;\n\n // 1. Exact canonical match\n matched = registry.find((e) => e.canonical_name === trimmedQuery);\n\n // 2. Exact alias match\n if (!matched) {\n matched = registry.find((e) =>\n e.aliases.some((a) => a === trimmedQuery),\n );\n }\n\n // 3. Normalized canonical match\n if (!matched) {\n const normalizedQuery = normalizeModelName(trimmedQuery);\n matched = registry.find(\n (e) => normalizeModelName(e.canonical_name) === normalizedQuery,\n );\n\n // 4. Normalized alias match\n if (!matched) {\n matched = registry.find((e) =>\n e.aliases.some((a) => normalizeModelName(a) === normalizedQuery),\n );\n }\n }\n\n if (!matched) {\n const suggestions = findSuggestions(trimmedQuery, registry);\n throw new ModelNotFoundError(trimmedQuery, suggestions);\n }\n\n // Apply provider filtering after matching\n if (availableProviders && availableProviders.length > 0) {\n const filteredProviders = matched.providers.filter((p) =>\n availableProviders.includes(p.provider),\n );\n\n if (filteredProviders.length === 0) {\n const suggestions = findSuggestions(trimmedQuery, registry);\n throw new ModelNotFoundError(trimmedQuery, suggestions);\n }\n\n return { ...matched, providers: filteredProviders };\n }\n\n return matched;\n}\n\n/**\n * Find up to 5 suggestions for a failed query.\n * Uses prefix and substring matching on normalized names.\n * Sorted by canonical_name length (shorter = more likely intended).\n */\nfunction findSuggestions(\n query: string,\n registry: ModelEntry[],\n): string[] {\n const normalizedQuery = normalizeModelName(query);\n\n if (normalizedQuery === \"\") {\n return [];\n }\n\n const matches = registry.filter((e) => {\n const normalizedCanonical = normalizeModelName(e.canonical_name);\n // Check if either is a prefix/substring of the other\n if (\n normalizedCanonical.startsWith(normalizedQuery) ||\n normalizedCanonical.includes(normalizedQuery) ||\n normalizedQuery.startsWith(normalizedCanonical)\n ) {\n return true;\n }\n // Check for a meaningful shared prefix (at least 3 chars)\n const minLen = Math.min(normalizedQuery.length, normalizedCanonical.length);\n let shared = 0;\n for (let i = 0; i < minLen; i++) {\n if (normalizedQuery[i] === normalizedCanonical[i]) {\n shared++;\n } else {\n break;\n }\n }\n return shared >= 3 && shared >= normalizedQuery.length * 0.3;\n });\n\n return matches\n .sort((a, b) => a.canonical_name.length - b.canonical_name.length)\n .slice(0, 5)\n .map((e) => e.canonical_name);\n}\n\n/**\n * Clears the registry cache. Useful for testing.\n */\nexport function clearRegistryCache(): void {\n registryCache = null;\n}\n","import type {\n GenerateRequest,\n ProviderBinding,\n CategoryTemplate,\n ParamMapping,\n OutputItem,\n OutputMapping,\n ProviderName,\n} from './types.js'\nimport { ValidationError } from './errors.js'\n\n/**\n * Maps a universal GenerateRequest to provider-specific params\n * using the category template's input_mappings.\n */\nexport function mapInput(\n request: GenerateRequest,\n binding: ProviderBinding,\n template: CategoryTemplate,\n): Record<string, unknown> {\n const result: Record<string, unknown> = {}\n const provider = binding.provider\n\n for (const mapping of template.input_mappings) {\n const value = getUniversalValue(request, mapping.universal)\n\n if (value === undefined || value === null) {\n if (mapping.required) {\n throw new ValidationError(\n mapping.universal,\n `\"${mapping.universal}\" is required but was not provided.`,\n )\n }\n continue\n }\n\n const providerKey = mapping.providers[provider]\n if (providerKey === undefined) {\n // Provider doesn't support this param — silently drop\n continue\n }\n\n const transformed = applyTransform(value, mapping, provider)\n\n if (Array.isArray(providerKey)) {\n // Spread into multiple params (e.g., Replicate's [\"width\", \"height\"])\n if (typeof transformed === 'object' && transformed !== null && !Array.isArray(transformed)) {\n const obj = transformed as Record<string, unknown>\n for (const key of providerKey) {\n if (obj[key] !== undefined) {\n result[key] = obj[key]\n }\n }\n }\n } else {\n result[providerKey] = transformed\n }\n }\n\n // Merge options passthrough — options wins on conflict\n if (request.options) {\n for (const [key, val] of Object.entries(request.options)) {\n result[key] = val\n }\n }\n\n return result\n}\n\n/**\n * Extracts a universal field value from the GenerateRequest.\n */\nfunction getUniversalValue(request: GenerateRequest, field: string): unknown {\n return (request as unknown as Record<string, unknown>)[field]\n}\n\n/**\n * Applies the specified transform to the value.\n */\nfunction applyTransform(\n value: unknown,\n mapping: ParamMapping,\n provider: ProviderName,\n): unknown {\n const transform = mapping.transform\n\n if (!transform || transform === 'none') {\n return value\n }\n\n if (transform === 'flip_boolean') {\n if (provider === 'replicate') {\n return !value\n }\n return value\n }\n\n if (transform === 'parse_size') {\n return parseSizeForProvider(value, mapping, provider)\n }\n\n return value\n}\n\n/**\n * Converts a size value to the provider-specific format.\n */\nfunction parseSizeForProvider(\n value: unknown,\n mapping: ParamMapping,\n provider: ProviderName,\n): unknown {\n if (provider === 'fal-ai') {\n if (typeof value === 'string') {\n const [w, h] = value.split('x').map(Number)\n return { width: w, height: h }\n }\n // Object passthrough\n return value\n }\n\n if (provider === 'replicate') {\n if (typeof value === 'string') {\n const [w, h] = value.split('x').map(Number)\n return { width: w, height: h }\n }\n if (typeof value === 'object' && value !== null) {\n return value\n }\n return value\n }\n\n // wavespeed and others: pass through as-is\n return value\n}\n\n/**\n * Maps raw provider response to OutputItem[] using the output mapping.\n */\nexport function mapOutput(raw: unknown, outputMapping: OutputMapping): OutputItem[] {\n const { type, extract_path, content_type } = outputMapping\n const defaultContentType = content_type || 'image/jpeg'\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const data = raw as any\n\n if (extract_path === 'images[].url') {\n const images: unknown[] = data?.images ?? []\n return images.map((img: any) => ({\n type,\n url: img.url as string,\n content_type: (img.content_type as string) || defaultContentType,\n }))\n }\n\n if (extract_path === 'output[]') {\n const arr: unknown[] = Array.isArray(data) ? data : data?.output ?? []\n return arr.map((url: unknown) => ({\n type,\n url: url as string,\n content_type: defaultContentType,\n }))\n }\n\n if (extract_path === 'data.outputs[]') {\n const outputs: unknown[] = data?.data?.outputs ?? []\n return outputs.map((url: unknown) => ({\n type,\n url: url as string,\n content_type: defaultContentType,\n }))\n }\n\n if (extract_path === 'video.url') {\n return [{\n type: 'video',\n url: data?.video?.url as string,\n content_type: 'video/mp4',\n }]\n }\n\n if (extract_path === 'audio.url') {\n return [{\n type: 'audio',\n url: data?.audio?.url as string,\n content_type: 'audio/mpeg',\n }]\n }\n\n // Generic dot-notation traversal for unknown paths\n return genericExtract(data, extract_path, type, defaultContentType)\n}\n\n/**\n * Generic dot-notation traversal for unknown extract paths.\n * Supports paths like \"foo.bar[].baz\".\n */\nfunction genericExtract(\n data: unknown,\n path: string,\n type: OutputMapping['type'],\n contentType: string,\n): OutputItem[] {\n const segments = path.split('.')\n let current: unknown = data\n\n for (const seg of segments) {\n if (current === null || current === undefined) return []\n\n const arrayMatch = seg.match(/^(.+)\\[\\]$/)\n if (arrayMatch) {\n const key = arrayMatch[1]\n current = (current as Record<string, unknown>)[key]\n if (Array.isArray(current)) {\n // If there are more segments after this, we'd need to map deeper\n // For now, treat as final array\n const remaining = segments.slice(segments.indexOf(seg) + 1).join('.')\n if (remaining) {\n return (current as unknown[]).map((item: any) => ({\n type,\n url: getNestedValue(item, remaining) as string,\n content_type: contentType,\n }))\n }\n return (current as unknown[]).map((item: unknown) => ({\n type,\n url: (typeof item === 'string' ? item : (item as any)?.url) as string,\n content_type: contentType,\n }))\n }\n return []\n }\n\n current = (current as Record<string, unknown>)[seg]\n }\n\n // Single value at end of path\n if (typeof current === 'string') {\n return [{ type, url: current, content_type: contentType }]\n }\n\n return []\n}\n\nfunction getNestedValue(obj: unknown, path: string): unknown {\n let current = obj\n for (const key of path.split('.')) {\n if (current === null || current === undefined) return undefined\n current = (current as Record<string, unknown>)[key]\n }\n return current\n}\n","import type { CategoryTemplate } from '../types.js'\n\nexport const textToImageTemplate: CategoryTemplate = {\n category: 'text-to-image',\n input_mappings: [\n {\n universal: 'prompt',\n providers: {\n 'fal-ai': 'prompt',\n 'replicate': 'prompt',\n 'wavespeed': 'prompt',\n },\n required: true,\n },\n {\n universal: 'negative_prompt',\n providers: {\n 'fal-ai': 'negative_prompt',\n 'replicate': 'negative_prompt',\n 'wavespeed': 'negative_prompt',\n },\n },\n {\n universal: 'count',\n providers: {\n 'fal-ai': 'num_images',\n 'replicate': 'num_outputs',\n 'wavespeed': 'num_outputs',\n },\n },\n {\n universal: 'size',\n providers: {\n 'fal-ai': 'image_size',\n 'replicate': ['width', 'height'],\n 'wavespeed': 'resolution',\n },\n transform: 'parse_size',\n },\n {\n universal: 'guidance',\n providers: {\n 'fal-ai': 'guidance_scale',\n 'replicate': 'guidance',\n 'wavespeed': 'guidance_scale',\n },\n },\n {\n universal: 'steps',\n providers: {\n 'fal-ai': 'num_inference_steps',\n 'replicate': 'num_inference_steps',\n 'wavespeed': 'num_inference_steps',\n },\n },\n {\n universal: 'seed',\n providers: {\n 'fal-ai': 'seed',\n 'replicate': 'seed',\n 'wavespeed': 'seed',\n },\n },\n {\n universal: 'format',\n providers: {\n 'fal-ai': 'output_format',\n 'replicate': 'output_format',\n 'wavespeed': 'output_format',\n },\n },\n {\n universal: 'quality',\n providers: {\n 'fal-ai': 'quality',\n 'replicate': 'output_quality',\n 'wavespeed': 'quality',\n },\n },\n {\n universal: 'safety',\n providers: {\n 'fal-ai': 'enable_safety_checker',\n 'replicate': 'disable_safety_checker',\n 'wavespeed': 'enable_safety_checker',\n },\n transform: 'flip_boolean',\n },\n ],\n output_type: 'image',\n output_extract: {\n 'fal-ai': 'images[].url',\n 'replicate': 'output[]',\n 'wavespeed': 'data.outputs[]',\n },\n default_timeout_ms: 60000,\n}\n","import type { CategoryTemplate } from '../types.js'\n\nexport const imageEditTemplate: CategoryTemplate = {\n category: 'image-edit',\n input_mappings: [\n {\n universal: 'image',\n providers: {\n 'fal-ai': 'image_url',\n 'replicate': 'image',\n 'wavespeed': 'image_url',\n },\n required: true,\n },\n {\n universal: 'prompt',\n providers: {\n 'fal-ai': 'prompt',\n 'replicate': 'prompt',\n 'wavespeed': 'prompt',\n },\n required: true,\n },\n {\n universal: 'strength',\n providers: {\n 'fal-ai': 'strength',\n 'replicate': 'strength',\n 'wavespeed': 'strength',\n },\n },\n {\n universal: 'mask',\n providers: {\n 'fal-ai': 'mask_url',\n 'replicate': 'mask',\n 'wavespeed': 'mask_url',\n },\n },\n {\n universal: 'seed',\n providers: {\n 'fal-ai': 'seed',\n 'replicate': 'seed',\n 'wavespeed': 'seed',\n },\n },\n {\n universal: 'format',\n providers: {\n 'fal-ai': 'output_format',\n 'replicate': 'output_format',\n 'wavespeed': 'output_format',\n },\n },\n {\n universal: 'quality',\n providers: {\n 'fal-ai': 'quality',\n 'replicate': 'output_quality',\n 'wavespeed': 'quality',\n },\n },\n {\n universal: 'safety',\n providers: {\n 'fal-ai': 'enable_safety_checker',\n 'replicate': 'disable_safety_checker',\n 'wavespeed': 'enable_safety_checker',\n },\n transform: 'flip_boolean',\n },\n ],\n output_type: 'image',\n output_extract: {\n 'fal-ai': 'images[].url',\n 'replicate': 'output[]',\n 'wavespeed': 'data.outputs[]',\n },\n default_timeout_ms: 60000,\n}\n","import type { CategoryTemplate } from '../types.js'\n\nexport const textToVideoTemplate: CategoryTemplate = {\n category: 'text-to-video',\n input_mappings: [\n {\n universal: 'prompt',\n providers: {\n 'fal-ai': 'prompt',\n 'replicate': 'prompt',\n 'wavespeed': 'prompt',\n },\n required: true,\n },\n {\n universal: 'negative_prompt',\n providers: {\n 'fal-ai': 'negative_prompt',\n 'replicate': 'negative_prompt',\n 'wavespeed': 'negative_prompt',\n },\n },\n {\n universal: 'count',\n providers: {\n 'fal-ai': 'num_videos',\n 'replicate': 'num_outputs',\n 'wavespeed': 'num_outputs',\n },\n },\n {\n universal: 'size',\n providers: {\n 'fal-ai': 'video_size',\n 'replicate': ['width', 'height'],\n 'wavespeed': 'resolution',\n },\n transform: 'parse_size',\n },\n {\n universal: 'guidance',\n providers: {\n 'fal-ai': 'guidance_scale',\n 'replicate': 'guidance',\n 'wavespeed': 'guidance_scale',\n },\n },\n {\n universal: 'steps',\n providers: {\n 'fal-ai': 'num_inference_steps',\n 'replicate': 'num_inference_steps',\n 'wavespeed': 'num_inference_steps',\n },\n },\n {\n universal: 'seed',\n providers: {\n 'fal-ai': 'seed',\n 'replicate': 'seed',\n 'wavespeed': 'seed',\n },\n },\n {\n universal: 'format',\n providers: {\n 'fal-ai': 'output_format',\n 'replicate': 'output_format',\n 'wavespeed': 'output_format',\n },\n },\n {\n universal: 'safety',\n providers: {\n 'fal-ai': 'enable_safety_checker',\n 'replicate': 'disable_safety_checker',\n 'wavespeed': 'enable_safety_checker',\n },\n transform: 'flip_boolean',\n },\n ],\n output_type: 'video',\n output_extract: {\n 'fal-ai': 'video.url',\n 'replicate': 'output',\n 'wavespeed': 'data.outputs[]',\n },\n default_timeout_ms: 300000,\n}\n","import type { CategoryTemplate } from '../types.js'\n\nexport const imageToVideoTemplate: CategoryTemplate = {\n category: 'image-to-video',\n input_mappings: [\n {\n universal: 'image',\n providers: {\n 'fal-ai': 'image_url',\n 'replicate': 'image',\n 'wavespeed': 'image_url',\n },\n required: true,\n },\n {\n universal: 'prompt',\n providers: {\n 'fal-ai': 'prompt',\n 'replicate': 'prompt',\n 'wavespeed': 'prompt',\n },\n },\n {\n universal: 'negative_prompt',\n providers: {\n 'fal-ai': 'negative_prompt',\n 'replicate': 'negative_prompt',\n 'wavespeed': 'negative_prompt',\n },\n },\n {\n universal: 'seed',\n providers: {\n 'fal-ai': 'seed',\n 'replicate': 'seed',\n 'wavespeed': 'seed',\n },\n },\n {\n universal: 'guidance',\n providers: {\n 'fal-ai': 'guidance_scale',\n 'replicate': 'guidance',\n 'wavespeed': 'guidance_scale',\n },\n },\n {\n universal: 'steps',\n providers: {\n 'fal-ai': 'num_inference_steps',\n 'replicate': 'num_inference_steps',\n 'wavespeed': 'num_inference_steps',\n },\n },\n {\n universal: 'format',\n providers: {\n 'fal-ai': 'output_format',\n 'replicate': 'output_format',\n 'wavespeed': 'output_format',\n },\n },\n {\n universal: 'safety',\n providers: {\n 'fal-ai': 'enable_safety_checker',\n 'replicate': 'disable_safety_checker',\n 'wavespeed': 'enable_safety_checker',\n },\n transform: 'flip_boolean',\n },\n ],\n output_type: 'video',\n output_extract: {\n 'fal-ai': 'video.url',\n 'replicate': 'output',\n 'wavespeed': 'data.outputs[]',\n },\n default_timeout_ms: 300000,\n}\n","import type { CategoryTemplate } from '../types.js'\n\nexport const upscaleImageTemplate: CategoryTemplate = {\n category: 'upscale-image',\n input_mappings: [\n {\n universal: 'image',\n providers: {\n 'fal-ai': 'image_url',\n 'replicate': 'image',\n 'wavespeed': 'image_url',\n },\n required: true,\n },\n {\n universal: 'strength',\n providers: {\n 'fal-ai': 'scale',\n 'replicate': 'scale',\n 'wavespeed': 'scale',\n },\n },\n {\n universal: 'format',\n providers: {\n 'fal-ai': 'output_format',\n 'replicate': 'output_format',\n 'wavespeed': 'output_format',\n },\n },\n {\n universal: 'quality',\n providers: {\n 'fal-ai': 'quality',\n 'replicate': 'output_quality',\n 'wavespeed': 'quality',\n },\n },\n ],\n output_type: 'image',\n output_extract: {\n 'fal-ai': 'images[].url',\n 'replicate': 'output[]',\n 'wavespeed': 'data.outputs[]',\n },\n default_timeout_ms: 120000,\n}\n","import type { CategoryTemplate } from '../types.js'\n\nexport const textToAudioTemplate: CategoryTemplate = {\n category: 'text-to-audio',\n input_mappings: [\n {\n universal: 'prompt',\n providers: {\n 'fal-ai': 'text',\n 'replicate': 'prompt',\n 'wavespeed': 'prompt',\n },\n required: true,\n },\n {\n universal: 'count',\n providers: {\n 'fal-ai': 'num_outputs',\n 'replicate': 'num_outputs',\n 'wavespeed': 'num_outputs',\n },\n },\n {\n universal: 'format',\n providers: {\n 'fal-ai': 'output_format',\n 'replicate': 'output_format',\n 'wavespeed': 'output_format',\n },\n },\n {\n universal: 'seed',\n providers: {\n 'fal-ai': 'seed',\n 'replicate': 'seed',\n 'wavespeed': 'seed',\n },\n },\n ],\n output_type: 'audio',\n output_extract: {\n 'fal-ai': 'audio.url',\n 'replicate': 'output',\n 'wavespeed': 'data.outputs[]',\n },\n default_timeout_ms: 60000,\n}\n","import type { CategoryTemplate } from '../types.js'\n\nexport const audioToTextTemplate: CategoryTemplate = {\n category: 'audio-to-text',\n input_mappings: [\n {\n universal: 'audio',\n providers: {\n 'fal-ai': 'audio_url',\n 'replicate': 'audio',\n 'wavespeed': 'audio_url',\n },\n required: true,\n },\n ],\n output_type: 'text',\n output_extract: {\n 'fal-ai': 'text',\n 'replicate': 'output.text',\n 'wavespeed': 'data.outputs[]',\n },\n default_timeout_ms: 120000,\n}\n","import type { CategoryTemplate } from '../types.js'\n\nexport const removeBackgroundTemplate: CategoryTemplate = {\n category: 'remove-background',\n input_mappings: [\n {\n universal: 'image',\n providers: {\n 'fal-ai': 'image_url',\n 'replicate': 'image',\n 'wavespeed': 'image_url',\n },\n required: true,\n },\n {\n universal: 'format',\n providers: {\n 'fal-ai': 'output_format',\n 'replicate': 'output_format',\n 'wavespeed': 'output_format',\n },\n },\n {\n universal: 'quality',\n providers: {\n 'fal-ai': 'quality',\n 'replicate': 'output_quality',\n 'wavespeed': 'quality',\n },\n },\n ],\n output_type: 'image',\n output_extract: {\n 'fal-ai': 'images[].url',\n 'replicate': 'output[]',\n 'wavespeed': 'data.outputs[]',\n },\n default_timeout_ms: 60000,\n}\n","import { textToImageTemplate } from './text-to-image.js'\nimport { imageEditTemplate } from './image-edit.js'\nimport { textToVideoTemplate } from './text-to-video.js'\nimport { imageToVideoTemplate } from './image-to-video.js'\nimport { upscaleImageTemplate } from './upscale-image.js'\nimport { textToAudioTemplate } from './text-to-audio.js'\nimport { audioToTextTemplate } from './audio-to-text.js'\nimport { removeBackgroundTemplate } from './remove-background.js'\nimport type { CategoryTemplate, ModelCategory } from '../types.js'\n\nconst templates: Partial<Record<ModelCategory, CategoryTemplate>> = {\n 'text-to-image': textToImageTemplate,\n 'image-edit': imageEditTemplate,\n 'text-to-video': textToVideoTemplate,\n 'image-to-video': imageToVideoTemplate,\n 'upscale-image': upscaleImageTemplate,\n 'text-to-audio': textToAudioTemplate,\n 'audio-to-text': audioToTextTemplate,\n 'remove-background': removeBackgroundTemplate,\n}\n\nexport function getCategoryTemplate(category: ModelCategory): CategoryTemplate | undefined {\n return templates[category]\n}\n\nexport {\n textToImageTemplate,\n imageEditTemplate,\n textToVideoTemplate,\n imageToVideoTemplate,\n upscaleImageTemplate,\n textToAudioTemplate,\n audioToTextTemplate,\n removeBackgroundTemplate,\n}\n","import type { ProviderAdapter, ProviderResponse, OutputItem, OutputMapping } from \"./base.js\";\nimport { AuthError, RateLimitError, ProviderError, TimeoutError } from \"../errors.js\";\n\nconst BASE_URL = \"https://queue.fal.run\";\n\nasync function handleHttpErrors(\n response: Response,\n endpoint: string,\n): Promise<void> {\n if (response.ok) return;\n\n const status = response.status;\n\n if (status === 401) {\n throw new AuthError(\"fal-ai\", \"FAL_KEY\");\n }\n\n if (status === 429) {\n const retryAfter = response.headers.get(\"retry-after\");\n const retryMs = retryAfter ? parseInt(retryAfter, 10) * 1000 : 60000;\n throw new RateLimitError(\"fal-ai\", retryMs);\n }\n\n let raw: unknown;\n try {\n raw = await response.json();\n } catch {\n raw = await response.text().catch(() => null);\n }\n\n throw new ProviderError(\"fal-ai\", endpoint, status, raw);\n}\n\nfunction authHeaders(auth: string): Record<string, string> {\n return {\n Authorization: `Key ${auth}`,\n \"Content-Type\": \"application/json\",\n };\n}\n\nexport const falAiAdapter: ProviderAdapter = {\n name: \"fal-ai\",\n\n async submit(\n endpoint: string,\n params: Record<string, unknown>,\n auth: string,\n ): Promise<ProviderResponse> {\n const url = `${BASE_URL}/${endpoint}`;\n const response = await fetch(url, {\n method: \"POST\",\n headers: authHeaders(auth),\n body: JSON.stringify(params),\n });\n\n await handleHttpErrors(response, endpoint);\n\n const data = (await response.json()) as { request_id: string };\n\n return {\n id: data.request_id,\n status: \"pending\",\n };\n },\n\n async poll(\n taskId: string,\n auth: string,\n endpoint?: string,\n ): Promise<ProviderResponse> {\n if (!endpoint) {\n throw new ProviderError(\"fal-ai\", \"unknown\", 400, \"endpoint is required for polling\");\n }\n\n // Check status\n const statusUrl = `${BASE_URL}/${endpoint}/requests/${taskId}/status`;\n const statusResponse = await fetch(statusUrl, {\n headers: { Authorization: `Key ${auth}` },\n });\n\n await handleHttpErrors(statusResponse, endpoint);\n\n const statusData = (await statusResponse.json()) as {\n status: \"IN_QUEUE\" | \"IN_PROGRESS\" | \"COMPLETED\" | \"FAILED\";\n error?: string;\n };\n\n if (statusData.status === \"FAILED\") {\n return {\n id: taskId,\n status: \"failed\",\n error: statusData.error ?? \"Unknown error\",\n };\n }\n\n if (statusData.status !== \"COMPLETED\") {\n return {\n id: taskId,\n status: \"processing\",\n };\n }\n\n // Fetch result\n const resultUrl = `${BASE_URL}/${endpoint}/requests/${taskId}`;\n const resultResponse = await fetch(resultUrl, {\n headers: { Authorization: `Key ${auth}` },\n });\n\n await handleHttpErrors(resultResponse, endpoint);\n\n const output = await resultResponse.json();\n\n return {\n id: taskId,\n status: \"completed\",\n output,\n };\n },\n\n parseOutput(raw: unknown, outputMapping: OutputMapping): OutputItem[] {\n const data = raw as Record<string, unknown>;\n const path = outputMapping.extract_path;\n\n if (path === \"images[].url\") {\n const images = data.images as Array<{\n url: string;\n content_type?: string;\n }>;\n if (!Array.isArray(images)) return [];\n return images.map((img) => ({\n type: outputMapping.type,\n url: img.url,\n content_type: img.content_type ?? outputMapping.content_type ?? \"image/jpeg\",\n }));\n }\n\n if (path === \"video.url\") {\n const video = data.video as { url: string; content_type?: string } | undefined;\n if (!video?.url) return [];\n return [\n {\n type: outputMapping.type,\n url: video.url,\n content_type: video.content_type ?? outputMapping.content_type ?? \"video/mp4\",\n },\n ];\n }\n\n if (path === \"audio.url\") {\n const audio = data.audio as { url: string; content_type?: string } | undefined;\n if (!audio?.url) return [];\n return [\n {\n type: outputMapping.type,\n url: audio.url,\n content_type: audio.content_type ?? outputMapping.content_type ?? \"audio/mpeg\",\n },\n ];\n }\n\n return [];\n },\n};\n\n/**\n * Submit a request and poll until completion or timeout.\n */\nexport async function submitAndPoll(\n endpoint: string,\n params: Record<string, unknown>,\n auth: string,\n options?: {\n timeoutMs?: number;\n intervalMs?: number;\n maxIntervalMs?: number;\n },\n): Promise<ProviderResponse> {\n const timeoutMs = options?.timeoutMs ?? 300_000;\n const startInterval = options?.intervalMs ?? 1000;\n const maxInterval = options?.maxIntervalMs ?? 5000;\n\n const submitted = await falAiAdapter.submit(endpoint, params, auth);\n const taskId = submitted.id;\n\n const start = Date.now();\n let interval = startInterval;\n\n while (Date.now() - start < timeoutMs) {\n await sleep(interval);\n\n const result = await falAiAdapter.poll(taskId, auth, endpoint);\n\n if (result.status === \"completed\" || result.status === \"failed\") {\n return result;\n }\n\n interval = Math.min(interval + 500, maxInterval);\n }\n\n throw new TimeoutError(\"fal-ai\", endpoint, timeoutMs);\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n","import type { ProviderAdapter, ProviderResponse, OutputItem, OutputMapping } from \"./base.js\";\nimport { AuthError, RateLimitError, ProviderError } from \"../errors.js\";\n\nconst BASE_URL = \"https://api.replicate.com/v1\";\n\nasync function handleHttpErrors(\n response: Response,\n endpoint: string,\n): Promise<void> {\n if (response.ok) return;\n\n const status = response.status;\n\n if (status === 401) {\n throw new AuthError(\"replicate\", \"REPLICATE_API_TOKEN\");\n }\n\n if (status === 429) {\n const retryAfter = response.headers.get(\"retry-after\");\n const retryMs = retryAfter ? parseInt(retryAfter, 10) * 1000 : 60000;\n throw new RateLimitError(\"replicate\", retryMs);\n }\n\n let raw: unknown;\n try {\n raw = await response.json();\n } catch {\n raw = await response.text().catch(() => null);\n }\n\n throw new ProviderError(\"replicate\", endpoint, status, raw);\n}\n\nfunction authHeaders(auth: string): Record<string, string> {\n return {\n Authorization: `Bearer ${auth}`,\n \"Content-Type\": \"application/json\",\n };\n}\n\nfunction inferContentType(url: string): string {\n const lower = url.toLowerCase();\n if (lower.includes(\".png\")) return \"image/png\";\n if (lower.includes(\".jpg\") || lower.includes(\".jpeg\")) return \"image/jpeg\";\n if (lower.includes(\".webp\")) return \"image/webp\";\n if (lower.includes(\".mp4\")) return \"video/mp4\";\n if (lower.includes(\".mp3\")) return \"audio/mpeg\";\n if (lower.includes(\".wav\")) return \"audio/wav\";\n return \"image/jpeg\";\n}\n\nexport const replicateAdapter: ProviderAdapter = {\n name: \"replicate\",\n\n async submit(\n endpoint: string,\n params: Record<string, unknown>,\n auth: string,\n ): Promise<ProviderResponse> {\n const url = `${BASE_URL}/models/${endpoint}/predictions`;\n const response = await fetch(url, {\n method: \"POST\",\n headers: authHeaders(auth),\n body: JSON.stringify({ input: params }),\n });\n\n await handleHttpErrors(response, endpoint);\n\n const data = (await response.json()) as { id: string };\n\n return {\n id: data.id,\n status: \"pending\",\n };\n },\n\n async poll(\n taskId: string,\n auth: string,\n ): Promise<ProviderResponse> {\n const url = `${BASE_URL}/predictions/${taskId}`;\n const response = await fetch(url, {\n headers: { Authorization: `Bearer ${auth}` },\n });\n\n await handleHttpErrors(response, taskId);\n\n const data = (await response.json()) as {\n id: string;\n status: \"starting\" | \"processing\" | \"succeeded\" | \"failed\" | \"canceled\";\n output?: unknown;\n error?: string;\n };\n\n if (data.status === \"succeeded\") {\n return {\n id: data.id,\n status: \"completed\",\n output: data.output,\n };\n }\n\n if (data.status === \"failed\" || data.status === \"canceled\") {\n return {\n id: data.id,\n status: \"failed\",\n error: data.error ?? `Prediction ${data.status}`,\n };\n }\n\n // starting or processing\n return {\n id: data.id,\n status: \"processing\",\n };\n },\n\n parseOutput(raw: unknown, outputMapping: OutputMapping): OutputItem[] {\n // Replicate output is typically string[] (URLs)\n if (!Array.isArray(raw)) return [];\n\n return (raw as string[]).map((url) => ({\n type: outputMapping.type,\n url,\n content_type: outputMapping.content_type ?? inferContentType(url),\n }));\n },\n};\n","import type { ProviderAdapter, ProviderResponse, OutputItem, OutputMapping } from \"./base.js\";\nimport { AuthError, RateLimitError, ProviderError } from \"../errors.js\";\n\nconst BASE_URL = \"https://api.wavespeed.ai/api/v3\";\n\nasync function handleHttpErrors(\n response: Response,\n endpoint: string,\n): Promise<void> {\n if (response.ok) return;\n\n const status = response.status;\n\n if (status === 401) {\n throw new AuthError(\"wavespeed\", \"WAVESPEED_API_KEY\");\n }\n\n if (status === 429) {\n const retryAfter = response.headers.get(\"retry-after\");\n const retryMs = retryAfter ? parseInt(retryAfter, 10) * 1000 : 60000;\n throw new RateLimitError(\"wavespeed\", retryMs);\n }\n\n let raw: unknown;\n try {\n raw = await response.json();\n } catch {\n raw = await response.text().catch(() => null);\n }\n\n throw new ProviderError(\"wavespeed\", endpoint, status, raw);\n}\n\nfunction authHeaders(auth: string): Record<string, string> {\n return {\n Authorization: `Bearer ${auth}`,\n \"Content-Type\": \"application/json\",\n };\n}\n\nfunction inferContentType(url: string): string {\n const ext = url.split(\".\").pop()?.toLowerCase()?.split(\"?\")[0];\n switch (ext) {\n case \"png\":\n return \"image/png\";\n case \"jpg\":\n case \"jpeg\":\n return \"image/jpeg\";\n case \"webp\":\n return \"image/webp\";\n case \"gif\":\n return \"image/gif\";\n case \"mp4\":\n return \"video/mp4\";\n case \"mp3\":\n return \"audio/mpeg\";\n case \"wav\":\n return \"audio/wav\";\n default:\n return \"application/octet-stream\";\n }\n}\n\nexport const wavespeedAdapter: ProviderAdapter = {\n name: \"wavespeed\",\n\n async submit(\n endpoint: string,\n params: Record<string, unknown>,\n auth: string,\n ): Promise<ProviderResponse> {\n const url = `${BASE_URL}/${endpoint}`;\n const response = await fetch(url, {\n method: \"POST\",\n headers: authHeaders(auth),\n body: JSON.stringify(params),\n });\n\n await handleHttpErrors(response, endpoint);\n\n const json = (await response.json()) as {\n data: { id: string; status: string };\n };\n\n return {\n id: json.data.id,\n status: \"pending\",\n };\n },\n\n async poll(\n taskId: string,\n auth: string,\n ): Promise<ProviderResponse> {\n const url = `${BASE_URL}/predictions/${taskId}/result`;\n const response = await fetch(url, {\n headers: { Authorization: `Bearer ${auth}` },\n });\n\n await handleHttpErrors(response, `predictions/${taskId}/result`);\n\n const json = (await response.json()) as {\n data: {\n id: string;\n status: string;\n outputs?: string[];\n error?: string;\n };\n };\n\n const { data } = json;\n\n if (data.status === \"failed\") {\n return {\n id: taskId,\n status: \"failed\",\n error: data.error ?? \"Unknown error\",\n };\n }\n\n if (data.status === \"completed\") {\n return {\n id: taskId,\n status: \"completed\",\n output: data,\n };\n }\n\n // created or processing\n return {\n id: taskId,\n status: \"processing\",\n };\n },\n\n parseOutput(raw: unknown, outputMapping: OutputMapping): OutputItem[] {\n const data = raw as Record<string, unknown>;\n const outputs = data.outputs as string[] | undefined;\n\n if (!Array.isArray(outputs)) return [];\n\n return outputs.map((url) => ({\n type: outputMapping.type,\n url,\n content_type: outputMapping.content_type ?? inferContentType(url),\n }));\n },\n};\n","import {\n AuthError,\n ValidationError,\n ModelNotFoundError,\n ProviderError,\n RateLimitError,\n TimeoutError,\n} from './errors.js'\n\nexport interface RetryOptions {\n maxRetries: number\n initialDelayMs: number\n maxDelayMs: number\n timeoutMs: number\n}\n\nconst DEFAULT_OPTIONS: RetryOptions = {\n maxRetries: 3,\n initialDelayMs: 1000,\n maxDelayMs: 10000,\n timeoutMs: 300_000,\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms))\n}\n\nfunction isRetryable(error: unknown): boolean {\n // Never retry auth, validation, or model-not-found errors\n if (\n error instanceof AuthError ||\n error instanceof ValidationError ||\n error instanceof ModelNotFoundError\n ) {\n return false\n }\n\n // Retry rate limit errors (429)\n if (error instanceof RateLimitError) {\n return true\n }\n\n // ProviderError: only retry 5xx, not 4xx\n if (error instanceof ProviderError) {\n return error.statusCode >= 500\n }\n\n // Network errors (TypeError from fetch, etc.) are retryable\n if (error instanceof TypeError) {\n return true\n }\n\n return false\n}\n\nfunction getDelayMs(\n error: unknown,\n attempt: number,\n options: RetryOptions,\n): number {\n // RateLimitError has its own retry-after\n if (error instanceof RateLimitError) {\n return error.retryAfterMs\n }\n\n // Exponential backoff with jitter\n const jitter = Math.random() * options.initialDelayMs * 0.5\n const delay = options.initialDelayMs * Math.pow(2, attempt) + jitter\n return Math.min(delay, options.maxDelayMs)\n}\n\nexport async function withRetry<T>(\n fn: () => Promise<T>,\n options?: Partial<RetryOptions>,\n): Promise<T> {\n const opts: RetryOptions = { ...DEFAULT_OPTIONS, ...options }\n const startTime = Date.now()\n let lastError: unknown\n\n for (let attempt = 0; attempt <= opts.maxRetries; attempt++) {\n // Check total timeout before attempting\n if (attempt > 0) {\n const elapsed = Date.now() - startTime\n if (elapsed >= opts.timeoutMs) {\n throw new TimeoutError('unknown', 'unknown', opts.timeoutMs)\n }\n }\n\n try {\n return await fn()\n } catch (error) {\n lastError = error\n\n // If not retryable, throw immediately\n if (!isRetryable(error)) {\n throw error\n }\n\n // If we've exhausted retries, throw\n if (attempt >= opts.maxRetries) {\n throw error\n }\n\n const delay = getDelayMs(error, attempt, opts)\n\n // Check if waiting would exceed timeout\n const elapsed = Date.now() - startTime\n if (elapsed + delay >= opts.timeoutMs) {\n throw new TimeoutError('unknown', 'unknown', opts.timeoutMs)\n }\n\n await sleep(delay)\n }\n }\n\n // Should not reach here, but just in case\n throw lastError\n}\n","import type { ModelEntry, ModelCategory, ProviderName } from \"./types.js\";\nimport { loadRegistry } from \"./resolver.js\";\nimport { resolveModel } from \"./resolver.js\";\nimport { AuthManager } from \"./auth.js\";\n\nexport interface ListModelsFilters {\n category?: ModelCategory;\n provider?: ProviderName;\n query?: string; // search canonical name and aliases\n}\n\n/**\n * Lists all models the caller can access (has API keys for).\n * Optionally filters by category, provider, or text query.\n */\nexport function listModels(filters?: ListModelsFilters): ModelEntry[] {\n const auth = new AuthManager();\n let models = auth.listAvailableModels(loadRegistry());\n\n if (filters?.category) {\n models = models.filter((m) => m.category === filters.category);\n }\n if (filters?.provider) {\n models = models.filter((m) =>\n m.providers.some((p) => p.provider === filters.provider),\n );\n }\n if (filters?.query) {\n const q = filters.query.toLowerCase();\n models = models.filter(\n (m) =>\n m.canonical_name.includes(q) ||\n m.aliases.some((a) => a.includes(q)),\n );\n }\n\n return models;\n}\n\n/**\n * Resolves a model by name (canonical name, alias, or fuzzy match).\n * Throws ModelNotFoundError if no match is found.\n */\nexport function getModel(name: string): ModelEntry {\n return resolveModel(name);\n}\n"],"mappings":"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","names":["BASE_URL","handleHttpErrors","authHeaders","BASE_URL","handleHttpErrors","authHeaders","inferContentType","resolve","resolve"]}
|
|
1
|
+
{"version":3,"sources":["../src/gateway.ts","../src/errors.ts","../src/auth.ts","../src/resolver.ts","../src/mapper.ts","../src/categories/text-to-image.ts","../src/categories/image-edit.ts","../src/categories/text-to-video.ts","../src/categories/image-to-video.ts","../src/categories/upscale-image.ts","../src/categories/text-to-audio.ts","../src/categories/audio-to-text.ts","../src/categories/remove-background.ts","../src/categories/index.ts","../src/adapters/fal-ai.ts","../src/adapters/replicate.ts","../src/adapters/wavespeed.ts","../src/retry.ts","../src/discovery.ts"],"sourcesContent":["import { randomUUID } from 'crypto'\nimport { AuthManager } from './auth.js'\nimport { resolveModel } from './resolver.js'\nimport { mapInput, mapOutput } from './mapper.js'\nimport { getCategoryTemplate } from './categories/index.js'\nimport { falAiAdapter } from './adapters/fal-ai.js'\nimport { replicateAdapter } from './adapters/replicate.js'\nimport { wavespeedAdapter } from './adapters/wavespeed.js'\nimport type { GenerateRequest, GenerateResponse, ProviderAdapter, ProviderName } from './types.js'\nimport { ValidationError, ProviderError } from './errors.js'\nimport { withRetry } from './retry.js'\n\n// Adapter registry\nconst adapters: Record<string, ProviderAdapter> = {\n 'fal-ai': falAiAdapter,\n 'replicate': replicateAdapter,\n 'wavespeed': wavespeedAdapter,\n}\n\nexport async function generate(request: GenerateRequest): Promise<GenerateResponse> {\n const startTime = Date.now()\n\n // 1. Validate request\n if (!request.model) throw new ValidationError('model', 'model is required')\n\n // 2. Auth - check available providers\n const auth = new AuthManager()\n\n // 3. Resolve model\n const model = resolveModel(request.model, auth.availableProviders())\n\n // 4. Pick provider (first available)\n const availableBindings = model.providers.filter(p =>\n auth.availableProviders().includes(p.provider) && adapters[p.provider]\n )\n if (availableBindings.length === 0) {\n throw new ValidationError(\n 'model',\n `No adapter available for model \"${model.canonical_name}\". Available providers: ${model.providers.map(p => p.provider).join(', ')}`,\n )\n }\n const binding = availableBindings[0]\n\n // 5. Get category template\n const template = getCategoryTemplate(model.category)\n if (!template) {\n throw new ValidationError('model', `No category template for \"${model.category}\" yet`)\n }\n\n // 6. Map input\n const providerParams = mapInput(request, binding, template)\n\n // 7. Get adapter and auth key\n const adapter = adapters[binding.provider]\n const apiKey = auth.getKey(binding.provider)\n\n // 8. Submit with retry, then poll\n const timeoutMs = (request.options?.timeout as number | undefined) ?? template.default_timeout_ms\n const submitted = await withRetry(\n () => adapter.submit(binding.endpoint, providerParams, apiKey),\n { timeoutMs },\n )\n\n let result = submitted\n while (result.status === 'processing' || result.status === 'pending') {\n await new Promise(resolve => setTimeout(resolve, 1000))\n result = await adapter.poll(submitted.id, apiKey, binding.endpoint)\n }\n\n if (result.status === 'failed') {\n throw new ProviderError(\n binding.provider,\n model.canonical_name,\n 0,\n result.error || 'Generation failed',\n )\n }\n\n // 9. Map output\n const outputs = mapOutput(result.output, binding.output_map)\n\n // 10. Build response\n return {\n id: randomUUID(),\n model: model.canonical_name,\n provider: binding.provider,\n status: 'completed',\n outputs,\n metadata: {\n inference_time_ms: Date.now() - startTime,\n seed: typeof result.output === 'object' && result.output !== null\n ? (result.output as Record<string, unknown>).seed as number | undefined\n : undefined,\n safety_flagged: typeof result.output === 'object' && result.output !== null\n ? (\n Array.isArray((result.output as Record<string, unknown>).has_nsfw_concepts)\n ? ((result.output as Record<string, unknown>).has_nsfw_concepts as boolean[]).some((v: boolean) => v)\n : undefined\n )\n : undefined,\n },\n }\n}\n","import type { ProviderName } from \"./types.js\";\n\nexport class GetAIApiError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"GetAIApiError\";\n }\n}\n\nexport class AuthError extends GetAIApiError {\n readonly provider: ProviderName;\n readonly envVar: string;\n\n constructor(provider: ProviderName, envVar: string) {\n super(`Missing or invalid API key for ${provider}. Set the ${envVar} environment variable.`);\n this.name = \"AuthError\";\n this.provider = provider;\n this.envVar = envVar;\n }\n}\n\nexport class ModelNotFoundError extends GetAIApiError {\n readonly query: string;\n readonly suggestions: string[];\n\n constructor(query: string, suggestions: string[] = []) {\n const hint =\n suggestions.length > 0\n ? ` Did you mean: ${suggestions.join(\", \")}?`\n : \"\";\n super(`Model \"${query}\" not found.${hint}`);\n this.name = \"ModelNotFoundError\";\n this.query = query;\n this.suggestions = suggestions;\n }\n}\n\nexport class ValidationError extends GetAIApiError {\n readonly field: string;\n\n constructor(field: string, message: string) {\n super(`Validation error on \"${field}\": ${message}`);\n this.name = \"ValidationError\";\n this.field = field;\n }\n}\n\nexport class ProviderError extends GetAIApiError {\n readonly provider: ProviderName;\n readonly model: string;\n readonly statusCode: number;\n readonly raw: unknown;\n\n constructor(\n provider: ProviderName,\n model: string,\n statusCode: number,\n raw: unknown,\n ) {\n super(\n `Provider ${provider} returned status ${statusCode} for model \"${model}\".`,\n );\n this.name = \"ProviderError\";\n this.provider = provider;\n this.model = model;\n this.statusCode = statusCode;\n this.raw = raw;\n }\n}\n\nexport class TimeoutError extends GetAIApiError {\n readonly provider: ProviderName;\n readonly model: string;\n readonly timeoutMs: number;\n\n constructor(provider: ProviderName, model: string, timeoutMs: number) {\n super(\n `Generation timed out after ${timeoutMs}ms for model \"${model}\" on ${provider}.`,\n );\n this.name = \"TimeoutError\";\n this.provider = provider;\n this.model = model;\n this.timeoutMs = timeoutMs;\n }\n}\n\nexport class RateLimitError extends GetAIApiError {\n readonly provider: ProviderName;\n readonly retryAfterMs: number;\n\n constructor(provider: ProviderName, retryAfterMs: number) {\n super(\n `Rate limited by ${provider}. Retry after ${retryAfterMs}ms.`,\n );\n this.name = \"RateLimitError\";\n this.provider = provider;\n this.retryAfterMs = retryAfterMs;\n }\n}\n","import type { ProviderName, ModelEntry } from \"./types.js\";\nimport { AuthError } from \"./errors.js\";\n\nconst ENV_MAP: Record<ProviderName, string> = {\n \"fal-ai\": \"FAL_KEY\",\n replicate: \"REPLICATE_API_TOKEN\",\n wavespeed: \"WAVESPEED_API_KEY\",\n};\n\nexport class AuthManager {\n private keys: Map<string, string>;\n\n constructor() {\n this.keys = new Map();\n for (const [provider, envVar] of Object.entries(ENV_MAP)) {\n const key = process.env[envVar]?.trim();\n if (key) this.keys.set(provider, key);\n }\n }\n\n availableProviders(): ProviderName[] {\n return [...this.keys.keys()] as ProviderName[];\n }\n\n getKey(provider: ProviderName): string {\n const key = this.keys.get(provider);\n if (!key) {\n throw new AuthError(provider, ENV_MAP[provider]);\n }\n return key;\n }\n\n canAccess(model: ModelEntry): boolean {\n return model.providers.some((p) => this.keys.has(p.provider));\n }\n\n listAvailableModels(registry: ModelEntry[]): ModelEntry[] {\n return registry.filter((m) => this.canAccess(m));\n }\n}\n","import { readFileSync } from \"fs\";\nimport { resolve, dirname } from \"path\";\nimport { fileURLToPath } from \"url\";\nimport type { ModelEntry, ProviderName } from \"./types.js\";\nimport { ModelNotFoundError } from \"./errors.js\";\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\n\nlet registryCache: ModelEntry[] | null = null;\n\n/**\n * Reads and parses registry/registry.json.\n * Caches the result so the file is only loaded once.\n */\nexport function loadRegistry(): ModelEntry[] {\n if (registryCache) {\n return registryCache;\n }\n\n // Try resolving from project root (works both from src/ and dist/)\n // Walk up from current file to find the registry directory\n let dir = __dirname;\n for (let i = 0; i < 5; i++) {\n const candidate = resolve(dir, \"registry\", \"registry.json\");\n try {\n const raw = readFileSync(candidate, \"utf-8\");\n registryCache = JSON.parse(raw) as ModelEntry[];\n return registryCache;\n } catch {\n dir = dirname(dir);\n }\n }\n\n throw new Error(\n \"Could not find registry/registry.json. Searched upward from: \" + __dirname,\n );\n}\n\n/**\n * Normalizes a model name for fuzzy matching.\n * - Lowercase\n * - Strip all non-alphanumeric characters\n * - Strip leading 'v' from version numbers (e.g., \"v4.5\" -> \"45\")\n */\nexport function normalizeModelName(input: string): string {\n return input\n .toLowerCase()\n .replace(/[^a-z0-9]/g, \"\")\n .replace(/(?<=\\d)v(?=\\d)/g, \"\") // v between digits (unlikely but safe)\n .replace(/v(?=\\d)/g, \"\"); // v before digits\n}\n\n/**\n * Resolves a user's model name query to a matching ModelEntry.\n *\n * Resolution order:\n * 1. Exact canonical match\n * 2. Exact alias match\n * 3. Normalized canonical match\n * 4. Normalized alias match\n * 5. No match -> throw ModelNotFoundError with suggestions\n */\nexport function resolveModel(\n query: string,\n availableProviders?: ProviderName[],\n): ModelEntry {\n if (!query || typeof query !== \"string\" || query.trim() === \"\") {\n throw new ModelNotFoundError(\"Model name is required\");\n }\n\n const trimmedQuery = query.trim();\n const registry = loadRegistry();\n\n let matched: ModelEntry | undefined;\n\n // 1. Exact canonical match\n matched = registry.find((e) => e.canonical_name === trimmedQuery);\n\n // 2. Exact alias match\n if (!matched) {\n matched = registry.find((e) =>\n e.aliases.some((a) => a === trimmedQuery),\n );\n }\n\n // 3. Normalized canonical match\n if (!matched) {\n const normalizedQuery = normalizeModelName(trimmedQuery);\n matched = registry.find(\n (e) => normalizeModelName(e.canonical_name) === normalizedQuery,\n );\n\n // 4. Normalized alias match\n if (!matched) {\n matched = registry.find((e) =>\n e.aliases.some((a) => normalizeModelName(a) === normalizedQuery),\n );\n }\n }\n\n if (!matched) {\n const suggestions = findSuggestions(trimmedQuery, registry);\n throw new ModelNotFoundError(trimmedQuery, suggestions);\n }\n\n // Apply provider filtering after matching\n if (availableProviders && availableProviders.length > 0) {\n const filteredProviders = matched.providers.filter((p) =>\n availableProviders.includes(p.provider),\n );\n\n if (filteredProviders.length === 0) {\n const suggestions = findSuggestions(trimmedQuery, registry);\n throw new ModelNotFoundError(trimmedQuery, suggestions);\n }\n\n return { ...matched, providers: filteredProviders };\n }\n\n return matched;\n}\n\n/**\n * Find up to 5 suggestions for a failed query.\n * Uses prefix and substring matching on normalized names.\n * Sorted by canonical_name length (shorter = more likely intended).\n */\nfunction findSuggestions(\n query: string,\n registry: ModelEntry[],\n): string[] {\n const normalizedQuery = normalizeModelName(query);\n\n if (normalizedQuery === \"\") {\n return [];\n }\n\n const matches = registry.filter((e) => {\n const normalizedCanonical = normalizeModelName(e.canonical_name);\n // Check if either is a prefix/substring of the other\n if (\n normalizedCanonical.startsWith(normalizedQuery) ||\n normalizedCanonical.includes(normalizedQuery) ||\n normalizedQuery.startsWith(normalizedCanonical)\n ) {\n return true;\n }\n // Check for a meaningful shared prefix (at least 3 chars)\n const minLen = Math.min(normalizedQuery.length, normalizedCanonical.length);\n let shared = 0;\n for (let i = 0; i < minLen; i++) {\n if (normalizedQuery[i] === normalizedCanonical[i]) {\n shared++;\n } else {\n break;\n }\n }\n return shared >= 3 && shared >= normalizedQuery.length * 0.3;\n });\n\n return matches\n .sort((a, b) => a.canonical_name.length - b.canonical_name.length)\n .slice(0, 5)\n .map((e) => e.canonical_name);\n}\n\n/**\n * Clears the registry cache. Useful for testing.\n */\nexport function clearRegistryCache(): void {\n registryCache = null;\n}\n","import type {\n GenerateRequest,\n ProviderBinding,\n CategoryTemplate,\n ParamMapping,\n OutputItem,\n OutputMapping,\n ProviderName,\n} from './types.js'\nimport { ValidationError } from './errors.js'\n\n/**\n * Maps a universal GenerateRequest to provider-specific params\n * using the category template's input_mappings.\n */\nexport function mapInput(\n request: GenerateRequest,\n binding: ProviderBinding,\n template: CategoryTemplate,\n): Record<string, unknown> {\n const result: Record<string, unknown> = {}\n const provider = binding.provider\n\n for (const mapping of template.input_mappings) {\n const value = getUniversalValue(request, mapping.universal)\n\n if (value === undefined || value === null) {\n if (mapping.required) {\n throw new ValidationError(\n mapping.universal,\n `\"${mapping.universal}\" is required but was not provided.`,\n )\n }\n continue\n }\n\n const providerKey = mapping.providers[provider]\n if (providerKey === undefined) {\n // Provider doesn't support this param — silently drop\n continue\n }\n\n const transformed = applyTransform(value, mapping, provider)\n\n if (Array.isArray(providerKey)) {\n // Spread into multiple params (e.g., Replicate's [\"width\", \"height\"])\n if (typeof transformed === 'object' && transformed !== null && !Array.isArray(transformed)) {\n const obj = transformed as Record<string, unknown>\n for (const key of providerKey) {\n if (obj[key] !== undefined) {\n result[key] = obj[key]\n }\n }\n }\n } else {\n result[providerKey] = transformed\n }\n }\n\n // Merge options passthrough — options wins on conflict\n if (request.options) {\n for (const [key, val] of Object.entries(request.options)) {\n result[key] = val\n }\n }\n\n return result\n}\n\n/**\n * Extracts a universal field value from the GenerateRequest.\n */\nfunction getUniversalValue(request: GenerateRequest, field: string): unknown {\n return (request as unknown as Record<string, unknown>)[field]\n}\n\n/**\n * Applies the specified transform to the value.\n */\nfunction applyTransform(\n value: unknown,\n mapping: ParamMapping,\n provider: ProviderName,\n): unknown {\n const transform = mapping.transform\n\n if (!transform || transform === 'none') {\n return value\n }\n\n if (transform === 'flip_boolean') {\n if (provider === 'replicate') {\n return !value\n }\n return value\n }\n\n if (transform === 'parse_size') {\n return parseSizeForProvider(value, mapping, provider)\n }\n\n return value\n}\n\n/**\n * Converts a size value to the provider-specific format.\n */\nfunction parseSizeForProvider(\n value: unknown,\n mapping: ParamMapping,\n provider: ProviderName,\n): unknown {\n if (provider === 'fal-ai') {\n if (typeof value === 'string') {\n const [w, h] = value.split('x').map(Number)\n return { width: w, height: h }\n }\n // Object passthrough\n return value\n }\n\n if (provider === 'replicate') {\n if (typeof value === 'string') {\n const [w, h] = value.split('x').map(Number)\n return { width: w, height: h }\n }\n if (typeof value === 'object' && value !== null) {\n return value\n }\n return value\n }\n\n // wavespeed and others: pass through as-is\n return value\n}\n\n/**\n * Maps raw provider response to OutputItem[] using the output mapping.\n */\nexport function mapOutput(raw: unknown, outputMapping: OutputMapping): OutputItem[] {\n const { type, extract_path, content_type } = outputMapping\n const defaultContentType = content_type || 'image/jpeg'\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const data = raw as any\n\n if (extract_path === 'images[].url') {\n const images: unknown[] = data?.images ?? []\n return images.map((img: any) => ({\n type,\n url: img.url as string,\n content_type: (img.content_type as string) || defaultContentType,\n }))\n }\n\n if (extract_path === 'output[]') {\n const arr: unknown[] = Array.isArray(data) ? data : data?.output ?? []\n return arr.map((url: unknown) => ({\n type,\n url: url as string,\n content_type: defaultContentType,\n }))\n }\n\n if (extract_path === 'data.outputs[]') {\n const outputs: unknown[] = data?.data?.outputs ?? []\n return outputs.map((url: unknown) => ({\n type,\n url: url as string,\n content_type: defaultContentType,\n }))\n }\n\n if (extract_path === 'video.url') {\n return [{\n type: 'video',\n url: data?.video?.url as string,\n content_type: 'video/mp4',\n }]\n }\n\n if (extract_path === 'audio.url') {\n return [{\n type: 'audio',\n url: data?.audio?.url as string,\n content_type: 'audio/mpeg',\n }]\n }\n\n // Generic dot-notation traversal for unknown paths\n return genericExtract(data, extract_path, type, defaultContentType)\n}\n\n/**\n * Generic dot-notation traversal for unknown extract paths.\n * Supports paths like \"foo.bar[].baz\".\n */\nfunction genericExtract(\n data: unknown,\n path: string,\n type: OutputMapping['type'],\n contentType: string,\n): OutputItem[] {\n const segments = path.split('.')\n let current: unknown = data\n\n for (const seg of segments) {\n if (current === null || current === undefined) return []\n\n const arrayMatch = seg.match(/^(.+)\\[\\]$/)\n if (arrayMatch) {\n const key = arrayMatch[1]\n current = (current as Record<string, unknown>)[key]\n if (Array.isArray(current)) {\n // If there are more segments after this, we'd need to map deeper\n // For now, treat as final array\n const remaining = segments.slice(segments.indexOf(seg) + 1).join('.')\n if (remaining) {\n return (current as unknown[]).map((item: any) => ({\n type,\n url: getNestedValue(item, remaining) as string,\n content_type: contentType,\n }))\n }\n return (current as unknown[]).map((item: unknown) => ({\n type,\n url: (typeof item === 'string' ? item : (item as any)?.url) as string,\n content_type: contentType,\n }))\n }\n return []\n }\n\n current = (current as Record<string, unknown>)[seg]\n }\n\n // Single value at end of path\n if (typeof current === 'string') {\n return [{ type, url: current, content_type: contentType }]\n }\n\n return []\n}\n\nfunction getNestedValue(obj: unknown, path: string): unknown {\n let current = obj\n for (const key of path.split('.')) {\n if (current === null || current === undefined) return undefined\n current = (current as Record<string, unknown>)[key]\n }\n return current\n}\n","import type { CategoryTemplate } from '../types.js'\n\nexport const textToImageTemplate: CategoryTemplate = {\n category: 'text-to-image',\n input_mappings: [\n {\n universal: 'prompt',\n providers: {\n 'fal-ai': 'prompt',\n 'replicate': 'prompt',\n 'wavespeed': 'prompt',\n },\n required: true,\n },\n {\n universal: 'negative_prompt',\n providers: {\n 'fal-ai': 'negative_prompt',\n 'replicate': 'negative_prompt',\n 'wavespeed': 'negative_prompt',\n },\n },\n {\n universal: 'count',\n providers: {\n 'fal-ai': 'num_images',\n 'replicate': 'num_outputs',\n 'wavespeed': 'num_outputs',\n },\n },\n {\n universal: 'size',\n providers: {\n 'fal-ai': 'image_size',\n 'replicate': ['width', 'height'],\n 'wavespeed': 'resolution',\n },\n transform: 'parse_size',\n },\n {\n universal: 'guidance',\n providers: {\n 'fal-ai': 'guidance_scale',\n 'replicate': 'guidance',\n 'wavespeed': 'guidance_scale',\n },\n },\n {\n universal: 'steps',\n providers: {\n 'fal-ai': 'num_inference_steps',\n 'replicate': 'num_inference_steps',\n 'wavespeed': 'num_inference_steps',\n },\n },\n {\n universal: 'seed',\n providers: {\n 'fal-ai': 'seed',\n 'replicate': 'seed',\n 'wavespeed': 'seed',\n },\n },\n {\n universal: 'format',\n providers: {\n 'fal-ai': 'output_format',\n 'replicate': 'output_format',\n 'wavespeed': 'output_format',\n },\n },\n {\n universal: 'quality',\n providers: {\n 'fal-ai': 'quality',\n 'replicate': 'output_quality',\n 'wavespeed': 'quality',\n },\n },\n {\n universal: 'safety',\n providers: {\n 'fal-ai': 'enable_safety_checker',\n 'replicate': 'disable_safety_checker',\n 'wavespeed': 'enable_safety_checker',\n },\n transform: 'flip_boolean',\n },\n ],\n output_type: 'image',\n output_extract: {\n 'fal-ai': 'images[].url',\n 'replicate': 'output[]',\n 'wavespeed': 'data.outputs[]',\n },\n default_timeout_ms: 60000,\n}\n","import type { CategoryTemplate } from '../types.js'\n\nexport const imageEditTemplate: CategoryTemplate = {\n category: 'image-edit',\n input_mappings: [\n {\n universal: 'image',\n providers: {\n 'fal-ai': 'image_url',\n 'replicate': 'image',\n 'wavespeed': 'image_url',\n },\n required: true,\n },\n {\n universal: 'prompt',\n providers: {\n 'fal-ai': 'prompt',\n 'replicate': 'prompt',\n 'wavespeed': 'prompt',\n },\n required: true,\n },\n {\n universal: 'strength',\n providers: {\n 'fal-ai': 'strength',\n 'replicate': 'strength',\n 'wavespeed': 'strength',\n },\n },\n {\n universal: 'mask',\n providers: {\n 'fal-ai': 'mask_url',\n 'replicate': 'mask',\n 'wavespeed': 'mask_url',\n },\n },\n {\n universal: 'seed',\n providers: {\n 'fal-ai': 'seed',\n 'replicate': 'seed',\n 'wavespeed': 'seed',\n },\n },\n {\n universal: 'format',\n providers: {\n 'fal-ai': 'output_format',\n 'replicate': 'output_format',\n 'wavespeed': 'output_format',\n },\n },\n {\n universal: 'quality',\n providers: {\n 'fal-ai': 'quality',\n 'replicate': 'output_quality',\n 'wavespeed': 'quality',\n },\n },\n {\n universal: 'safety',\n providers: {\n 'fal-ai': 'enable_safety_checker',\n 'replicate': 'disable_safety_checker',\n 'wavespeed': 'enable_safety_checker',\n },\n transform: 'flip_boolean',\n },\n ],\n output_type: 'image',\n output_extract: {\n 'fal-ai': 'images[].url',\n 'replicate': 'output[]',\n 'wavespeed': 'data.outputs[]',\n },\n default_timeout_ms: 60000,\n}\n","import type { CategoryTemplate } from '../types.js'\n\nexport const textToVideoTemplate: CategoryTemplate = {\n category: 'text-to-video',\n input_mappings: [\n {\n universal: 'prompt',\n providers: {\n 'fal-ai': 'prompt',\n 'replicate': 'prompt',\n 'wavespeed': 'prompt',\n },\n required: true,\n },\n {\n universal: 'negative_prompt',\n providers: {\n 'fal-ai': 'negative_prompt',\n 'replicate': 'negative_prompt',\n 'wavespeed': 'negative_prompt',\n },\n },\n {\n universal: 'count',\n providers: {\n 'fal-ai': 'num_videos',\n 'replicate': 'num_outputs',\n 'wavespeed': 'num_outputs',\n },\n },\n {\n universal: 'size',\n providers: {\n 'fal-ai': 'video_size',\n 'replicate': ['width', 'height'],\n 'wavespeed': 'resolution',\n },\n transform: 'parse_size',\n },\n {\n universal: 'guidance',\n providers: {\n 'fal-ai': 'guidance_scale',\n 'replicate': 'guidance',\n 'wavespeed': 'guidance_scale',\n },\n },\n {\n universal: 'steps',\n providers: {\n 'fal-ai': 'num_inference_steps',\n 'replicate': 'num_inference_steps',\n 'wavespeed': 'num_inference_steps',\n },\n },\n {\n universal: 'seed',\n providers: {\n 'fal-ai': 'seed',\n 'replicate': 'seed',\n 'wavespeed': 'seed',\n },\n },\n {\n universal: 'format',\n providers: {\n 'fal-ai': 'output_format',\n 'replicate': 'output_format',\n 'wavespeed': 'output_format',\n },\n },\n {\n universal: 'safety',\n providers: {\n 'fal-ai': 'enable_safety_checker',\n 'replicate': 'disable_safety_checker',\n 'wavespeed': 'enable_safety_checker',\n },\n transform: 'flip_boolean',\n },\n ],\n output_type: 'video',\n output_extract: {\n 'fal-ai': 'video.url',\n 'replicate': 'output',\n 'wavespeed': 'data.outputs[]',\n },\n default_timeout_ms: 300000,\n}\n","import type { CategoryTemplate } from '../types.js'\n\nexport const imageToVideoTemplate: CategoryTemplate = {\n category: 'image-to-video',\n input_mappings: [\n {\n universal: 'image',\n providers: {\n 'fal-ai': 'image_url',\n 'replicate': 'image',\n 'wavespeed': 'image_url',\n },\n required: true,\n },\n {\n universal: 'prompt',\n providers: {\n 'fal-ai': 'prompt',\n 'replicate': 'prompt',\n 'wavespeed': 'prompt',\n },\n },\n {\n universal: 'negative_prompt',\n providers: {\n 'fal-ai': 'negative_prompt',\n 'replicate': 'negative_prompt',\n 'wavespeed': 'negative_prompt',\n },\n },\n {\n universal: 'seed',\n providers: {\n 'fal-ai': 'seed',\n 'replicate': 'seed',\n 'wavespeed': 'seed',\n },\n },\n {\n universal: 'guidance',\n providers: {\n 'fal-ai': 'guidance_scale',\n 'replicate': 'guidance',\n 'wavespeed': 'guidance_scale',\n },\n },\n {\n universal: 'steps',\n providers: {\n 'fal-ai': 'num_inference_steps',\n 'replicate': 'num_inference_steps',\n 'wavespeed': 'num_inference_steps',\n },\n },\n {\n universal: 'format',\n providers: {\n 'fal-ai': 'output_format',\n 'replicate': 'output_format',\n 'wavespeed': 'output_format',\n },\n },\n {\n universal: 'safety',\n providers: {\n 'fal-ai': 'enable_safety_checker',\n 'replicate': 'disable_safety_checker',\n 'wavespeed': 'enable_safety_checker',\n },\n transform: 'flip_boolean',\n },\n ],\n output_type: 'video',\n output_extract: {\n 'fal-ai': 'video.url',\n 'replicate': 'output',\n 'wavespeed': 'data.outputs[]',\n },\n default_timeout_ms: 300000,\n}\n","import type { CategoryTemplate } from '../types.js'\n\nexport const upscaleImageTemplate: CategoryTemplate = {\n category: 'upscale-image',\n input_mappings: [\n {\n universal: 'image',\n providers: {\n 'fal-ai': 'image_url',\n 'replicate': 'image',\n 'wavespeed': 'image_url',\n },\n required: true,\n },\n {\n universal: 'strength',\n providers: {\n 'fal-ai': 'scale',\n 'replicate': 'scale',\n 'wavespeed': 'scale',\n },\n },\n {\n universal: 'format',\n providers: {\n 'fal-ai': 'output_format',\n 'replicate': 'output_format',\n 'wavespeed': 'output_format',\n },\n },\n {\n universal: 'quality',\n providers: {\n 'fal-ai': 'quality',\n 'replicate': 'output_quality',\n 'wavespeed': 'quality',\n },\n },\n ],\n output_type: 'image',\n output_extract: {\n 'fal-ai': 'images[].url',\n 'replicate': 'output[]',\n 'wavespeed': 'data.outputs[]',\n },\n default_timeout_ms: 120000,\n}\n","import type { CategoryTemplate } from '../types.js'\n\nexport const textToAudioTemplate: CategoryTemplate = {\n category: 'text-to-audio',\n input_mappings: [\n {\n universal: 'prompt',\n providers: {\n 'fal-ai': 'text',\n 'replicate': 'prompt',\n 'wavespeed': 'prompt',\n },\n required: true,\n },\n {\n universal: 'count',\n providers: {\n 'fal-ai': 'num_outputs',\n 'replicate': 'num_outputs',\n 'wavespeed': 'num_outputs',\n },\n },\n {\n universal: 'format',\n providers: {\n 'fal-ai': 'output_format',\n 'replicate': 'output_format',\n 'wavespeed': 'output_format',\n },\n },\n {\n universal: 'seed',\n providers: {\n 'fal-ai': 'seed',\n 'replicate': 'seed',\n 'wavespeed': 'seed',\n },\n },\n ],\n output_type: 'audio',\n output_extract: {\n 'fal-ai': 'audio.url',\n 'replicate': 'output',\n 'wavespeed': 'data.outputs[]',\n },\n default_timeout_ms: 60000,\n}\n","import type { CategoryTemplate } from '../types.js'\n\nexport const audioToTextTemplate: CategoryTemplate = {\n category: 'audio-to-text',\n input_mappings: [\n {\n universal: 'audio',\n providers: {\n 'fal-ai': 'audio_url',\n 'replicate': 'audio',\n 'wavespeed': 'audio_url',\n },\n required: true,\n },\n ],\n output_type: 'text',\n output_extract: {\n 'fal-ai': 'text',\n 'replicate': 'output.text',\n 'wavespeed': 'data.outputs[]',\n },\n default_timeout_ms: 120000,\n}\n","import type { CategoryTemplate } from '../types.js'\n\nexport const removeBackgroundTemplate: CategoryTemplate = {\n category: 'remove-background',\n input_mappings: [\n {\n universal: 'image',\n providers: {\n 'fal-ai': 'image_url',\n 'replicate': 'image',\n 'wavespeed': 'image_url',\n },\n required: true,\n },\n {\n universal: 'format',\n providers: {\n 'fal-ai': 'output_format',\n 'replicate': 'output_format',\n 'wavespeed': 'output_format',\n },\n },\n {\n universal: 'quality',\n providers: {\n 'fal-ai': 'quality',\n 'replicate': 'output_quality',\n 'wavespeed': 'quality',\n },\n },\n ],\n output_type: 'image',\n output_extract: {\n 'fal-ai': 'images[].url',\n 'replicate': 'output[]',\n 'wavespeed': 'data.outputs[]',\n },\n default_timeout_ms: 60000,\n}\n","import { textToImageTemplate } from './text-to-image.js'\nimport { imageEditTemplate } from './image-edit.js'\nimport { textToVideoTemplate } from './text-to-video.js'\nimport { imageToVideoTemplate } from './image-to-video.js'\nimport { upscaleImageTemplate } from './upscale-image.js'\nimport { textToAudioTemplate } from './text-to-audio.js'\nimport { audioToTextTemplate } from './audio-to-text.js'\nimport { removeBackgroundTemplate } from './remove-background.js'\nimport type { CategoryTemplate, ModelCategory } from '../types.js'\n\nconst templates: Partial<Record<ModelCategory, CategoryTemplate>> = {\n 'text-to-image': textToImageTemplate,\n 'image-edit': imageEditTemplate,\n 'text-to-video': textToVideoTemplate,\n 'image-to-video': imageToVideoTemplate,\n 'upscale-image': upscaleImageTemplate,\n 'text-to-audio': textToAudioTemplate,\n 'audio-to-text': audioToTextTemplate,\n 'remove-background': removeBackgroundTemplate,\n}\n\nexport function getCategoryTemplate(category: ModelCategory): CategoryTemplate | undefined {\n return templates[category]\n}\n\nexport {\n textToImageTemplate,\n imageEditTemplate,\n textToVideoTemplate,\n imageToVideoTemplate,\n upscaleImageTemplate,\n textToAudioTemplate,\n audioToTextTemplate,\n removeBackgroundTemplate,\n}\n","import type { ProviderAdapter, ProviderResponse, OutputItem, OutputMapping } from \"./base.js\";\nimport { AuthError, RateLimitError, ProviderError, TimeoutError } from \"../errors.js\";\n\nconst BASE_URL = \"https://queue.fal.run\";\n\nasync function handleHttpErrors(\n response: Response,\n endpoint: string,\n): Promise<void> {\n if (response.ok) return;\n\n const status = response.status;\n\n if (status === 401) {\n throw new AuthError(\"fal-ai\", \"FAL_KEY\");\n }\n\n if (status === 429) {\n const retryAfter = response.headers.get(\"retry-after\");\n const retryMs = retryAfter ? parseInt(retryAfter, 10) * 1000 : 60000;\n throw new RateLimitError(\"fal-ai\", retryMs);\n }\n\n let raw: unknown;\n try {\n raw = await response.json();\n } catch {\n raw = await response.text().catch(() => null);\n }\n\n throw new ProviderError(\"fal-ai\", endpoint, status, raw);\n}\n\nfunction authHeaders(auth: string): Record<string, string> {\n return {\n Authorization: `Key ${auth}`,\n \"Content-Type\": \"application/json\",\n };\n}\n\nexport const falAiAdapter: ProviderAdapter = {\n name: \"fal-ai\",\n\n async submit(\n endpoint: string,\n params: Record<string, unknown>,\n auth: string,\n ): Promise<ProviderResponse> {\n const url = `${BASE_URL}/${endpoint}`;\n const response = await fetch(url, {\n method: \"POST\",\n headers: authHeaders(auth),\n body: JSON.stringify(params),\n });\n\n await handleHttpErrors(response, endpoint);\n\n const data = (await response.json()) as { request_id: string };\n\n return {\n id: data.request_id,\n status: \"pending\",\n };\n },\n\n async poll(\n taskId: string,\n auth: string,\n endpoint?: string,\n ): Promise<ProviderResponse> {\n if (!endpoint) {\n throw new ProviderError(\"fal-ai\", \"unknown\", 400, \"endpoint is required for polling\");\n }\n\n // Check status\n const statusUrl = `${BASE_URL}/${endpoint}/requests/${taskId}/status`;\n const statusResponse = await fetch(statusUrl, {\n headers: { Authorization: `Key ${auth}` },\n });\n\n await handleHttpErrors(statusResponse, endpoint);\n\n const statusData = (await statusResponse.json()) as {\n status: \"IN_QUEUE\" | \"IN_PROGRESS\" | \"COMPLETED\" | \"FAILED\";\n error?: string;\n };\n\n if (statusData.status === \"FAILED\") {\n return {\n id: taskId,\n status: \"failed\",\n error: statusData.error ?? \"Unknown error\",\n };\n }\n\n if (statusData.status !== \"COMPLETED\") {\n return {\n id: taskId,\n status: \"processing\",\n };\n }\n\n // Fetch result\n const resultUrl = `${BASE_URL}/${endpoint}/requests/${taskId}`;\n const resultResponse = await fetch(resultUrl, {\n headers: { Authorization: `Key ${auth}` },\n });\n\n await handleHttpErrors(resultResponse, endpoint);\n\n const output = await resultResponse.json();\n\n return {\n id: taskId,\n status: \"completed\",\n output,\n };\n },\n\n parseOutput(raw: unknown, outputMapping: OutputMapping): OutputItem[] {\n const data = raw as Record<string, unknown>;\n const path = outputMapping.extract_path;\n\n if (path === \"images[].url\") {\n const images = data.images as Array<{\n url: string;\n content_type?: string;\n }>;\n if (!Array.isArray(images)) return [];\n return images.map((img) => ({\n type: outputMapping.type,\n url: img.url,\n content_type: img.content_type ?? outputMapping.content_type ?? \"image/jpeg\",\n }));\n }\n\n if (path === \"video.url\") {\n const video = data.video as { url: string; content_type?: string } | undefined;\n if (!video?.url) return [];\n return [\n {\n type: outputMapping.type,\n url: video.url,\n content_type: video.content_type ?? outputMapping.content_type ?? \"video/mp4\",\n },\n ];\n }\n\n if (path === \"audio.url\") {\n const audio = data.audio as { url: string; content_type?: string } | undefined;\n if (!audio?.url) return [];\n return [\n {\n type: outputMapping.type,\n url: audio.url,\n content_type: audio.content_type ?? outputMapping.content_type ?? \"audio/mpeg\",\n },\n ];\n }\n\n return [];\n },\n};\n\n/**\n * Submit a request and poll until completion or timeout.\n */\nexport async function submitAndPoll(\n endpoint: string,\n params: Record<string, unknown>,\n auth: string,\n options?: {\n timeoutMs?: number;\n intervalMs?: number;\n maxIntervalMs?: number;\n },\n): Promise<ProviderResponse> {\n const timeoutMs = options?.timeoutMs ?? 300_000;\n const startInterval = options?.intervalMs ?? 1000;\n const maxInterval = options?.maxIntervalMs ?? 5000;\n\n const submitted = await falAiAdapter.submit(endpoint, params, auth);\n const taskId = submitted.id;\n\n const start = Date.now();\n let interval = startInterval;\n\n while (Date.now() - start < timeoutMs) {\n await sleep(interval);\n\n const result = await falAiAdapter.poll(taskId, auth, endpoint);\n\n if (result.status === \"completed\" || result.status === \"failed\") {\n return result;\n }\n\n interval = Math.min(interval + 500, maxInterval);\n }\n\n throw new TimeoutError(\"fal-ai\", endpoint, timeoutMs);\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n","import type { ProviderAdapter, ProviderResponse, OutputItem, OutputMapping } from \"./base.js\";\nimport { AuthError, RateLimitError, ProviderError } from \"../errors.js\";\n\nconst BASE_URL = \"https://api.replicate.com/v1\";\n\nasync function handleHttpErrors(\n response: Response,\n endpoint: string,\n): Promise<void> {\n if (response.ok) return;\n\n const status = response.status;\n\n if (status === 401) {\n throw new AuthError(\"replicate\", \"REPLICATE_API_TOKEN\");\n }\n\n if (status === 429) {\n const retryAfter = response.headers.get(\"retry-after\");\n const retryMs = retryAfter ? parseInt(retryAfter, 10) * 1000 : 60000;\n throw new RateLimitError(\"replicate\", retryMs);\n }\n\n let raw: unknown;\n try {\n raw = await response.json();\n } catch {\n raw = await response.text().catch(() => null);\n }\n\n throw new ProviderError(\"replicate\", endpoint, status, raw);\n}\n\nfunction authHeaders(auth: string): Record<string, string> {\n return {\n Authorization: `Bearer ${auth}`,\n \"Content-Type\": \"application/json\",\n };\n}\n\nfunction inferContentType(url: string): string {\n const lower = url.toLowerCase();\n if (lower.includes(\".png\")) return \"image/png\";\n if (lower.includes(\".jpg\") || lower.includes(\".jpeg\")) return \"image/jpeg\";\n if (lower.includes(\".webp\")) return \"image/webp\";\n if (lower.includes(\".mp4\")) return \"video/mp4\";\n if (lower.includes(\".mp3\")) return \"audio/mpeg\";\n if (lower.includes(\".wav\")) return \"audio/wav\";\n return \"image/jpeg\";\n}\n\nexport const replicateAdapter: ProviderAdapter = {\n name: \"replicate\",\n\n async submit(\n endpoint: string,\n params: Record<string, unknown>,\n auth: string,\n ): Promise<ProviderResponse> {\n const url = `${BASE_URL}/models/${endpoint}/predictions`;\n const response = await fetch(url, {\n method: \"POST\",\n headers: authHeaders(auth),\n body: JSON.stringify({ input: params }),\n });\n\n await handleHttpErrors(response, endpoint);\n\n const data = (await response.json()) as { id: string };\n\n return {\n id: data.id,\n status: \"pending\",\n };\n },\n\n async poll(\n taskId: string,\n auth: string,\n ): Promise<ProviderResponse> {\n const url = `${BASE_URL}/predictions/${taskId}`;\n const response = await fetch(url, {\n headers: { Authorization: `Bearer ${auth}` },\n });\n\n await handleHttpErrors(response, taskId);\n\n const data = (await response.json()) as {\n id: string;\n status: \"starting\" | \"processing\" | \"succeeded\" | \"failed\" | \"canceled\";\n output?: unknown;\n error?: string;\n };\n\n if (data.status === \"succeeded\") {\n return {\n id: data.id,\n status: \"completed\",\n output: data.output,\n };\n }\n\n if (data.status === \"failed\" || data.status === \"canceled\") {\n return {\n id: data.id,\n status: \"failed\",\n error: data.error ?? `Prediction ${data.status}`,\n };\n }\n\n // starting or processing\n return {\n id: data.id,\n status: \"processing\",\n };\n },\n\n parseOutput(raw: unknown, outputMapping: OutputMapping): OutputItem[] {\n // Replicate output is typically string[] (URLs)\n if (!Array.isArray(raw)) return [];\n\n return (raw as string[]).map((url) => ({\n type: outputMapping.type,\n url,\n content_type: outputMapping.content_type ?? inferContentType(url),\n }));\n },\n};\n","import type { ProviderAdapter, ProviderResponse, OutputItem, OutputMapping } from \"./base.js\";\nimport { AuthError, RateLimitError, ProviderError } from \"../errors.js\";\n\nconst BASE_URL = \"https://api.wavespeed.ai/api/v3\";\n\nasync function handleHttpErrors(\n response: Response,\n endpoint: string,\n): Promise<void> {\n if (response.ok) return;\n\n const status = response.status;\n\n if (status === 401) {\n throw new AuthError(\"wavespeed\", \"WAVESPEED_API_KEY\");\n }\n\n if (status === 429) {\n const retryAfter = response.headers.get(\"retry-after\");\n const retryMs = retryAfter ? parseInt(retryAfter, 10) * 1000 : 60000;\n throw new RateLimitError(\"wavespeed\", retryMs);\n }\n\n let raw: unknown;\n try {\n raw = await response.json();\n } catch {\n raw = await response.text().catch(() => null);\n }\n\n throw new ProviderError(\"wavespeed\", endpoint, status, raw);\n}\n\nfunction authHeaders(auth: string): Record<string, string> {\n return {\n Authorization: `Bearer ${auth}`,\n \"Content-Type\": \"application/json\",\n };\n}\n\nfunction inferContentType(url: string): string {\n const ext = url.split(\".\").pop()?.toLowerCase()?.split(\"?\")[0];\n switch (ext) {\n case \"png\":\n return \"image/png\";\n case \"jpg\":\n case \"jpeg\":\n return \"image/jpeg\";\n case \"webp\":\n return \"image/webp\";\n case \"gif\":\n return \"image/gif\";\n case \"mp4\":\n return \"video/mp4\";\n case \"mp3\":\n return \"audio/mpeg\";\n case \"wav\":\n return \"audio/wav\";\n default:\n return \"application/octet-stream\";\n }\n}\n\nexport const wavespeedAdapter: ProviderAdapter = {\n name: \"wavespeed\",\n\n async submit(\n endpoint: string,\n params: Record<string, unknown>,\n auth: string,\n ): Promise<ProviderResponse> {\n const url = `${BASE_URL}/${endpoint}`;\n const response = await fetch(url, {\n method: \"POST\",\n headers: authHeaders(auth),\n body: JSON.stringify(params),\n });\n\n await handleHttpErrors(response, endpoint);\n\n const json = (await response.json()) as {\n data: { id: string; status: string };\n };\n\n return {\n id: json.data.id,\n status: \"pending\",\n };\n },\n\n async poll(\n taskId: string,\n auth: string,\n ): Promise<ProviderResponse> {\n const url = `${BASE_URL}/predictions/${taskId}/result`;\n const response = await fetch(url, {\n headers: { Authorization: `Bearer ${auth}` },\n });\n\n await handleHttpErrors(response, `predictions/${taskId}/result`);\n\n const json = (await response.json()) as {\n data: {\n id: string;\n status: string;\n outputs?: string[];\n error?: string;\n };\n };\n\n const { data } = json;\n\n if (data.status === \"failed\") {\n return {\n id: taskId,\n status: \"failed\",\n error: data.error ?? \"Unknown error\",\n };\n }\n\n if (data.status === \"completed\") {\n return {\n id: taskId,\n status: \"completed\",\n output: data,\n };\n }\n\n // created or processing\n return {\n id: taskId,\n status: \"processing\",\n };\n },\n\n parseOutput(raw: unknown, outputMapping: OutputMapping): OutputItem[] {\n const data = raw as Record<string, unknown>;\n const outputs = data.outputs as string[] | undefined;\n\n if (!Array.isArray(outputs)) return [];\n\n return outputs.map((url) => ({\n type: outputMapping.type,\n url,\n content_type: outputMapping.content_type ?? inferContentType(url),\n }));\n },\n};\n","import {\n AuthError,\n ValidationError,\n ModelNotFoundError,\n ProviderError,\n RateLimitError,\n TimeoutError,\n} from './errors.js'\n\nexport interface RetryOptions {\n maxRetries: number\n initialDelayMs: number\n maxDelayMs: number\n timeoutMs: number\n}\n\nconst DEFAULT_OPTIONS: RetryOptions = {\n maxRetries: 3,\n initialDelayMs: 1000,\n maxDelayMs: 10000,\n timeoutMs: 300_000,\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms))\n}\n\nfunction isRetryable(error: unknown): boolean {\n // Never retry auth, validation, or model-not-found errors\n if (\n error instanceof AuthError ||\n error instanceof ValidationError ||\n error instanceof ModelNotFoundError\n ) {\n return false\n }\n\n // Retry rate limit errors (429)\n if (error instanceof RateLimitError) {\n return true\n }\n\n // ProviderError: only retry 5xx, not 4xx\n if (error instanceof ProviderError) {\n return error.statusCode >= 500\n }\n\n // Network errors (TypeError from fetch, etc.) are retryable\n if (error instanceof TypeError) {\n return true\n }\n\n return false\n}\n\nfunction getDelayMs(\n error: unknown,\n attempt: number,\n options: RetryOptions,\n): number {\n // RateLimitError has its own retry-after\n if (error instanceof RateLimitError) {\n return error.retryAfterMs\n }\n\n // Exponential backoff with jitter\n const jitter = Math.random() * options.initialDelayMs * 0.5\n const delay = options.initialDelayMs * Math.pow(2, attempt) + jitter\n return Math.min(delay, options.maxDelayMs)\n}\n\nexport async function withRetry<T>(\n fn: () => Promise<T>,\n options?: Partial<RetryOptions>,\n): Promise<T> {\n const opts: RetryOptions = { ...DEFAULT_OPTIONS, ...options }\n const startTime = Date.now()\n let lastError: unknown\n\n for (let attempt = 0; attempt <= opts.maxRetries; attempt++) {\n // Check total timeout before attempting\n if (attempt > 0) {\n const elapsed = Date.now() - startTime\n if (elapsed >= opts.timeoutMs) {\n throw new TimeoutError('unknown', 'unknown', opts.timeoutMs)\n }\n }\n\n try {\n return await fn()\n } catch (error) {\n lastError = error\n\n // If not retryable, throw immediately\n if (!isRetryable(error)) {\n throw error\n }\n\n // If we've exhausted retries, throw\n if (attempt >= opts.maxRetries) {\n throw error\n }\n\n const delay = getDelayMs(error, attempt, opts)\n\n // Check if waiting would exceed timeout\n const elapsed = Date.now() - startTime\n if (elapsed + delay >= opts.timeoutMs) {\n throw new TimeoutError('unknown', 'unknown', opts.timeoutMs)\n }\n\n await sleep(delay)\n }\n }\n\n /* v8 ignore next 3 */\n // Unreachable: the for loop always returns or throws\n throw lastError as Error\n}\n","import type { ModelEntry, ModelCategory, ProviderName } from \"./types.js\";\nimport { loadRegistry } from \"./resolver.js\";\nimport { resolveModel } from \"./resolver.js\";\nimport { AuthManager } from \"./auth.js\";\n\nexport interface ListModelsFilters {\n category?: ModelCategory;\n provider?: ProviderName;\n query?: string; // search canonical name and aliases\n accessible?: boolean; // if true, only return models the caller has API keys for\n}\n\n/**\n * Lists all models in the registry.\n * Set `accessible: true` to filter to only models the caller has API keys for.\n * Optionally filters by category, provider, or text query.\n */\nexport function listModels(filters?: ListModelsFilters): ModelEntry[] {\n let models = loadRegistry();\n\n if (filters?.accessible) {\n const auth = new AuthManager();\n models = auth.listAvailableModels(models);\n }\n\n if (filters?.category) {\n models = models.filter((m) => m.category === filters.category);\n }\n if (filters?.provider) {\n models = models.filter((m) =>\n m.providers.some((p) => p.provider === filters.provider),\n );\n }\n if (filters?.query) {\n const q = filters.query.toLowerCase();\n models = models.filter(\n (m) =>\n m.canonical_name.includes(q) ||\n m.aliases.some((a) => a.includes(q)),\n );\n }\n\n return models;\n}\n\n/**\n * Resolves a model by name (canonical name, alias, or fuzzy match).\n * Throws ModelNotFoundError if no match is found.\n */\nexport function getModel(name: string): ModelEntry {\n return resolveModel(name);\n}\n"],"mappings":"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","names":["BASE_URL","handleHttpErrors","authHeaders","BASE_URL","handleHttpErrors","authHeaders","inferContentType","resolve","resolve"]}
|
package/dist/cli.js
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -72,9 +72,11 @@ interface ListModelsFilters {
|
|
|
72
72
|
category?: ModelCategory;
|
|
73
73
|
provider?: ProviderName;
|
|
74
74
|
query?: string;
|
|
75
|
+
accessible?: boolean;
|
|
75
76
|
}
|
|
76
77
|
/**
|
|
77
|
-
* Lists all models the
|
|
78
|
+
* Lists all models in the registry.
|
|
79
|
+
* Set `accessible: true` to filter to only models the caller has API keys for.
|
|
78
80
|
* Optionally filters by category, provider, or text query.
|
|
79
81
|
*/
|
|
80
82
|
declare function listModels(filters?: ListModelsFilters): ModelEntry[];
|
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "getaiapi",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Unified AI API Gateway - one function to call any AI model",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -51,6 +51,7 @@
|
|
|
51
51
|
"generate-registry": "tsx scripts/generate-registry.ts"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
|
+
"@vitest/coverage-v8": "^3.2.4",
|
|
54
55
|
"tsup": "^8.4.0",
|
|
55
56
|
"tsx": "^4.19.0",
|
|
56
57
|
"typescript": "^5.7.0",
|