{"version":3,"file":"transcription-client.mjs","names":["TranscriptionErrorCode"],"sources":["../../src/lib/transcription-client.ts"],"sourcesContent":["import type { CopilotKitCoreReact } from \"./react-core\";\nimport {\n  TranscriptionErrorCode,\n  type TranscriptionErrorResponse,\n} from \"@copilotkitnext/shared\";\n\nexport interface TranscriptionResult {\n  text: string;\n  size: number;\n  type: string;\n}\n\n/**\n * Error info parsed from transcription endpoint error responses.\n */\nexport interface TranscriptionErrorInfo {\n  code: TranscriptionErrorCode;\n  message: string;\n  retryable: boolean;\n}\n\n// Re-export error code enum for convenience\nexport { TranscriptionErrorCode };\n\n/**\n * Convert a Blob to a base64 string\n */\nasync function blobToBase64(blob: Blob): Promise<string> {\n  return new Promise((resolve, reject) => {\n    const reader = new FileReader();\n    reader.onloadend = () => {\n      const result = reader.result as string;\n      // Remove the data URL prefix to get pure base64\n      const base64 = result.split(\",\")[1];\n      resolve(base64 ?? \"\");\n    };\n    reader.onerror = () => reject(new Error(\"Failed to read audio data\"));\n    reader.readAsDataURL(blob);\n  });\n}\n\n/**\n * Check if an error response matches our expected format\n */\nfunction isTranscriptionErrorResponse(\n  data: unknown,\n): data is TranscriptionErrorResponse {\n  return (\n    typeof data === \"object\" &&\n    data !== null &&\n    \"error\" in data &&\n    \"message\" in data &&\n    typeof (data as TranscriptionErrorResponse).error === \"string\" &&\n    typeof (data as TranscriptionErrorResponse).message === \"string\"\n  );\n}\n\n/**\n * Parse error info from a transcription error response\n */\nfunction parseTranscriptionError(\n  response: TranscriptionErrorResponse,\n): TranscriptionErrorInfo {\n  return {\n    code: response.error,\n    message: response.message,\n    retryable: response.retryable ?? false,\n  };\n}\n\n/**\n * Custom error type for transcription failures.\n * Extends Error with transcription-specific info for contextual error handling.\n */\nexport class TranscriptionError extends Error {\n  public readonly info: TranscriptionErrorInfo;\n\n  constructor(info: TranscriptionErrorInfo) {\n    super(info.message);\n    this.name = \"TranscriptionError\";\n    this.info = info;\n  }\n}\n\n/**\n * Transcribe an audio blob using the CopilotKit runtime\n *\n * Supports both REST mode (multipart/form-data) and single-endpoint mode (base64 JSON)\n *\n * @throws {TranscriptionError} When transcription fails with typed error information\n */\nexport async function transcribeAudio(\n  core: CopilotKitCoreReact,\n  audioBlob: Blob,\n  filename: string = \"recording.webm\",\n): Promise<TranscriptionResult> {\n  const runtimeUrl = core.runtimeUrl;\n  if (!runtimeUrl) {\n    throw new TranscriptionError({\n      code: TranscriptionErrorCode.INVALID_REQUEST,\n      message: \"Runtime URL is not configured\",\n      retryable: false,\n    });\n  }\n\n  const headers: Record<string, string> = { ...core.headers };\n  let response: Response;\n\n  try {\n    if (core.runtimeTransport === \"single\") {\n      // Single-endpoint mode: POST JSON with base64 audio\n      const base64Audio = await blobToBase64(audioBlob);\n\n      headers[\"Content-Type\"] = \"application/json\";\n\n      response = await fetch(runtimeUrl, {\n        method: \"POST\",\n        headers,\n        body: JSON.stringify({\n          method: \"transcribe\",\n          body: {\n            audio: base64Audio,\n            mimeType: audioBlob.type || \"audio/webm\",\n            filename,\n          },\n        }),\n      });\n    } else {\n      // REST mode: POST multipart/form-data to /transcribe\n      // Don't set Content-Type - browser will set it with boundary for FormData\n      delete headers[\"Content-Type\"];\n\n      const formData = new FormData();\n      formData.append(\"audio\", audioBlob, filename);\n\n      response = await fetch(`${runtimeUrl}/transcribe`, {\n        method: \"POST\",\n        headers,\n        body: formData,\n      });\n    }\n  } catch (error) {\n    // Network error - fetch failed\n    throw new TranscriptionError({\n      code: TranscriptionErrorCode.NETWORK_ERROR,\n      message:\n        error instanceof Error ? error.message : \"Network request failed\",\n      retryable: true,\n    });\n  }\n\n  if (!response.ok) {\n    let errorData: unknown;\n    try {\n      errorData = await response.json();\n    } catch {\n      // Could not parse error response\n      throw new TranscriptionError({\n        code: TranscriptionErrorCode.PROVIDER_ERROR,\n        message: `HTTP ${response.status}: ${response.statusText}`,\n        retryable: response.status >= 500,\n      });\n    }\n\n    // If we got a typed error response, use it\n    if (isTranscriptionErrorResponse(errorData)) {\n      throw new TranscriptionError(parseTranscriptionError(errorData));\n    }\n\n    // Unknown error format\n    throw new TranscriptionError({\n      code: TranscriptionErrorCode.PROVIDER_ERROR,\n      message:\n        typeof errorData === \"object\" &&\n        errorData !== null &&\n        \"message\" in errorData\n          ? String((errorData as { message: unknown }).message)\n          : \"Transcription failed\",\n      retryable: response.status >= 500,\n    });\n  }\n\n  return (await response.json()) as TranscriptionResult;\n}\n"],"mappings":";;;;;;AA2BA,eAAe,aAAa,MAA6B;AACvD,QAAO,IAAI,SAAS,SAAS,WAAW;EACtC,MAAM,SAAS,IAAI,YAAY;AAC/B,SAAO,kBAAkB;GAGvB,MAAM,SAFS,OAAO,OAEA,MAAM,IAAI,CAAC;AACjC,WAAQ,UAAU,GAAG;;AAEvB,SAAO,gBAAgB,uBAAO,IAAI,MAAM,4BAA4B,CAAC;AACrE,SAAO,cAAc,KAAK;GAC1B;;;;;AAMJ,SAAS,6BACP,MACoC;AACpC,QACE,OAAO,SAAS,YAChB,SAAS,QACT,WAAW,QACX,aAAa,QACb,OAAQ,KAAoC,UAAU,YACtD,OAAQ,KAAoC,YAAY;;;;;AAO5D,SAAS,wBACP,UACwB;AACxB,QAAO;EACL,MAAM,SAAS;EACf,SAAS,SAAS;EAClB,WAAW,SAAS,aAAa;EAClC;;;;;;AAOH,IAAa,qBAAb,cAAwC,MAAM;CAC5C,AAAgB;CAEhB,YAAY,MAA8B;AACxC,QAAM,KAAK,QAAQ;AACnB,OAAK,OAAO;AACZ,OAAK,OAAO;;;;;;;;;;AAWhB,eAAsB,gBACpB,MACA,WACA,WAAmB,kBACW;CAC9B,MAAM,aAAa,KAAK;AACxB,KAAI,CAAC,WACH,OAAM,IAAI,mBAAmB;EAC3B,MAAMA,yBAAuB;EAC7B,SAAS;EACT,WAAW;EACZ,CAAC;CAGJ,MAAM,UAAkC,EAAE,GAAG,KAAK,SAAS;CAC3D,IAAI;AAEJ,KAAI;AACF,MAAI,KAAK,qBAAqB,UAAU;GAEtC,MAAM,cAAc,MAAM,aAAa,UAAU;AAEjD,WAAQ,kBAAkB;AAE1B,cAAW,MAAM,MAAM,YAAY;IACjC,QAAQ;IACR;IACA,MAAM,KAAK,UAAU;KACnB,QAAQ;KACR,MAAM;MACJ,OAAO;MACP,UAAU,UAAU,QAAQ;MAC5B;MACD;KACF,CAAC;IACH,CAAC;SACG;AAGL,UAAO,QAAQ;GAEf,MAAM,WAAW,IAAI,UAAU;AAC/B,YAAS,OAAO,SAAS,WAAW,SAAS;AAE7C,cAAW,MAAM,MAAM,GAAG,WAAW,cAAc;IACjD,QAAQ;IACR;IACA,MAAM;IACP,CAAC;;UAEG,OAAO;AAEd,QAAM,IAAI,mBAAmB;GAC3B,MAAMA,yBAAuB;GAC7B,SACE,iBAAiB,QAAQ,MAAM,UAAU;GAC3C,WAAW;GACZ,CAAC;;AAGJ,KAAI,CAAC,SAAS,IAAI;EAChB,IAAI;AACJ,MAAI;AACF,eAAY,MAAM,SAAS,MAAM;UAC3B;AAEN,SAAM,IAAI,mBAAmB;IAC3B,MAAMA,yBAAuB;IAC7B,SAAS,QAAQ,SAAS,OAAO,IAAI,SAAS;IAC9C,WAAW,SAAS,UAAU;IAC/B,CAAC;;AAIJ,MAAI,6BAA6B,UAAU,CACzC,OAAM,IAAI,mBAAmB,wBAAwB,UAAU,CAAC;AAIlE,QAAM,IAAI,mBAAmB;GAC3B,MAAMA,yBAAuB;GAC7B,SACE,OAAO,cAAc,YACrB,cAAc,QACd,aAAa,YACT,OAAQ,UAAmC,QAAQ,GACnD;GACN,WAAW,SAAS,UAAU;GAC/B,CAAC;;AAGJ,QAAQ,MAAM,SAAS,MAAM"}