{"version":3,"file":"fal-audio.cjs","names":["FORMAT_TO_CONTENT_TYPE","getTestId","matchFixture","proxyAndRecord","isErrorResponse","isAudioResponse","crypto"],"sources":["../src/fal-audio.ts"],"sourcesContent":["import type http from \"node:http\";\nimport crypto from \"node:crypto\";\nimport type { AudioResponse, ChatCompletionRequest, Fixture, HandlerDefaults } from \"./types.js\";\nimport { isAudioResponse, isErrorResponse, FORMAT_TO_CONTENT_TYPE, getTestId } from \"./helpers.js\";\nimport { matchFixture } from \"./router.js\";\nimport { proxyAndRecord } from \"./recorder.js\";\nimport type { Journal } from \"./journal.js\";\n\n// ─── FalJobMap with TTL and size bound ───────────────────────────────────\n\nconst FAL_JOB_MAX_ENTRIES = 10_000;\nconst FAL_JOB_TTL_MS = 3_600_000; // 1 hour\n\ninterface FalJob {\n  requestId: string;\n  modelId: string;\n  status: \"IN_QUEUE\" | \"IN_PROGRESS\" | \"COMPLETED\";\n  result: Record<string, unknown> | null;\n  createdAt: number;\n}\n\ninterface FalJobEntry {\n  job: FalJob;\n  createdAt: number;\n}\n\n/**\n * A Map wrapper for fal.ai queue jobs that enforces a maximum size and per-entry TTL.\n * Entries older than FAL_JOB_TTL_MS are lazily evicted on `get`.\n * When the map exceeds FAL_JOB_MAX_ENTRIES on `set`, the oldest entries\n * are removed to stay within bounds.\n */\nexport class FalJobMap {\n  private readonly entries = new Map<string, FalJobEntry>();\n\n  get(key: string): FalJob | undefined {\n    const entry = this.entries.get(key);\n    if (!entry) return undefined;\n    if (Date.now() - entry.createdAt > FAL_JOB_TTL_MS) {\n      this.entries.delete(key);\n      return undefined;\n    }\n    return entry.job;\n  }\n\n  set(key: string, job: FalJob): void {\n    this.entries.set(key, { job, createdAt: Date.now() });\n    // Evict oldest entries if over capacity\n    if (this.entries.size > FAL_JOB_MAX_ENTRIES) {\n      const excess = this.entries.size - FAL_JOB_MAX_ENTRIES;\n      const iter = this.entries.keys();\n      for (let i = 0; i < excess; i++) {\n        const next = iter.next();\n        if (!next.done) this.entries.delete(next.value);\n      }\n    }\n  }\n\n  delete(key: string): boolean {\n    return this.entries.delete(key);\n  }\n\n  clear(): void {\n    this.entries.clear();\n  }\n\n  get size(): number {\n    return this.entries.size;\n  }\n}\n\n// Module-level singleton — exported so server.ts can clear it during reset\nexport const falJobs = new FalJobMap();\n\n// ─── Audio response translation ──────────────────────────────────────────\n\nfunction audioToFalFile(response: AudioResponse): Record<string, unknown> {\n  let contentType: string;\n  let data: string;\n\n  if (typeof response.audio === \"string\") {\n    data = response.audio;\n    contentType = FORMAT_TO_CONTENT_TYPE[response.format ?? \"mp3\"] ?? \"audio/mpeg\";\n  } else {\n    data = response.audio.b64Json;\n    contentType = response.audio.contentType ?? \"audio/mpeg\";\n  }\n\n  const ext =\n    response.format ??\n    (contentType !== \"audio/mpeg\"\n      ? (Object.entries(FORMAT_TO_CONTENT_TYPE).find(([, v]) => v === contentType)?.[0] ?? \"mp3\")\n      : \"mp3\");\n\n  const fileSize =\n    Math.ceil((data.length * 3) / 4) - (data.endsWith(\"==\") ? 2 : data.endsWith(\"=\") ? 1 : 0);\n\n  return {\n    audio: {\n      url: `https://mock.fal.media/files/generated_audio.${ext}`,\n      content_type: contentType,\n      file_name: `generated_audio.${ext}`,\n      file_size: fileSize,\n    },\n  };\n}\n\n// ─── Route patterns ──────────────────────────────────────────────────────\n\nconst QUEUE_SUBMIT_RE = /^\\/fal\\/queue\\/submit\\/(.+)$/;\nconst QUEUE_STATUS_RE = /^\\/fal\\/queue\\/requests\\/([^/]+)\\/status$/;\nconst QUEUE_RESULT_RE = /^\\/fal\\/queue\\/requests\\/([^/]+)$/;\nconst QUEUE_CANCEL_RE = /^\\/fal\\/queue\\/requests\\/([^/]+)\\/cancel$/;\nconst SYNC_RUN_RE = /^\\/fal\\/run\\/(.+)$/;\n\n// ─── Handler ─────────────────────────────────────────────────────────────\n\nexport async function handleFalQueue(\n  req: http.IncomingMessage,\n  res: http.ServerResponse,\n  body: string,\n  pathname: string,\n  fixtures: Fixture[],\n  defaults: HandlerDefaults,\n  journal: Journal,\n): Promise<void> {\n  const testId = getTestId(req);\n  const matchCounts = journal.getFixtureMatchCountsForTest(testId);\n\n  // ── Queue Submit ───────────────────────────────────────────────────\n  const submitMatch = QUEUE_SUBMIT_RE.exec(pathname);\n  if (submitMatch && req.method === \"POST\") {\n    const modelId = submitMatch[1];\n    return handleQueueSubmit(\n      req,\n      res,\n      body,\n      pathname,\n      modelId,\n      testId,\n      fixtures,\n      defaults,\n      matchCounts,\n      journal,\n    );\n  }\n\n  // ── Queue Status ───────────────────────────────────────────────────\n  const statusMatch = QUEUE_STATUS_RE.exec(pathname);\n  if (statusMatch) {\n    const requestId = statusMatch[1];\n    return handleQueueStatus(req, res, pathname, requestId, testId, journal);\n  }\n\n  // ── Queue Cancel ───────────────────────────────────────────────────\n  const cancelMatch = QUEUE_CANCEL_RE.exec(pathname);\n  if (cancelMatch) {\n    const requestId = cancelMatch[1];\n    return handleQueueCancel(req, res, pathname, requestId, testId, journal);\n  }\n\n  // ── Queue Result ───────────────────────────────────────────────────\n  const resultMatch = QUEUE_RESULT_RE.exec(pathname);\n  if (resultMatch) {\n    const requestId = resultMatch[1];\n    return handleQueueResult(req, res, pathname, requestId, testId, journal);\n  }\n\n  // ── Synchronous Run ────────────────────────────────────────────────\n  const runMatch = SYNC_RUN_RE.exec(pathname);\n  if (runMatch && req.method === \"POST\") {\n    const modelId = runMatch[1];\n    return handleSyncRun(\n      req,\n      res,\n      body,\n      pathname,\n      modelId,\n      fixtures,\n      defaults,\n      matchCounts,\n      journal,\n    );\n  }\n\n  // Unknown fal path\n  const errorBody = { error: { message: \"Unknown fal.ai endpoint\", type: \"not_found\" } };\n  journal.add({\n    method: req.method ?? \"GET\",\n    path: pathname,\n    headers: {},\n    body: null,\n    response: { status: 404, fixture: null },\n  });\n  res.writeHead(404, { \"Content-Type\": \"application/json\" });\n  res.end(JSON.stringify(errorBody));\n}\n\n// ─── Sub-handlers ────────────────────────────────────────────────────────\n\nasync function handleQueueSubmit(\n  req: http.IncomingMessage,\n  res: http.ServerResponse,\n  body: string,\n  pathname: string,\n  modelId: string,\n  testId: string,\n  fixtures: Fixture[],\n  defaults: HandlerDefaults,\n  matchCounts: Map<Fixture, number>,\n  journal: Journal,\n): Promise<void> {\n  let parsed: Record<string, unknown> = {};\n  if (body.trim()) {\n    try {\n      parsed = JSON.parse(body) as Record<string, unknown>;\n    } catch {\n      journal.add({\n        method: req.method ?? \"POST\",\n        path: pathname,\n        headers: {},\n        body: null,\n        response: { status: 400, fixture: null },\n      });\n      res.writeHead(400, { \"Content-Type\": \"application/json\" });\n      res.end(\n        JSON.stringify({\n          error: { message: \"Malformed JSON\", type: \"invalid_request_error\" },\n        }),\n      );\n      return;\n    }\n  }\n\n  const prompt =\n    (typeof parsed.prompt === \"string\" ? parsed.prompt : null) ??\n    (typeof parsed.text === \"string\" ? parsed.text : null) ??\n    \"\";\n\n  const syntheticReq: ChatCompletionRequest = {\n    model: modelId,\n    messages: [{ role: \"user\", content: prompt }],\n    _endpointType: \"fal-audio\",\n  };\n\n  const fixture = matchFixture(fixtures, syntheticReq, matchCounts, defaults.requestTransform);\n\n  if (!fixture) {\n    if (defaults.record) {\n      const proxied = await proxyAndRecord(\n        req,\n        res,\n        syntheticReq,\n        \"fal\",\n        pathname,\n        fixtures,\n        defaults,\n        body,\n      );\n      if (proxied) {\n        journal.add({\n          method: req.method ?? \"POST\",\n          path: pathname,\n          headers: {},\n          body: syntheticReq,\n          response: { status: res.statusCode ?? 200, fixture: null },\n        });\n        return;\n      }\n    }\n\n    const strictStatus = defaults.strict ? 503 : 404;\n    const strictMessage = defaults.strict\n      ? \"Strict mode: no fixture matched\"\n      : \"No fixture matched\";\n    journal.add({\n      method: req.method ?? \"POST\",\n      path: pathname,\n      headers: {},\n      body: syntheticReq,\n      response: { status: strictStatus, fixture: null },\n    });\n    res.writeHead(strictStatus, { \"Content-Type\": \"application/json\" });\n    res.end(\n      JSON.stringify({\n        error: {\n          message: strictMessage,\n          type: \"invalid_request_error\",\n          code: \"no_fixture_match\",\n        },\n      }),\n    );\n    return;\n  }\n\n  journal.incrementFixtureMatchCount(fixture, fixtures, testId);\n  const response = fixture.response;\n\n  if (isErrorResponse(response)) {\n    const status = response.status ?? 500;\n    journal.add({\n      method: req.method ?? \"POST\",\n      path: pathname,\n      headers: {},\n      body: syntheticReq,\n      response: { status, fixture },\n    });\n    res.writeHead(status, { \"Content-Type\": \"application/json\" });\n    res.end(JSON.stringify(response));\n    return;\n  }\n\n  if (!isAudioResponse(response)) {\n    journal.add({\n      method: req.method ?? \"POST\",\n      path: pathname,\n      headers: {},\n      body: syntheticReq,\n      response: { status: 500, fixture },\n    });\n    res.writeHead(500, { \"Content-Type\": \"application/json\" });\n    res.end(\n      JSON.stringify({\n        error: { message: \"Fixture response is not an audio type\", type: \"server_error\" },\n      }),\n    );\n    return;\n  }\n\n  const requestId = crypto.randomUUID();\n  const result = audioToFalFile(response);\n\n  const job: FalJob = {\n    requestId,\n    modelId,\n    status: \"COMPLETED\",\n    result,\n    createdAt: Date.now(),\n  };\n\n  const stateKey = `${testId}:${requestId}`;\n  falJobs.set(stateKey, job);\n\n  journal.add({\n    method: req.method ?? \"POST\",\n    path: pathname,\n    headers: {},\n    body: syntheticReq,\n    response: { status: 200, fixture },\n  });\n  res.writeHead(200, { \"Content-Type\": \"application/json\" });\n  res.end(\n    JSON.stringify({\n      request_id: requestId,\n      response_url: `https://queue.fal.run/${modelId}/requests/${requestId}/response`,\n      status_url: `https://queue.fal.run/${modelId}/requests/${requestId}/status`,\n      cancel_url: `https://queue.fal.run/${modelId}/requests/${requestId}/cancel`,\n      queue_position: 0,\n    }),\n  );\n}\n\nfunction handleQueueStatus(\n  req: http.IncomingMessage,\n  res: http.ServerResponse,\n  pathname: string,\n  requestId: string,\n  testId: string,\n  journal: Journal,\n): void {\n  const stateKey = `${testId}:${requestId}`;\n  const job = falJobs.get(stateKey);\n\n  if (!job) {\n    journal.add({\n      method: req.method ?? \"GET\",\n      path: pathname,\n      headers: {},\n      body: null,\n      response: { status: 404, fixture: null },\n    });\n    res.writeHead(404, { \"Content-Type\": \"application/json\" });\n    res.end(\n      JSON.stringify({\n        error: { message: `Request ${requestId} not found`, type: \"not_found\" },\n      }),\n    );\n    return;\n  }\n\n  journal.add({\n    method: req.method ?? \"GET\",\n    path: pathname,\n    headers: {},\n    body: null,\n    response: { status: 200, fixture: null },\n  });\n  res.writeHead(200, { \"Content-Type\": \"application/json\" });\n  res.end(\n    JSON.stringify({\n      status: job.status,\n      request_id: job.requestId,\n      response_url: `https://queue.fal.run/${job.modelId}/requests/${requestId}/response`,\n    }),\n  );\n}\n\nfunction handleQueueResult(\n  req: http.IncomingMessage,\n  res: http.ServerResponse,\n  pathname: string,\n  requestId: string,\n  testId: string,\n  journal: Journal,\n): void {\n  const stateKey = `${testId}:${requestId}`;\n  const job = falJobs.get(stateKey);\n\n  if (!job) {\n    journal.add({\n      method: req.method ?? \"GET\",\n      path: pathname,\n      headers: {},\n      body: null,\n      response: { status: 404, fixture: null },\n    });\n    res.writeHead(404, { \"Content-Type\": \"application/json\" });\n    res.end(\n      JSON.stringify({\n        error: { message: `Request ${requestId} not found`, type: \"not_found\" },\n      }),\n    );\n    return;\n  }\n\n  journal.add({\n    method: req.method ?? \"GET\",\n    path: pathname,\n    headers: {},\n    body: null,\n    response: { status: 200, fixture: null },\n  });\n  res.writeHead(200, { \"Content-Type\": \"application/json\" });\n  res.end(JSON.stringify(job.result));\n}\n\nfunction handleQueueCancel(\n  req: http.IncomingMessage,\n  res: http.ServerResponse,\n  pathname: string,\n  requestId: string,\n  testId: string,\n  journal: Journal,\n): void {\n  const stateKey = `${testId}:${requestId}`;\n  const job = falJobs.get(stateKey);\n\n  if (!job) {\n    journal.add({\n      method: req.method ?? \"DELETE\",\n      path: pathname,\n      headers: {},\n      body: null,\n      response: { status: 404, fixture: null },\n    });\n    res.writeHead(404, { \"Content-Type\": \"application/json\" });\n    res.end(JSON.stringify({ status: \"NOT_FOUND\" }));\n    return;\n  }\n\n  // Since we complete immediately, cancellation always returns ALREADY_COMPLETED\n  journal.add({\n    method: req.method ?? \"DELETE\",\n    path: pathname,\n    headers: {},\n    body: null,\n    response: { status: 400, fixture: null },\n  });\n  res.writeHead(400, { \"Content-Type\": \"application/json\" });\n  res.end(JSON.stringify({ status: \"ALREADY_COMPLETED\" }));\n}\n\nasync function handleSyncRun(\n  req: http.IncomingMessage,\n  res: http.ServerResponse,\n  body: string,\n  pathname: string,\n  modelId: string,\n  fixtures: Fixture[],\n  defaults: HandlerDefaults,\n  matchCounts: Map<Fixture, number>,\n  journal: Journal,\n): Promise<void> {\n  let parsed: Record<string, unknown> = {};\n  if (body.trim()) {\n    try {\n      parsed = JSON.parse(body) as Record<string, unknown>;\n    } catch {\n      journal.add({\n        method: req.method ?? \"POST\",\n        path: pathname,\n        headers: {},\n        body: null,\n        response: { status: 400, fixture: null },\n      });\n      res.writeHead(400, { \"Content-Type\": \"application/json\" });\n      res.end(\n        JSON.stringify({\n          error: { message: \"Malformed JSON\", type: \"invalid_request_error\" },\n        }),\n      );\n      return;\n    }\n  }\n\n  const prompt =\n    (typeof parsed.prompt === \"string\" ? parsed.prompt : null) ??\n    (typeof parsed.text === \"string\" ? parsed.text : null) ??\n    \"\";\n\n  const syntheticReq: ChatCompletionRequest = {\n    model: modelId,\n    messages: [{ role: \"user\", content: prompt }],\n    _endpointType: \"fal-audio\",\n  };\n\n  const fixture = matchFixture(fixtures, syntheticReq, matchCounts, defaults.requestTransform);\n\n  if (!fixture) {\n    if (defaults.record) {\n      const proxied = await proxyAndRecord(\n        req,\n        res,\n        syntheticReq,\n        \"fal\",\n        pathname,\n        fixtures,\n        defaults,\n        body,\n      );\n      if (proxied) {\n        journal.add({\n          method: req.method ?? \"POST\",\n          path: pathname,\n          headers: {},\n          body: syntheticReq,\n          response: { status: res.statusCode ?? 200, fixture: null },\n        });\n        return;\n      }\n    }\n\n    const strictStatus = defaults.strict ? 503 : 404;\n    const strictMessage = defaults.strict\n      ? \"Strict mode: no fixture matched\"\n      : \"No fixture matched\";\n    journal.add({\n      method: req.method ?? \"POST\",\n      path: pathname,\n      headers: {},\n      body: syntheticReq,\n      response: { status: strictStatus, fixture: null },\n    });\n    res.writeHead(strictStatus, { \"Content-Type\": \"application/json\" });\n    res.end(\n      JSON.stringify({\n        error: {\n          message: strictMessage,\n          type: \"invalid_request_error\",\n          code: \"no_fixture_match\",\n        },\n      }),\n    );\n    return;\n  }\n\n  journal.incrementFixtureMatchCount(fixture, fixtures, getTestId(req));\n  const response = fixture.response;\n\n  if (isErrorResponse(response)) {\n    const status = response.status ?? 500;\n    journal.add({\n      method: req.method ?? \"POST\",\n      path: pathname,\n      headers: {},\n      body: syntheticReq,\n      response: { status, fixture },\n    });\n    res.writeHead(status, { \"Content-Type\": \"application/json\" });\n    res.end(JSON.stringify(response));\n    return;\n  }\n\n  if (!isAudioResponse(response)) {\n    journal.add({\n      method: req.method ?? \"POST\",\n      path: pathname,\n      headers: {},\n      body: syntheticReq,\n      response: { status: 500, fixture },\n    });\n    res.writeHead(500, { \"Content-Type\": \"application/json\" });\n    res.end(\n      JSON.stringify({\n        error: { message: \"Fixture response is not an audio type\", type: \"server_error\" },\n      }),\n    );\n    return;\n  }\n\n  const result = audioToFalFile(response);\n\n  journal.add({\n    method: req.method ?? \"POST\",\n    path: pathname,\n    headers: {},\n    body: syntheticReq,\n    response: { status: 200, fixture },\n  });\n  res.writeHead(200, { \"Content-Type\": \"application/json\" });\n  res.end(JSON.stringify(result));\n}\n"],"mappings":"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"}