naijalingo 0.1.2 → 0.1.3

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.
package/dist/index.cjs CHANGED
@@ -260,6 +260,9 @@ var BaseClient = class {
260
260
  // Let fetch set multipart boundary — do not set Content-Type
261
261
  });
262
262
  }
263
+ async delete(path) {
264
+ await this.request("DELETE", path);
265
+ }
263
266
  };
264
267
  function sleep(ms) {
265
268
  return new Promise((resolve) => setTimeout(resolve, ms));
@@ -641,6 +644,14 @@ var TTS = class {
641
644
  const data = await this.client.getJson(`/v1/speakers/${speakerId}`);
642
645
  return speakerFromDict(data);
643
646
  }
647
+ /** Permanently delete a cloned voice owned by this API key. */
648
+ async deleteVoice(voiceId) {
649
+ const normalizedVoiceId = voiceId.trim();
650
+ if (!normalizedVoiceId) {
651
+ throw new Error("voiceId is required");
652
+ }
653
+ await this.client.delete(`/v1/voices/${encodeURIComponent(normalizedVoiceId)}`);
654
+ }
644
655
  async listLanguages() {
645
656
  const data = await this.client.getJson("/v1/languages");
646
657
  return languageListFromDict(data);
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/client.ts","../src/tts.ts","../src/types.ts","../src/voice.ts"],"sourcesContent":["/**\n * 9jaLingo Node.js SDK\n *\n * Official SDK for the 9jaLingo API — Nigerian language Text-to-Speech.\n *\n * @example\n * ```ts\n * import { NaijaLingo } from \"naijalingo\";\n *\n * const client = new NaijaLingo(); // uses NAIJALINGO_API_KEY\n * const audio = await client.tts.generate(\"Bawo ni!\", {\n * voice: \"adeola_yo\",\n * lang: \"yo\",\n * });\n * await audio.save(\"greeting.wav\");\n * ```\n */\n\nimport { BaseClient, type ClientOptions } from \"./client.js\";\nimport { TTS } from \"./tts.js\";\nimport {\n apiInfoFromDict,\n modelListFromDict,\n serviceInfoFromDict,\n type APIInfo,\n type ModelList,\n type ServiceInfo,\n} from \"./types.js\";\n\nexport const VERSION = \"0.1.2\";\n\nexport {\n AuthenticationError,\n ConnectionError,\n InferenceCapacityError,\n NaijaLingoError,\n NotFoundError,\n RateLimitError,\n ServerError,\n} from \"./errors.js\";\n\nexport {\n AudioResponse,\n AudioStream,\n CloneResponse,\n TTS,\n type CloneOptions,\n type GenerateOptions,\n type ListSpeakersOptions,\n type StreamOptions,\n} from \"./tts.js\";\n\nexport type {\n APIInfo,\n HealthStatus,\n Language,\n LanguageList,\n Model,\n ModelList,\n ResponseFormat,\n ServiceInfo,\n Speaker,\n SpeakerList,\n} from \"./types.js\";\n\nexport type { ClientOptions };\n\nexport class NaijaLingo {\n private readonly _client: BaseClient;\n readonly tts: TTS;\n\n constructor(options: ClientOptions = {}) {\n this._client = new BaseClient(options);\n this.tts = new TTS(this._client);\n }\n\n /** List available TTS models. GET /v1/models */\n async listModels(): Promise<ModelList> {\n const data = await this._client.getJson(\"/v1/models\");\n return modelListFromDict(data);\n }\n\n /** Root API information. GET / */\n async apiInfo(): Promise<APIInfo> {\n const data = await this._client.getJson(\"/\");\n return apiInfoFromDict(data);\n }\n\n /** v1 service metadata. GET /v1 */\n async serviceInfo(): Promise<ServiceInfo> {\n const data = await this._client.getJson(\"/v1\");\n return serviceInfoFromDict(data);\n }\n}\n","/** Base exception for all 9jaLingo SDK errors. */\nexport class NaijaLingoError extends Error {\n readonly statusCode?: number;\n readonly response?: unknown;\n\n constructor(message: string, statusCode?: number, response?: unknown) {\n super(message);\n this.name = \"NaijaLingoError\";\n this.statusCode = statusCode;\n this.response = response;\n }\n}\n\n/** Raised when the API key is missing or invalid. */\nexport class AuthenticationError extends NaijaLingoError {\n constructor(message: string, statusCode?: number, response?: unknown) {\n super(message, statusCode, response);\n this.name = \"AuthenticationError\";\n }\n}\n\n/** Raised when rate limit is exceeded. */\nexport class RateLimitError extends NaijaLingoError {\n constructor(message: string, statusCode?: number, response?: unknown) {\n super(message, statusCode, response);\n this.name = \"RateLimitError\";\n }\n}\n\n/** Raised when a requested resource is not found. */\nexport class NotFoundError extends NaijaLingoError {\n constructor(message: string, statusCode?: number, response?: unknown) {\n super(message, statusCode, response);\n this.name = \"NotFoundError\";\n }\n}\n\n/** Raised when the API returns a 5xx error. */\nexport class ServerError extends NaijaLingoError {\n constructor(message: string, statusCode?: number, response?: unknown) {\n super(message, statusCode, response);\n this.name = \"ServerError\";\n }\n}\n\n/** Raised when the inference GPU is waking from scale-to-zero. */\nexport class InferenceCapacityError extends ServerError {\n constructor(message: string, statusCode?: number, response?: unknown) {\n super(message, statusCode, response);\n this.name = \"InferenceCapacityError\";\n }\n}\n\n/** Raised when unable to connect to the API. */\nexport class ConnectionError extends NaijaLingoError {\n constructor(message: string, statusCode?: number, response?: unknown) {\n super(message, statusCode, response);\n this.name = \"ConnectionError\";\n }\n}\n","import {\n AuthenticationError,\n ConnectionError,\n InferenceCapacityError,\n NaijaLingoError,\n NotFoundError,\n RateLimitError,\n ServerError,\n} from \"./errors.js\";\n\nconst DEFAULT_BASE_URL = \"https://api.9jalingo.org\";\nconst DEFAULT_TIMEOUT_MS = 300_000;\n\nexport interface ClientOptions {\n apiKey?: string;\n baseUrl?: string;\n /** Request timeout in milliseconds (default 300000). */\n timeout?: number;\n}\n\nexport class BaseClient {\n readonly apiKey: string;\n readonly baseUrl: string;\n readonly timeout: number;\n private readonly defaultHeaders: Record<string, string>;\n\n constructor(options: ClientOptions = {}) {\n this.apiKey =\n options.apiKey ?? process.env.NAIJALINGO_API_KEY ?? \"\";\n const base =\n options.baseUrl ??\n process.env.NAIJALINGO_BASE_URL ??\n DEFAULT_BASE_URL;\n this.baseUrl = base.replace(/\\/+$/, \"\");\n this.timeout = options.timeout ?? DEFAULT_TIMEOUT_MS;\n\n this.defaultHeaders = {\n \"User-Agent\": \"naijalingo-js/0.1.2\",\n };\n if (this.apiKey) {\n this.defaultHeaders[\"X-API-Key\"] = this.apiKey;\n }\n }\n\n private async request(\n method: string,\n path: string,\n init: RequestInit & { timeoutMs?: number } = {},\n ): Promise<Response> {\n const url = `${this.baseUrl}${path.startsWith(\"/\") ? path : `/${path}`}`;\n const timeoutMs = init.timeoutMs ?? this.timeout;\n let lastError: unknown;\n\n for (let attempt = 0; attempt < 3; attempt++) {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeoutMs);\n try {\n const response = await fetch(url, {\n ...init,\n method,\n headers: {\n ...this.defaultHeaders,\n ...(init.headers as Record<string, string> | undefined),\n },\n signal: controller.signal,\n });\n clearTimeout(timer);\n\n if (response.ok) {\n return response;\n }\n await this.raiseForStatus(response);\n // unreachable\n return response;\n } catch (err) {\n clearTimeout(timer);\n if (err instanceof NaijaLingoError) {\n throw err;\n }\n lastError = err;\n const isAbort =\n err instanceof Error &&\n (err.name === \"AbortError\" || err.name === \"TimeoutError\");\n // Only retry connect-style failures, not aborts from long reads\n if (isAbort) {\n throw new ConnectionError(\n `Request timed out after ${timeoutMs}ms: ${String(err)}`,\n );\n }\n if (attempt < 2) {\n await sleep(1500);\n continue;\n }\n }\n }\n\n throw new ConnectionError(\n `Unable to connect to ${this.baseUrl}: ${String(lastError)}`,\n );\n }\n\n private async raiseForStatus(response: Response): Promise<never> {\n const status = response.status;\n let detail: string;\n let body: unknown;\n try {\n body = await response.json();\n detail =\n typeof body === \"object\" &&\n body !== null &&\n \"detail\" in body\n ? String((body as { detail: unknown }).detail)\n : JSON.stringify(body);\n } catch {\n detail = await response.text();\n }\n\n const normalizedDetail = detail.toLowerCase();\n if (status === 503 && (\n normalizedDetail.includes(\"inference capacity\")\n || normalizedDetail.includes(\"inference component has no capacity\")\n || normalizedDetail.includes(\"capacity is starting\")\n )) {\n throw new InferenceCapacityError(detail, status, body);\n }\n if (status === 401 || status === 403) {\n throw new AuthenticationError(detail, status, body);\n }\n if (status === 404) {\n throw new NotFoundError(detail, status, body);\n }\n if (status === 429) {\n throw new RateLimitError(detail, status, body);\n }\n if (status >= 500) {\n throw new ServerError(detail, status, body);\n }\n throw new NaijaLingoError(detail, status, body);\n }\n\n async getJson(\n path: string,\n params?: Record<string, string | undefined | null>,\n ): Promise<Record<string, unknown>> {\n let url = path;\n if (params) {\n const qs = new URLSearchParams();\n for (const [k, v] of Object.entries(params)) {\n if (v != null) qs.set(k, v);\n }\n const s = qs.toString();\n if (s) url = `${path}?${s}`;\n }\n const resp = await this.request(\"GET\", url);\n return (await resp.json()) as Record<string, unknown>;\n }\n\n async postBytes(\n path: string,\n body: Record<string, unknown>,\n ): Promise<Uint8Array> {\n const resp = await this.request(\"POST\", path, {\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(body),\n });\n return new Uint8Array(await resp.arrayBuffer());\n }\n\n async *postStream(\n path: string,\n body: Record<string, unknown>,\n ): AsyncGenerator<Uint8Array, void, unknown> {\n let lastError: unknown;\n for (let attempt = 0; attempt < 3; attempt++) {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.timeout);\n try {\n const response = await fetch(\n `${this.baseUrl}${path.startsWith(\"/\") ? path : `/${path}`}`,\n {\n method: \"POST\",\n headers: {\n ...this.defaultHeaders,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(body),\n signal: controller.signal,\n },\n );\n clearTimeout(timer);\n\n if (!response.ok) {\n await this.raiseForStatus(response);\n }\n if (!response.body) {\n throw new ConnectionError(\"No response body for stream\");\n }\n\n const reader = response.body.getReader();\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n if (value && value.length > 0) {\n yield value;\n }\n }\n } finally {\n reader.releaseLock();\n }\n return;\n } catch (err) {\n clearTimeout(timer);\n if (err instanceof NaijaLingoError) throw err;\n lastError = err;\n const isAbort =\n err instanceof Error &&\n (err.name === \"AbortError\" || err.name === \"TimeoutError\");\n if (isAbort) {\n throw new ConnectionError(`Request timed out: ${String(err)}`);\n }\n if (attempt < 2) {\n await sleep(1500);\n continue;\n }\n }\n }\n throw new ConnectionError(\n `Unable to connect to ${this.baseUrl}: ${String(lastError)}`,\n );\n }\n\n async postMultipart(\n path: string,\n form: FormData,\n timeoutMs?: number,\n ): Promise<Response> {\n return this.request(\"POST\", path, {\n body: form,\n timeoutMs: timeoutMs ?? Math.max(this.timeout, 600_000),\n // Let fetch set multipart boundary — do not set Content-Type\n });\n }\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n","import { mkdir, writeFile } from \"node:fs/promises\";\nimport { basename, dirname } from \"node:path\";\nimport { readFileSync } from \"node:fs\";\nimport { BaseClient } from \"./client.js\";\nimport {\n type HealthStatus,\n type LanguageList,\n type ResponseFormat,\n type Speaker,\n type SpeakerList,\n healthStatusFromDict,\n languageListFromDict,\n speakerFromDict,\n speakerListFromDict,\n} from \"./types.js\";\nimport {\n resolveCloneLangAndSpeaker,\n resolveTtsVoiceAndLang,\n} from \"./voice.js\";\n\nconst DEFAULT_MODEL_NAME = \"9jalingo-tts-1\";\n\nexport type GenerateOptions = {\n voice?: string;\n speaker?: string;\n lang?: string;\n language?: string;\n modelName?: string;\n speakerEmbedding?: number[];\n responseFormat?: ResponseFormat;\n temperature?: number;\n topP?: number;\n repetitionPenalty?: number;\n enableLongForm?: boolean;\n maxChunkDuration?: number;\n silenceDuration?: number;\n};\n\nexport type StreamOptions = Omit<\n GenerateOptions,\n \"modelName\" | \"responseFormat\"\n>;\n\nexport type CloneOptions = {\n voice?: string;\n lang?: string;\n speaker?: string;\n modelName?: string;\n temperature?: number;\n topP?: number;\n repetitionPenalty?: number;\n responseFormat?: ResponseFormat;\n};\n\nexport type ListSpeakersOptions = {\n language?: string;\n gender?: string;\n domain?: string;\n};\n\n/** Audio data returned from a generation request. */\nexport class AudioResponse {\n readonly content: Uint8Array;\n readonly mediaType: string;\n\n constructor(content: Uint8Array, mediaType = \"audio/wav\") {\n this.content = content;\n this.mediaType = mediaType;\n }\n\n /** Write the audio to a file. */\n async save(path: string): Promise<string> {\n await mkdir(dirname(path), { recursive: true });\n await writeFile(path, this.content);\n return path;\n }\n\n get length(): number {\n return this.content.length;\n }\n\n toString(): string {\n return `AudioResponse(${this.content.length} bytes, ${this.mediaType})`;\n }\n}\n\n/** Audio and reusable voice metadata returned from a clone request. */\nexport class CloneResponse extends AudioResponse {\n readonly voiceId: string | null;\n readonly voiceCode: string | null;\n readonly voiceName: string | null;\n readonly cloneId: string | null;\n readonly jobId: string | null;\n\n constructor(\n content: Uint8Array,\n mediaType: string,\n metadata: {\n voiceId: string | null;\n voiceCode: string | null;\n voiceName: string | null;\n cloneId: string | null;\n jobId: string | null;\n },\n ) {\n super(content, mediaType);\n this.voiceId = metadata.voiceId;\n this.voiceCode = metadata.voiceCode;\n this.voiceName = metadata.voiceName;\n this.cloneId = metadata.cloneId;\n this.jobId = metadata.jobId;\n }\n}\n\n/** Streaming audio response — yields byte chunks as they arrive. */\nexport class AudioStream implements AsyncIterable<Uint8Array> {\n private readonly chunks: AsyncIterable<Uint8Array>;\n private collected: Uint8Array | null = null;\n\n constructor(chunks: AsyncIterable<Uint8Array>) {\n this.chunks = chunks;\n }\n\n async *[Symbol.asyncIterator](): AsyncIterator<Uint8Array> {\n for await (const chunk of this.chunks) {\n yield chunk;\n }\n }\n\n /** Consume the entire stream and return an AudioResponse. */\n async collect(): Promise<AudioResponse> {\n if (this.collected == null) {\n const parts: Uint8Array[] = [];\n let total = 0;\n for await (const chunk of this.chunks) {\n parts.push(chunk);\n total += chunk.length;\n }\n const out = new Uint8Array(total);\n let offset = 0;\n for (const part of parts) {\n out.set(part, offset);\n offset += part.length;\n }\n this.collected = out;\n }\n return new AudioResponse(this.collected, \"audio/wav\");\n }\n}\n\nexport class TTS {\n private readonly client: BaseClient;\n\n constructor(client: BaseClient) {\n this.client = client;\n }\n\n /** Generate speech from text. */\n async generate(\n text: string,\n options: GenerateOptions = {},\n ): Promise<AudioResponse> {\n let [resolvedVoice, resolvedLang] = resolveTtsVoiceAndLang(options);\n if (resolvedVoice == null && options.speakerEmbedding == null) {\n resolvedVoice = \"blessing_pcm\";\n }\n const responseFormat = options.responseFormat ?? \"wav\";\n const body = buildBody({\n input: text,\n voice: resolvedVoice,\n lang: resolvedLang,\n model: options.modelName ?? DEFAULT_MODEL_NAME,\n speaker_embedding: options.speakerEmbedding,\n response_format: responseFormat,\n temperature: options.temperature,\n top_p: options.topP,\n repetition_penalty: options.repetitionPenalty,\n enable_long_form: options.enableLongForm ?? true,\n max_chunk_duration: options.maxChunkDuration,\n silence_duration: options.silenceDuration,\n });\n const content = await this.client.postBytes(\"/v1/audio/speech\", body);\n const mediaType = MEDIA_TYPES[responseFormat] ?? \"application/octet-stream\";\n return new AudioResponse(content, mediaType);\n }\n\n /** Stream speech generation — audio arrives as it's produced. */\n stream(text: string, options: StreamOptions = {}): AudioStream {\n let [resolvedVoice, resolvedLang] = resolveTtsVoiceAndLang(options);\n if (resolvedVoice == null && options.speakerEmbedding == null) {\n resolvedVoice = \"blessing_pcm\";\n }\n const body = buildBody({\n input: text,\n voice: resolvedVoice,\n lang: resolvedLang,\n speaker_embedding: options.speakerEmbedding,\n response_format: \"wav\",\n temperature: options.temperature,\n top_p: options.topP,\n repetition_penalty: options.repetitionPenalty,\n enable_long_form: options.enableLongForm ?? true,\n max_chunk_duration: options.maxChunkDuration,\n silence_duration: options.silenceDuration,\n });\n return new AudioStream(this.client.postStream(\"/v1/audio/speech/stream\", body));\n }\n\n /**\n * Generate speech using a cloned voice from a reference audio file.\n * `audioFile` may be a filesystem path, Buffer, Uint8Array, Blob, or File.\n */\n async clone(\n text: string,\n audioFile: string | Buffer | Uint8Array | Blob,\n options: CloneOptions = {},\n ): Promise<CloneResponse> {\n const voice = options.voice ?? \"pcm\";\n const [resolvedLang, resolvedSpeaker] = resolveCloneLangAndSpeaker(\n voice,\n { lang: options.lang, speaker: options.speaker },\n );\n const responseFormat = options.responseFormat ?? \"wav\";\n\n const form = new FormData();\n form.append(\"text\", text);\n form.append(\"lang\", resolvedLang);\n form.append(\"model_name\", options.modelName ?? DEFAULT_MODEL_NAME);\n form.append(\"response_format\", responseFormat);\n if (resolvedSpeaker) {\n form.append(\"voice\", resolvedSpeaker);\n }\n if (options.temperature != null) {\n form.append(\"temperature\", String(options.temperature));\n }\n if (options.topP != null) {\n form.append(\"top_p\", String(options.topP));\n }\n if (options.repetitionPenalty != null) {\n form.append(\"repetition_penalty\", String(options.repetitionPenalty));\n }\n\n const { blob, filename } = await toAudioBlob(audioFile);\n form.append(\"audio\", blob, filename);\n\n const response = await this.client.postMultipart(\"/v1/audio/clone\", form);\n const content = new Uint8Array(await response.arrayBuffer());\n const mediaType = MEDIA_TYPES[responseFormat] ?? \"application/octet-stream\";\n return new CloneResponse(content, mediaType, {\n voiceId: response.headers.get(\"X-Voice-ID\"),\n voiceCode: response.headers.get(\"X-Voice-Code\"),\n voiceName: response.headers.get(\"X-Voice-Name\"),\n cloneId: response.headers.get(\"X-Clone-ID\"),\n jobId: response.headers.get(\"X-Job-ID\"),\n });\n }\n\n async listSpeakers(\n options: ListSpeakersOptions = {},\n ): Promise<SpeakerList> {\n const data = await this.client.getJson(\"/v1/speakers\", {\n language: options.language,\n gender: options.gender,\n domain: options.domain,\n });\n return speakerListFromDict(data);\n }\n\n async getSpeaker(speakerId: string): Promise<Speaker> {\n const data = await this.client.getJson(`/v1/speakers/${speakerId}`);\n return speakerFromDict(data);\n }\n\n async listLanguages(): Promise<LanguageList> {\n const data = await this.client.getJson(\"/v1/languages\");\n return languageListFromDict(data);\n }\n\n async health(): Promise<HealthStatus> {\n const data = await this.client.getJson(\"/v1/health\");\n return healthStatusFromDict(data);\n }\n}\n\nconst MEDIA_TYPES: Record<string, string> = {\n wav: \"audio/wav\",\n pcm: \"application/octet-stream\",\n flac: \"audio/flac\",\n aac: \"audio/aac\",\n ogg: \"audio/ogg\",\n mp3: \"audio/mpeg\",\n alac: \"audio/alac\",\n};\n\nfunction buildBody(\n kwargs: Record<string, unknown>,\n): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(kwargs)) {\n if (v !== undefined && v !== null) out[k] = v;\n }\n return out;\n}\n\nasync function toAudioBlob(\n audioFile: string | Buffer | Uint8Array | Blob,\n): Promise<{ blob: Blob; filename: string }> {\n if (typeof audioFile === \"string\") {\n const bytes = readFileSync(audioFile);\n const filename = basename(audioFile);\n const mime = guessMime(filename);\n return {\n blob: new Blob([bytes], { type: mime }),\n filename,\n };\n }\n if (audioFile instanceof Blob) {\n return {\n blob: audioFile,\n filename: \"audio.wav\",\n };\n }\n // Buffer | Uint8Array\n const bytes =\n audioFile instanceof Uint8Array\n ? audioFile\n : new Uint8Array(audioFile);\n return {\n blob: new Blob([bytes], { type: \"application/octet-stream\" }),\n filename: \"audio.wav\",\n };\n}\n\nfunction guessMime(filename: string): string {\n const lower = filename.toLowerCase();\n if (lower.endsWith(\".wav\")) return \"audio/wav\";\n if (lower.endsWith(\".mp3\")) return \"audio/mpeg\";\n if (lower.endsWith(\".flac\")) return \"audio/flac\";\n if (lower.endsWith(\".ogg\")) return \"audio/ogg\";\n if (lower.endsWith(\".aac\") || lower.endsWith(\".m4a\")) return \"audio/aac\";\n return \"application/octet-stream\";\n}\n","/** A speaker voice identity. */\nexport interface Speaker {\n id: string;\n name: string;\n language: string;\n gender?: string | null;\n domain?: string | null;\n}\n\nexport function speakerFromDict(data: Record<string, unknown>): Speaker {\n return {\n id: String(data.id ?? data.speaker_id ?? \"\"),\n name: String(data.name ?? data.id ?? \"\"),\n language: String(data.language ?? \"\"),\n gender: (data.gender as string | null | undefined) ?? null,\n domain: (data.domain as string | null | undefined) ?? null,\n };\n}\n\n/** List of speakers with metadata. */\nexport interface SpeakerList {\n speakers: Speaker[];\n total: number;\n byLanguage: Record<string, number>;\n [Symbol.iterator](): Iterator<Speaker>;\n length: number;\n}\n\nexport function speakerListFromDict(data: Record<string, unknown>): SpeakerList {\n const raw = (data.speakers as Record<string, unknown>[] | undefined) ?? [];\n const speakers = raw.map(speakerFromDict);\n const total = typeof data.total === \"number\" ? data.total : speakers.length;\n const byLanguage =\n (data.by_language as Record<string, number> | undefined) ?? {};\n return {\n speakers,\n total,\n byLanguage,\n get length() {\n return total;\n },\n [Symbol.iterator]() {\n return speakers[Symbol.iterator]();\n },\n };\n}\n\n/** A supported language. */\nexport interface Language {\n code: string;\n name: string;\n speakerCount: number;\n}\n\nexport function languageFromDict(data: Record<string, unknown>): Language {\n return {\n code: String(data.code ?? \"\"),\n name: String(data.name ?? \"\"),\n speakerCount: Number(data.speaker_count ?? 0),\n };\n}\n\n/** List of supported languages and domains. */\nexport interface LanguageList {\n languages: Language[];\n domains: string[];\n}\n\nexport function languageListFromDict(data: Record<string, unknown>): LanguageList {\n const rawLangs = data.languages;\n let languages: Language[];\n\n if (rawLangs && typeof rawLangs === \"object\" && !Array.isArray(rawLangs)) {\n languages = Object.entries(rawLangs as Record<string, unknown>).map(\n ([code, value]) => {\n if (value && typeof value === \"object\") {\n const v = value as Record<string, unknown>;\n return {\n code,\n name: String(v.name ?? code),\n speakerCount: Number(v.speaker_count ?? 0),\n };\n }\n return { code, name: String(value), speakerCount: 0 };\n },\n );\n } else {\n const arr = (rawLangs as Record<string, unknown>[] | undefined) ?? [];\n languages = arr.map(languageFromDict);\n }\n\n return {\n languages,\n domains: (data.domains as string[] | undefined) ?? [],\n };\n}\n\n/** API health check result. */\nexport interface HealthStatus {\n status: string;\n engineReady: boolean;\n codecReady: boolean;\n totalSpeakers: number;\n languages: string[];\n voiceCloningAvailable: boolean;\n speakerProjectionLoaded: boolean;\n}\n\nexport function healthStatusFromDict(data: Record<string, unknown>): HealthStatus {\n const supported = data.supported_languages;\n let languages: string[] = [];\n if (Array.isArray(data.languages)) {\n languages = data.languages as string[];\n } else if (supported && typeof supported === \"object\") {\n languages = Object.keys(supported as Record<string, unknown>);\n }\n\n return {\n status: String(data.status ?? \"unknown\"),\n engineReady: Boolean(data.engine_ready ?? data.tts_initialized ?? false),\n codecReady: Boolean(data.codec_ready ?? false),\n totalSpeakers: Number(data.total_speakers ?? data.speakers_loaded ?? 0),\n languages,\n voiceCloningAvailable: Boolean(data.voice_cloning_available ?? false),\n speakerProjectionLoaded: Boolean(data.speaker_projection_loaded ?? false),\n };\n}\n\n/** An available TTS model. */\nexport interface Model {\n id: string;\n object: string;\n ownedBy: string;\n}\n\nexport function modelFromDict(data: Record<string, unknown>): Model {\n return {\n id: String(data.id ?? \"\"),\n object: String(data.object ?? \"model\"),\n ownedBy: String(data.owned_by ?? \"9jalingo\"),\n };\n}\n\n/** List of available models. */\nexport interface ModelList {\n models: Model[];\n object: string;\n [Symbol.iterator](): Iterator<Model>;\n length: number;\n}\n\nexport function modelListFromDict(data: Record<string, unknown>): ModelList {\n const raw = (data.data as Record<string, unknown>[] | undefined) ?? [];\n const models = raw.map(modelFromDict);\n return {\n models,\n object: String(data.object ?? \"list\"),\n get length() {\n return models.length;\n },\n [Symbol.iterator]() {\n return models[Symbol.iterator]();\n },\n };\n}\n\n/** Root API information returned by GET /. */\nexport interface APIInfo {\n name: string;\n version: string;\n description: string;\n endpoints: Record<string, string>;\n}\n\nexport function apiInfoFromDict(data: Record<string, unknown>): APIInfo {\n return {\n name: String(data.name ?? \"\"),\n version: String(data.version ?? \"\"),\n description: String(data.description ?? \"\"),\n endpoints: (data.endpoints as Record<string, string> | undefined) ?? {},\n };\n}\n\n/** Service metadata returned by GET /v1. */\nexport interface ServiceInfo {\n object: string;\n name: string;\n modelsUrl: string;\n speechUrl: string;\n speechStreamUrl: string;\n}\n\nexport function serviceInfoFromDict(data: Record<string, unknown>): ServiceInfo {\n return {\n object: String(data.object ?? \"service\"),\n name: String(data.name ?? \"\"),\n modelsUrl: String(data.models_url ?? \"\"),\n speechUrl: String(data.speech_url ?? \"\"),\n speechStreamUrl: String(data.speech_stream_url ?? \"\"),\n };\n}\n\nexport type ResponseFormat =\n | \"wav\"\n | \"pcm\"\n | \"flac\"\n | \"aac\"\n | \"ogg\"\n | \"mp3\"\n | \"alac\";\n","const LANG_ALIASES: Record<string, string> = {\n yo: \"yo\",\n yor: \"yo\",\n yoruba: \"yo\",\n ig: \"ig\",\n ibo: \"ig\",\n igbo: \"ig\",\n ha: \"ha\",\n hau: \"ha\",\n hausa: \"ha\",\n pcm: \"pcm\",\n pidgin: \"pcm\",\n};\n\nexport function normalizeLang(code: string): string | null {\n return LANG_ALIASES[code.trim().toLowerCase()] ?? null;\n}\n\n/**\n * Resolve speech API fields: voice/speaker + lang/language.\n * Returns [speakerId, langCode]. Bare language codes must be passed via lang/language.\n */\nexport function resolveTtsVoiceAndLang(options: {\n voice?: string | null;\n speaker?: string | null;\n lang?: string | null;\n language?: string | null;\n}): [string | null, string | null] {\n let resolvedLang: string | null = null;\n\n if (options.lang != null) {\n resolvedLang = normalizeLang(options.lang);\n if (resolvedLang == null) {\n throw new Error(\n `Unsupported language '${options.lang}'. Use ha, ig, yo, or pcm.`,\n );\n }\n } else if (options.language != null) {\n resolvedLang = normalizeLang(options.language);\n if (resolvedLang == null) {\n throw new Error(\n `Unsupported language '${options.language}'. Use ha, ig, yo, or pcm.`,\n );\n }\n }\n\n // speaker takes precedence over voice\n const candidate =\n options.speaker != null ? options.speaker : options.voice;\n if (candidate == null || !String(candidate).trim()) {\n return [null, resolvedLang];\n }\n\n const resolved = String(candidate).trim();\n const normalized = resolved.toLowerCase();\n if (normalized in LANG_ALIASES) {\n const langCode = LANG_ALIASES[normalized];\n throw new Error(\n `'${resolved}' is a language code, not a speaker ID. ` +\n `Pass speaker/voice='ada_pcm' (or another speaker ID) and ` +\n `lang='${langCode}' for the language. ` +\n `Browse speakers with: client.tts.listSpeakers({ language: '${langCode}' })`,\n );\n }\n\n if (resolvedLang == null && resolved.includes(\"_\")) {\n const suffix = resolved.split(\"_\").pop()!;\n resolvedLang = normalizeLang(suffix);\n }\n\n return [resolved, resolvedLang];\n}\n\n/**\n * Resolve clone form fields.\n * voice may be a language code (\"pcm\") or a speaker ID with a language suffix.\n */\nexport function resolveCloneLangAndSpeaker(\n voice: string,\n options: { lang?: string | null; speaker?: string | null } = {},\n): [string, string | null] {\n let resolvedLang =\n options.lang != null ? normalizeLang(options.lang) : null;\n let resolvedSpeaker = options.speaker?.trim() || null;\n\n const voiceStr = (voice || \"\").trim();\n const voiceNorm = voiceStr.toLowerCase();\n\n if (voiceNorm in LANG_ALIASES) {\n if (resolvedLang == null) {\n resolvedLang = LANG_ALIASES[voiceNorm];\n }\n } else if (voiceStr.includes(\"_\")) {\n if (resolvedSpeaker == null) {\n resolvedSpeaker = voiceStr;\n }\n if (resolvedLang == null) {\n const suffix = voiceStr.split(\"_\").pop()!;\n resolvedLang = normalizeLang(suffix);\n }\n } else if (voiceStr && resolvedLang == null) {\n throw new Error(\n `'${voice}' is not a language code (ha/ig/yo/pcm) or a speaker ID ` +\n `with a language suffix (e.g. 'daniel_pcm'). ` +\n `Pass voice='pcm' or lang='pcm'.`,\n );\n }\n\n if (!resolvedLang) {\n throw new Error(\n \"Clone requires a language. Pass voice='pcm' (or 'ha'/'ig'/'yo'), \" +\n \"lang='pcm', or a speaker ID ending in _pcm/_ha/_ig/_yo.\",\n );\n }\n\n return [resolvedLang, resolvedSpeaker];\n}\n"],"mappings":"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","names":["bytes"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/client.ts","../src/tts.ts","../src/types.ts","../src/voice.ts"],"sourcesContent":["/**\n * 9jaLingo Node.js SDK\n *\n * Official SDK for the 9jaLingo API — Nigerian language Text-to-Speech.\n *\n * @example\n * ```ts\n * import { NaijaLingo } from \"naijalingo\";\n *\n * const client = new NaijaLingo(); // uses NAIJALINGO_API_KEY\n * const audio = await client.tts.generate(\"Bawo ni!\", {\n * voice: \"adeola_yo\",\n * lang: \"yo\",\n * });\n * await audio.save(\"greeting.wav\");\n * ```\n */\n\nimport { BaseClient, type ClientOptions } from \"./client.js\";\nimport { TTS } from \"./tts.js\";\nimport {\n apiInfoFromDict,\n modelListFromDict,\n serviceInfoFromDict,\n type APIInfo,\n type ModelList,\n type ServiceInfo,\n} from \"./types.js\";\n\nexport const VERSION = \"0.1.2\";\n\nexport {\n AuthenticationError,\n ConnectionError,\n InferenceCapacityError,\n NaijaLingoError,\n NotFoundError,\n RateLimitError,\n ServerError,\n} from \"./errors.js\";\n\nexport {\n AudioResponse,\n AudioStream,\n CloneResponse,\n TTS,\n type CloneOptions,\n type GenerateOptions,\n type ListSpeakersOptions,\n type StreamOptions,\n} from \"./tts.js\";\n\nexport type {\n APIInfo,\n HealthStatus,\n Language,\n LanguageList,\n Model,\n ModelList,\n ResponseFormat,\n ServiceInfo,\n Speaker,\n SpeakerList,\n} from \"./types.js\";\n\nexport type { ClientOptions };\n\nexport class NaijaLingo {\n private readonly _client: BaseClient;\n readonly tts: TTS;\n\n constructor(options: ClientOptions = {}) {\n this._client = new BaseClient(options);\n this.tts = new TTS(this._client);\n }\n\n /** List available TTS models. GET /v1/models */\n async listModels(): Promise<ModelList> {\n const data = await this._client.getJson(\"/v1/models\");\n return modelListFromDict(data);\n }\n\n /** Root API information. GET / */\n async apiInfo(): Promise<APIInfo> {\n const data = await this._client.getJson(\"/\");\n return apiInfoFromDict(data);\n }\n\n /** v1 service metadata. GET /v1 */\n async serviceInfo(): Promise<ServiceInfo> {\n const data = await this._client.getJson(\"/v1\");\n return serviceInfoFromDict(data);\n }\n}\n","/** Base exception for all 9jaLingo SDK errors. */\nexport class NaijaLingoError extends Error {\n readonly statusCode?: number;\n readonly response?: unknown;\n\n constructor(message: string, statusCode?: number, response?: unknown) {\n super(message);\n this.name = \"NaijaLingoError\";\n this.statusCode = statusCode;\n this.response = response;\n }\n}\n\n/** Raised when the API key is missing or invalid. */\nexport class AuthenticationError extends NaijaLingoError {\n constructor(message: string, statusCode?: number, response?: unknown) {\n super(message, statusCode, response);\n this.name = \"AuthenticationError\";\n }\n}\n\n/** Raised when rate limit is exceeded. */\nexport class RateLimitError extends NaijaLingoError {\n constructor(message: string, statusCode?: number, response?: unknown) {\n super(message, statusCode, response);\n this.name = \"RateLimitError\";\n }\n}\n\n/** Raised when a requested resource is not found. */\nexport class NotFoundError extends NaijaLingoError {\n constructor(message: string, statusCode?: number, response?: unknown) {\n super(message, statusCode, response);\n this.name = \"NotFoundError\";\n }\n}\n\n/** Raised when the API returns a 5xx error. */\nexport class ServerError extends NaijaLingoError {\n constructor(message: string, statusCode?: number, response?: unknown) {\n super(message, statusCode, response);\n this.name = \"ServerError\";\n }\n}\n\n/** Raised when the inference GPU is waking from scale-to-zero. */\nexport class InferenceCapacityError extends ServerError {\n constructor(message: string, statusCode?: number, response?: unknown) {\n super(message, statusCode, response);\n this.name = \"InferenceCapacityError\";\n }\n}\n\n/** Raised when unable to connect to the API. */\nexport class ConnectionError extends NaijaLingoError {\n constructor(message: string, statusCode?: number, response?: unknown) {\n super(message, statusCode, response);\n this.name = \"ConnectionError\";\n }\n}\n","import {\n AuthenticationError,\n ConnectionError,\n InferenceCapacityError,\n NaijaLingoError,\n NotFoundError,\n RateLimitError,\n ServerError,\n} from \"./errors.js\";\n\nconst DEFAULT_BASE_URL = \"https://api.9jalingo.org\";\nconst DEFAULT_TIMEOUT_MS = 300_000;\n\nexport interface ClientOptions {\n apiKey?: string;\n baseUrl?: string;\n /** Request timeout in milliseconds (default 300000). */\n timeout?: number;\n}\n\nexport class BaseClient {\n readonly apiKey: string;\n readonly baseUrl: string;\n readonly timeout: number;\n private readonly defaultHeaders: Record<string, string>;\n\n constructor(options: ClientOptions = {}) {\n this.apiKey =\n options.apiKey ?? process.env.NAIJALINGO_API_KEY ?? \"\";\n const base =\n options.baseUrl ??\n process.env.NAIJALINGO_BASE_URL ??\n DEFAULT_BASE_URL;\n this.baseUrl = base.replace(/\\/+$/, \"\");\n this.timeout = options.timeout ?? DEFAULT_TIMEOUT_MS;\n\n this.defaultHeaders = {\n \"User-Agent\": \"naijalingo-js/0.1.2\",\n };\n if (this.apiKey) {\n this.defaultHeaders[\"X-API-Key\"] = this.apiKey;\n }\n }\n\n private async request(\n method: string,\n path: string,\n init: RequestInit & { timeoutMs?: number } = {},\n ): Promise<Response> {\n const url = `${this.baseUrl}${path.startsWith(\"/\") ? path : `/${path}`}`;\n const timeoutMs = init.timeoutMs ?? this.timeout;\n let lastError: unknown;\n\n for (let attempt = 0; attempt < 3; attempt++) {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeoutMs);\n try {\n const response = await fetch(url, {\n ...init,\n method,\n headers: {\n ...this.defaultHeaders,\n ...(init.headers as Record<string, string> | undefined),\n },\n signal: controller.signal,\n });\n clearTimeout(timer);\n\n if (response.ok) {\n return response;\n }\n await this.raiseForStatus(response);\n // unreachable\n return response;\n } catch (err) {\n clearTimeout(timer);\n if (err instanceof NaijaLingoError) {\n throw err;\n }\n lastError = err;\n const isAbort =\n err instanceof Error &&\n (err.name === \"AbortError\" || err.name === \"TimeoutError\");\n // Only retry connect-style failures, not aborts from long reads\n if (isAbort) {\n throw new ConnectionError(\n `Request timed out after ${timeoutMs}ms: ${String(err)}`,\n );\n }\n if (attempt < 2) {\n await sleep(1500);\n continue;\n }\n }\n }\n\n throw new ConnectionError(\n `Unable to connect to ${this.baseUrl}: ${String(lastError)}`,\n );\n }\n\n private async raiseForStatus(response: Response): Promise<never> {\n const status = response.status;\n let detail: string;\n let body: unknown;\n try {\n body = await response.json();\n detail =\n typeof body === \"object\" &&\n body !== null &&\n \"detail\" in body\n ? String((body as { detail: unknown }).detail)\n : JSON.stringify(body);\n } catch {\n detail = await response.text();\n }\n\n const normalizedDetail = detail.toLowerCase();\n if (status === 503 && (\n normalizedDetail.includes(\"inference capacity\")\n || normalizedDetail.includes(\"inference component has no capacity\")\n || normalizedDetail.includes(\"capacity is starting\")\n )) {\n throw new InferenceCapacityError(detail, status, body);\n }\n if (status === 401 || status === 403) {\n throw new AuthenticationError(detail, status, body);\n }\n if (status === 404) {\n throw new NotFoundError(detail, status, body);\n }\n if (status === 429) {\n throw new RateLimitError(detail, status, body);\n }\n if (status >= 500) {\n throw new ServerError(detail, status, body);\n }\n throw new NaijaLingoError(detail, status, body);\n }\n\n async getJson(\n path: string,\n params?: Record<string, string | undefined | null>,\n ): Promise<Record<string, unknown>> {\n let url = path;\n if (params) {\n const qs = new URLSearchParams();\n for (const [k, v] of Object.entries(params)) {\n if (v != null) qs.set(k, v);\n }\n const s = qs.toString();\n if (s) url = `${path}?${s}`;\n }\n const resp = await this.request(\"GET\", url);\n return (await resp.json()) as Record<string, unknown>;\n }\n\n async postBytes(\n path: string,\n body: Record<string, unknown>,\n ): Promise<Uint8Array> {\n const resp = await this.request(\"POST\", path, {\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(body),\n });\n return new Uint8Array(await resp.arrayBuffer());\n }\n\n async *postStream(\n path: string,\n body: Record<string, unknown>,\n ): AsyncGenerator<Uint8Array, void, unknown> {\n let lastError: unknown;\n for (let attempt = 0; attempt < 3; attempt++) {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.timeout);\n try {\n const response = await fetch(\n `${this.baseUrl}${path.startsWith(\"/\") ? path : `/${path}`}`,\n {\n method: \"POST\",\n headers: {\n ...this.defaultHeaders,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(body),\n signal: controller.signal,\n },\n );\n clearTimeout(timer);\n\n if (!response.ok) {\n await this.raiseForStatus(response);\n }\n if (!response.body) {\n throw new ConnectionError(\"No response body for stream\");\n }\n\n const reader = response.body.getReader();\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n if (value && value.length > 0) {\n yield value;\n }\n }\n } finally {\n reader.releaseLock();\n }\n return;\n } catch (err) {\n clearTimeout(timer);\n if (err instanceof NaijaLingoError) throw err;\n lastError = err;\n const isAbort =\n err instanceof Error &&\n (err.name === \"AbortError\" || err.name === \"TimeoutError\");\n if (isAbort) {\n throw new ConnectionError(`Request timed out: ${String(err)}`);\n }\n if (attempt < 2) {\n await sleep(1500);\n continue;\n }\n }\n }\n throw new ConnectionError(\n `Unable to connect to ${this.baseUrl}: ${String(lastError)}`,\n );\n }\n\n async postMultipart(\n path: string,\n form: FormData,\n timeoutMs?: number,\n ): Promise<Response> {\n return this.request(\"POST\", path, {\n body: form,\n timeoutMs: timeoutMs ?? Math.max(this.timeout, 600_000),\n // Let fetch set multipart boundary — do not set Content-Type\n });\n }\n\n async delete(path: string): Promise<void> {\n await this.request(\"DELETE\", path);\n }\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n","import { mkdir, writeFile } from \"node:fs/promises\";\nimport { basename, dirname } from \"node:path\";\nimport { readFileSync } from \"node:fs\";\nimport { BaseClient } from \"./client.js\";\nimport {\n type HealthStatus,\n type LanguageList,\n type ResponseFormat,\n type Speaker,\n type SpeakerList,\n healthStatusFromDict,\n languageListFromDict,\n speakerFromDict,\n speakerListFromDict,\n} from \"./types.js\";\nimport {\n resolveCloneLangAndSpeaker,\n resolveTtsVoiceAndLang,\n} from \"./voice.js\";\n\nconst DEFAULT_MODEL_NAME = \"9jalingo-tts-1\";\n\nexport type GenerateOptions = {\n voice?: string;\n speaker?: string;\n lang?: string;\n language?: string;\n modelName?: string;\n speakerEmbedding?: number[];\n responseFormat?: ResponseFormat;\n temperature?: number;\n topP?: number;\n repetitionPenalty?: number;\n enableLongForm?: boolean;\n maxChunkDuration?: number;\n silenceDuration?: number;\n};\n\nexport type StreamOptions = Omit<\n GenerateOptions,\n \"modelName\" | \"responseFormat\"\n>;\n\nexport type CloneOptions = {\n voice?: string;\n lang?: string;\n speaker?: string;\n modelName?: string;\n temperature?: number;\n topP?: number;\n repetitionPenalty?: number;\n responseFormat?: ResponseFormat;\n};\n\nexport type ListSpeakersOptions = {\n language?: string;\n gender?: string;\n domain?: string;\n};\n\n/** Audio data returned from a generation request. */\nexport class AudioResponse {\n readonly content: Uint8Array;\n readonly mediaType: string;\n\n constructor(content: Uint8Array, mediaType = \"audio/wav\") {\n this.content = content;\n this.mediaType = mediaType;\n }\n\n /** Write the audio to a file. */\n async save(path: string): Promise<string> {\n await mkdir(dirname(path), { recursive: true });\n await writeFile(path, this.content);\n return path;\n }\n\n get length(): number {\n return this.content.length;\n }\n\n toString(): string {\n return `AudioResponse(${this.content.length} bytes, ${this.mediaType})`;\n }\n}\n\n/** Audio and reusable voice metadata returned from a clone request. */\nexport class CloneResponse extends AudioResponse {\n readonly voiceId: string | null;\n readonly voiceCode: string | null;\n readonly voiceName: string | null;\n readonly cloneId: string | null;\n readonly jobId: string | null;\n\n constructor(\n content: Uint8Array,\n mediaType: string,\n metadata: {\n voiceId: string | null;\n voiceCode: string | null;\n voiceName: string | null;\n cloneId: string | null;\n jobId: string | null;\n },\n ) {\n super(content, mediaType);\n this.voiceId = metadata.voiceId;\n this.voiceCode = metadata.voiceCode;\n this.voiceName = metadata.voiceName;\n this.cloneId = metadata.cloneId;\n this.jobId = metadata.jobId;\n }\n}\n\n/** Streaming audio response — yields byte chunks as they arrive. */\nexport class AudioStream implements AsyncIterable<Uint8Array> {\n private readonly chunks: AsyncIterable<Uint8Array>;\n private collected: Uint8Array | null = null;\n\n constructor(chunks: AsyncIterable<Uint8Array>) {\n this.chunks = chunks;\n }\n\n async *[Symbol.asyncIterator](): AsyncIterator<Uint8Array> {\n for await (const chunk of this.chunks) {\n yield chunk;\n }\n }\n\n /** Consume the entire stream and return an AudioResponse. */\n async collect(): Promise<AudioResponse> {\n if (this.collected == null) {\n const parts: Uint8Array[] = [];\n let total = 0;\n for await (const chunk of this.chunks) {\n parts.push(chunk);\n total += chunk.length;\n }\n const out = new Uint8Array(total);\n let offset = 0;\n for (const part of parts) {\n out.set(part, offset);\n offset += part.length;\n }\n this.collected = out;\n }\n return new AudioResponse(this.collected, \"audio/wav\");\n }\n}\n\nexport class TTS {\n private readonly client: BaseClient;\n\n constructor(client: BaseClient) {\n this.client = client;\n }\n\n /** Generate speech from text. */\n async generate(\n text: string,\n options: GenerateOptions = {},\n ): Promise<AudioResponse> {\n let [resolvedVoice, resolvedLang] = resolveTtsVoiceAndLang(options);\n if (resolvedVoice == null && options.speakerEmbedding == null) {\n resolvedVoice = \"blessing_pcm\";\n }\n const responseFormat = options.responseFormat ?? \"wav\";\n const body = buildBody({\n input: text,\n voice: resolvedVoice,\n lang: resolvedLang,\n model: options.modelName ?? DEFAULT_MODEL_NAME,\n speaker_embedding: options.speakerEmbedding,\n response_format: responseFormat,\n temperature: options.temperature,\n top_p: options.topP,\n repetition_penalty: options.repetitionPenalty,\n enable_long_form: options.enableLongForm ?? true,\n max_chunk_duration: options.maxChunkDuration,\n silence_duration: options.silenceDuration,\n });\n const content = await this.client.postBytes(\"/v1/audio/speech\", body);\n const mediaType = MEDIA_TYPES[responseFormat] ?? \"application/octet-stream\";\n return new AudioResponse(content, mediaType);\n }\n\n /** Stream speech generation — audio arrives as it's produced. */\n stream(text: string, options: StreamOptions = {}): AudioStream {\n let [resolvedVoice, resolvedLang] = resolveTtsVoiceAndLang(options);\n if (resolvedVoice == null && options.speakerEmbedding == null) {\n resolvedVoice = \"blessing_pcm\";\n }\n const body = buildBody({\n input: text,\n voice: resolvedVoice,\n lang: resolvedLang,\n speaker_embedding: options.speakerEmbedding,\n response_format: \"wav\",\n temperature: options.temperature,\n top_p: options.topP,\n repetition_penalty: options.repetitionPenalty,\n enable_long_form: options.enableLongForm ?? true,\n max_chunk_duration: options.maxChunkDuration,\n silence_duration: options.silenceDuration,\n });\n return new AudioStream(this.client.postStream(\"/v1/audio/speech/stream\", body));\n }\n\n /**\n * Generate speech using a cloned voice from a reference audio file.\n * `audioFile` may be a filesystem path, Buffer, Uint8Array, Blob, or File.\n */\n async clone(\n text: string,\n audioFile: string | Buffer | Uint8Array | Blob,\n options: CloneOptions = {},\n ): Promise<CloneResponse> {\n const voice = options.voice ?? \"pcm\";\n const [resolvedLang, resolvedSpeaker] = resolveCloneLangAndSpeaker(\n voice,\n { lang: options.lang, speaker: options.speaker },\n );\n const responseFormat = options.responseFormat ?? \"wav\";\n\n const form = new FormData();\n form.append(\"text\", text);\n form.append(\"lang\", resolvedLang);\n form.append(\"model_name\", options.modelName ?? DEFAULT_MODEL_NAME);\n form.append(\"response_format\", responseFormat);\n if (resolvedSpeaker) {\n form.append(\"voice\", resolvedSpeaker);\n }\n if (options.temperature != null) {\n form.append(\"temperature\", String(options.temperature));\n }\n if (options.topP != null) {\n form.append(\"top_p\", String(options.topP));\n }\n if (options.repetitionPenalty != null) {\n form.append(\"repetition_penalty\", String(options.repetitionPenalty));\n }\n\n const { blob, filename } = await toAudioBlob(audioFile);\n form.append(\"audio\", blob, filename);\n\n const response = await this.client.postMultipart(\"/v1/audio/clone\", form);\n const content = new Uint8Array(await response.arrayBuffer());\n const mediaType = MEDIA_TYPES[responseFormat] ?? \"application/octet-stream\";\n return new CloneResponse(content, mediaType, {\n voiceId: response.headers.get(\"X-Voice-ID\"),\n voiceCode: response.headers.get(\"X-Voice-Code\"),\n voiceName: response.headers.get(\"X-Voice-Name\"),\n cloneId: response.headers.get(\"X-Clone-ID\"),\n jobId: response.headers.get(\"X-Job-ID\"),\n });\n }\n\n async listSpeakers(\n options: ListSpeakersOptions = {},\n ): Promise<SpeakerList> {\n const data = await this.client.getJson(\"/v1/speakers\", {\n language: options.language,\n gender: options.gender,\n domain: options.domain,\n });\n return speakerListFromDict(data);\n }\n\n async getSpeaker(speakerId: string): Promise<Speaker> {\n const data = await this.client.getJson(`/v1/speakers/${speakerId}`);\n return speakerFromDict(data);\n }\n\n /** Permanently delete a cloned voice owned by this API key. */\n async deleteVoice(voiceId: string): Promise<void> {\n const normalizedVoiceId = voiceId.trim();\n if (!normalizedVoiceId) {\n throw new Error(\"voiceId is required\");\n }\n await this.client.delete(`/v1/voices/${encodeURIComponent(normalizedVoiceId)}`);\n }\n\n async listLanguages(): Promise<LanguageList> {\n const data = await this.client.getJson(\"/v1/languages\");\n return languageListFromDict(data);\n }\n\n async health(): Promise<HealthStatus> {\n const data = await this.client.getJson(\"/v1/health\");\n return healthStatusFromDict(data);\n }\n}\n\nconst MEDIA_TYPES: Record<string, string> = {\n wav: \"audio/wav\",\n pcm: \"application/octet-stream\",\n flac: \"audio/flac\",\n aac: \"audio/aac\",\n ogg: \"audio/ogg\",\n mp3: \"audio/mpeg\",\n alac: \"audio/alac\",\n};\n\nfunction buildBody(\n kwargs: Record<string, unknown>,\n): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(kwargs)) {\n if (v !== undefined && v !== null) out[k] = v;\n }\n return out;\n}\n\nasync function toAudioBlob(\n audioFile: string | Buffer | Uint8Array | Blob,\n): Promise<{ blob: Blob; filename: string }> {\n if (typeof audioFile === \"string\") {\n const bytes = readFileSync(audioFile);\n const filename = basename(audioFile);\n const mime = guessMime(filename);\n return {\n blob: new Blob([bytes], { type: mime }),\n filename,\n };\n }\n if (audioFile instanceof Blob) {\n return {\n blob: audioFile,\n filename: \"audio.wav\",\n };\n }\n // Buffer | Uint8Array\n const bytes =\n audioFile instanceof Uint8Array\n ? audioFile\n : new Uint8Array(audioFile);\n return {\n blob: new Blob([bytes], { type: \"application/octet-stream\" }),\n filename: \"audio.wav\",\n };\n}\n\nfunction guessMime(filename: string): string {\n const lower = filename.toLowerCase();\n if (lower.endsWith(\".wav\")) return \"audio/wav\";\n if (lower.endsWith(\".mp3\")) return \"audio/mpeg\";\n if (lower.endsWith(\".flac\")) return \"audio/flac\";\n if (lower.endsWith(\".ogg\")) return \"audio/ogg\";\n if (lower.endsWith(\".aac\") || lower.endsWith(\".m4a\")) return \"audio/aac\";\n return \"application/octet-stream\";\n}\n","/** A speaker voice identity. */\nexport interface Speaker {\n id: string;\n name: string;\n language: string;\n gender?: string | null;\n domain?: string | null;\n}\n\nexport function speakerFromDict(data: Record<string, unknown>): Speaker {\n return {\n id: String(data.id ?? data.speaker_id ?? \"\"),\n name: String(data.name ?? data.id ?? \"\"),\n language: String(data.language ?? \"\"),\n gender: (data.gender as string | null | undefined) ?? null,\n domain: (data.domain as string | null | undefined) ?? null,\n };\n}\n\n/** List of speakers with metadata. */\nexport interface SpeakerList {\n speakers: Speaker[];\n total: number;\n byLanguage: Record<string, number>;\n [Symbol.iterator](): Iterator<Speaker>;\n length: number;\n}\n\nexport function speakerListFromDict(data: Record<string, unknown>): SpeakerList {\n const raw = (data.speakers as Record<string, unknown>[] | undefined) ?? [];\n const speakers = raw.map(speakerFromDict);\n const total = typeof data.total === \"number\" ? data.total : speakers.length;\n const byLanguage =\n (data.by_language as Record<string, number> | undefined) ?? {};\n return {\n speakers,\n total,\n byLanguage,\n get length() {\n return total;\n },\n [Symbol.iterator]() {\n return speakers[Symbol.iterator]();\n },\n };\n}\n\n/** A supported language. */\nexport interface Language {\n code: string;\n name: string;\n speakerCount: number;\n}\n\nexport function languageFromDict(data: Record<string, unknown>): Language {\n return {\n code: String(data.code ?? \"\"),\n name: String(data.name ?? \"\"),\n speakerCount: Number(data.speaker_count ?? 0),\n };\n}\n\n/** List of supported languages and domains. */\nexport interface LanguageList {\n languages: Language[];\n domains: string[];\n}\n\nexport function languageListFromDict(data: Record<string, unknown>): LanguageList {\n const rawLangs = data.languages;\n let languages: Language[];\n\n if (rawLangs && typeof rawLangs === \"object\" && !Array.isArray(rawLangs)) {\n languages = Object.entries(rawLangs as Record<string, unknown>).map(\n ([code, value]) => {\n if (value && typeof value === \"object\") {\n const v = value as Record<string, unknown>;\n return {\n code,\n name: String(v.name ?? code),\n speakerCount: Number(v.speaker_count ?? 0),\n };\n }\n return { code, name: String(value), speakerCount: 0 };\n },\n );\n } else {\n const arr = (rawLangs as Record<string, unknown>[] | undefined) ?? [];\n languages = arr.map(languageFromDict);\n }\n\n return {\n languages,\n domains: (data.domains as string[] | undefined) ?? [],\n };\n}\n\n/** API health check result. */\nexport interface HealthStatus {\n status: string;\n engineReady: boolean;\n codecReady: boolean;\n totalSpeakers: number;\n languages: string[];\n voiceCloningAvailable: boolean;\n speakerProjectionLoaded: boolean;\n}\n\nexport function healthStatusFromDict(data: Record<string, unknown>): HealthStatus {\n const supported = data.supported_languages;\n let languages: string[] = [];\n if (Array.isArray(data.languages)) {\n languages = data.languages as string[];\n } else if (supported && typeof supported === \"object\") {\n languages = Object.keys(supported as Record<string, unknown>);\n }\n\n return {\n status: String(data.status ?? \"unknown\"),\n engineReady: Boolean(data.engine_ready ?? data.tts_initialized ?? false),\n codecReady: Boolean(data.codec_ready ?? false),\n totalSpeakers: Number(data.total_speakers ?? data.speakers_loaded ?? 0),\n languages,\n voiceCloningAvailable: Boolean(data.voice_cloning_available ?? false),\n speakerProjectionLoaded: Boolean(data.speaker_projection_loaded ?? false),\n };\n}\n\n/** An available TTS model. */\nexport interface Model {\n id: string;\n object: string;\n ownedBy: string;\n}\n\nexport function modelFromDict(data: Record<string, unknown>): Model {\n return {\n id: String(data.id ?? \"\"),\n object: String(data.object ?? \"model\"),\n ownedBy: String(data.owned_by ?? \"9jalingo\"),\n };\n}\n\n/** List of available models. */\nexport interface ModelList {\n models: Model[];\n object: string;\n [Symbol.iterator](): Iterator<Model>;\n length: number;\n}\n\nexport function modelListFromDict(data: Record<string, unknown>): ModelList {\n const raw = (data.data as Record<string, unknown>[] | undefined) ?? [];\n const models = raw.map(modelFromDict);\n return {\n models,\n object: String(data.object ?? \"list\"),\n get length() {\n return models.length;\n },\n [Symbol.iterator]() {\n return models[Symbol.iterator]();\n },\n };\n}\n\n/** Root API information returned by GET /. */\nexport interface APIInfo {\n name: string;\n version: string;\n description: string;\n endpoints: Record<string, string>;\n}\n\nexport function apiInfoFromDict(data: Record<string, unknown>): APIInfo {\n return {\n name: String(data.name ?? \"\"),\n version: String(data.version ?? \"\"),\n description: String(data.description ?? \"\"),\n endpoints: (data.endpoints as Record<string, string> | undefined) ?? {},\n };\n}\n\n/** Service metadata returned by GET /v1. */\nexport interface ServiceInfo {\n object: string;\n name: string;\n modelsUrl: string;\n speechUrl: string;\n speechStreamUrl: string;\n}\n\nexport function serviceInfoFromDict(data: Record<string, unknown>): ServiceInfo {\n return {\n object: String(data.object ?? \"service\"),\n name: String(data.name ?? \"\"),\n modelsUrl: String(data.models_url ?? \"\"),\n speechUrl: String(data.speech_url ?? \"\"),\n speechStreamUrl: String(data.speech_stream_url ?? \"\"),\n };\n}\n\nexport type ResponseFormat =\n | \"wav\"\n | \"pcm\"\n | \"flac\"\n | \"aac\"\n | \"ogg\"\n | \"mp3\"\n | \"alac\";\n","const LANG_ALIASES: Record<string, string> = {\n yo: \"yo\",\n yor: \"yo\",\n yoruba: \"yo\",\n ig: \"ig\",\n ibo: \"ig\",\n igbo: \"ig\",\n ha: \"ha\",\n hau: \"ha\",\n hausa: \"ha\",\n pcm: \"pcm\",\n pidgin: \"pcm\",\n};\n\nexport function normalizeLang(code: string): string | null {\n return LANG_ALIASES[code.trim().toLowerCase()] ?? null;\n}\n\n/**\n * Resolve speech API fields: voice/speaker + lang/language.\n * Returns [speakerId, langCode]. Bare language codes must be passed via lang/language.\n */\nexport function resolveTtsVoiceAndLang(options: {\n voice?: string | null;\n speaker?: string | null;\n lang?: string | null;\n language?: string | null;\n}): [string | null, string | null] {\n let resolvedLang: string | null = null;\n\n if (options.lang != null) {\n resolvedLang = normalizeLang(options.lang);\n if (resolvedLang == null) {\n throw new Error(\n `Unsupported language '${options.lang}'. Use ha, ig, yo, or pcm.`,\n );\n }\n } else if (options.language != null) {\n resolvedLang = normalizeLang(options.language);\n if (resolvedLang == null) {\n throw new Error(\n `Unsupported language '${options.language}'. Use ha, ig, yo, or pcm.`,\n );\n }\n }\n\n // speaker takes precedence over voice\n const candidate =\n options.speaker != null ? options.speaker : options.voice;\n if (candidate == null || !String(candidate).trim()) {\n return [null, resolvedLang];\n }\n\n const resolved = String(candidate).trim();\n const normalized = resolved.toLowerCase();\n if (normalized in LANG_ALIASES) {\n const langCode = LANG_ALIASES[normalized];\n throw new Error(\n `'${resolved}' is a language code, not a speaker ID. ` +\n `Pass speaker/voice='ada_pcm' (or another speaker ID) and ` +\n `lang='${langCode}' for the language. ` +\n `Browse speakers with: client.tts.listSpeakers({ language: '${langCode}' })`,\n );\n }\n\n if (resolvedLang == null && resolved.includes(\"_\")) {\n const suffix = resolved.split(\"_\").pop()!;\n resolvedLang = normalizeLang(suffix);\n }\n\n return [resolved, resolvedLang];\n}\n\n/**\n * Resolve clone form fields.\n * voice may be a language code (\"pcm\") or a speaker ID with a language suffix.\n */\nexport function resolveCloneLangAndSpeaker(\n voice: string,\n options: { lang?: string | null; speaker?: string | null } = {},\n): [string, string | null] {\n let resolvedLang =\n options.lang != null ? normalizeLang(options.lang) : null;\n let resolvedSpeaker = options.speaker?.trim() || null;\n\n const voiceStr = (voice || \"\").trim();\n const voiceNorm = voiceStr.toLowerCase();\n\n if (voiceNorm in LANG_ALIASES) {\n if (resolvedLang == null) {\n resolvedLang = LANG_ALIASES[voiceNorm];\n }\n } else if (voiceStr.includes(\"_\")) {\n if (resolvedSpeaker == null) {\n resolvedSpeaker = voiceStr;\n }\n if (resolvedLang == null) {\n const suffix = voiceStr.split(\"_\").pop()!;\n resolvedLang = normalizeLang(suffix);\n }\n } else if (voiceStr && resolvedLang == null) {\n throw new Error(\n `'${voice}' is not a language code (ha/ig/yo/pcm) or a speaker ID ` +\n `with a language suffix (e.g. 'daniel_pcm'). ` +\n `Pass voice='pcm' or lang='pcm'.`,\n );\n }\n\n if (!resolvedLang) {\n throw new Error(\n \"Clone requires a language. Pass voice='pcm' (or 'ha'/'ig'/'yo'), \" +\n \"lang='pcm', or a speaker ID ending in _pcm/_ha/_ig/_yo.\",\n );\n }\n\n return [resolvedLang, resolvedSpeaker];\n}\n"],"mappings":"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","names":["bytes"]}
package/dist/index.d.cts CHANGED
@@ -16,6 +16,7 @@ declare class BaseClient {
16
16
  postBytes(path: string, body: Record<string, unknown>): Promise<Uint8Array>;
17
17
  postStream(path: string, body: Record<string, unknown>): AsyncGenerator<Uint8Array, void, unknown>;
18
18
  postMultipart(path: string, form: FormData, timeoutMs?: number): Promise<Response>;
19
+ delete(path: string): Promise<void>;
19
20
  }
20
21
 
21
22
  /** A speaker voice identity. */
@@ -164,6 +165,8 @@ declare class TTS {
164
165
  clone(text: string, audioFile: string | Buffer | Uint8Array | Blob, options?: CloneOptions): Promise<CloneResponse>;
165
166
  listSpeakers(options?: ListSpeakersOptions): Promise<SpeakerList>;
166
167
  getSpeaker(speakerId: string): Promise<Speaker>;
168
+ /** Permanently delete a cloned voice owned by this API key. */
169
+ deleteVoice(voiceId: string): Promise<void>;
167
170
  listLanguages(): Promise<LanguageList>;
168
171
  health(): Promise<HealthStatus>;
169
172
  }
package/dist/index.d.ts CHANGED
@@ -16,6 +16,7 @@ declare class BaseClient {
16
16
  postBytes(path: string, body: Record<string, unknown>): Promise<Uint8Array>;
17
17
  postStream(path: string, body: Record<string, unknown>): AsyncGenerator<Uint8Array, void, unknown>;
18
18
  postMultipart(path: string, form: FormData, timeoutMs?: number): Promise<Response>;
19
+ delete(path: string): Promise<void>;
19
20
  }
20
21
 
21
22
  /** A speaker voice identity. */
@@ -164,6 +165,8 @@ declare class TTS {
164
165
  clone(text: string, audioFile: string | Buffer | Uint8Array | Blob, options?: CloneOptions): Promise<CloneResponse>;
165
166
  listSpeakers(options?: ListSpeakersOptions): Promise<SpeakerList>;
166
167
  getSpeaker(speakerId: string): Promise<Speaker>;
168
+ /** Permanently delete a cloned voice owned by this API key. */
169
+ deleteVoice(voiceId: string): Promise<void>;
167
170
  listLanguages(): Promise<LanguageList>;
168
171
  health(): Promise<HealthStatus>;
169
172
  }
package/dist/index.js CHANGED
@@ -222,6 +222,9 @@ var BaseClient = class {
222
222
  // Let fetch set multipart boundary — do not set Content-Type
223
223
  });
224
224
  }
225
+ async delete(path) {
226
+ await this.request("DELETE", path);
227
+ }
225
228
  };
226
229
  function sleep(ms) {
227
230
  return new Promise((resolve) => setTimeout(resolve, ms));
@@ -603,6 +606,14 @@ var TTS = class {
603
606
  const data = await this.client.getJson(`/v1/speakers/${speakerId}`);
604
607
  return speakerFromDict(data);
605
608
  }
609
+ /** Permanently delete a cloned voice owned by this API key. */
610
+ async deleteVoice(voiceId) {
611
+ const normalizedVoiceId = voiceId.trim();
612
+ if (!normalizedVoiceId) {
613
+ throw new Error("voiceId is required");
614
+ }
615
+ await this.client.delete(`/v1/voices/${encodeURIComponent(normalizedVoiceId)}`);
616
+ }
606
617
  async listLanguages() {
607
618
  const data = await this.client.getJson("/v1/languages");
608
619
  return languageListFromDict(data);
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/errors.ts","../src/client.ts","../src/tts.ts","../src/types.ts","../src/voice.ts","../src/index.ts"],"sourcesContent":["/** Base exception for all 9jaLingo SDK errors. */\nexport class NaijaLingoError extends Error {\n readonly statusCode?: number;\n readonly response?: unknown;\n\n constructor(message: string, statusCode?: number, response?: unknown) {\n super(message);\n this.name = \"NaijaLingoError\";\n this.statusCode = statusCode;\n this.response = response;\n }\n}\n\n/** Raised when the API key is missing or invalid. */\nexport class AuthenticationError extends NaijaLingoError {\n constructor(message: string, statusCode?: number, response?: unknown) {\n super(message, statusCode, response);\n this.name = \"AuthenticationError\";\n }\n}\n\n/** Raised when rate limit is exceeded. */\nexport class RateLimitError extends NaijaLingoError {\n constructor(message: string, statusCode?: number, response?: unknown) {\n super(message, statusCode, response);\n this.name = \"RateLimitError\";\n }\n}\n\n/** Raised when a requested resource is not found. */\nexport class NotFoundError extends NaijaLingoError {\n constructor(message: string, statusCode?: number, response?: unknown) {\n super(message, statusCode, response);\n this.name = \"NotFoundError\";\n }\n}\n\n/** Raised when the API returns a 5xx error. */\nexport class ServerError extends NaijaLingoError {\n constructor(message: string, statusCode?: number, response?: unknown) {\n super(message, statusCode, response);\n this.name = \"ServerError\";\n }\n}\n\n/** Raised when the inference GPU is waking from scale-to-zero. */\nexport class InferenceCapacityError extends ServerError {\n constructor(message: string, statusCode?: number, response?: unknown) {\n super(message, statusCode, response);\n this.name = \"InferenceCapacityError\";\n }\n}\n\n/** Raised when unable to connect to the API. */\nexport class ConnectionError extends NaijaLingoError {\n constructor(message: string, statusCode?: number, response?: unknown) {\n super(message, statusCode, response);\n this.name = \"ConnectionError\";\n }\n}\n","import {\n AuthenticationError,\n ConnectionError,\n InferenceCapacityError,\n NaijaLingoError,\n NotFoundError,\n RateLimitError,\n ServerError,\n} from \"./errors.js\";\n\nconst DEFAULT_BASE_URL = \"https://api.9jalingo.org\";\nconst DEFAULT_TIMEOUT_MS = 300_000;\n\nexport interface ClientOptions {\n apiKey?: string;\n baseUrl?: string;\n /** Request timeout in milliseconds (default 300000). */\n timeout?: number;\n}\n\nexport class BaseClient {\n readonly apiKey: string;\n readonly baseUrl: string;\n readonly timeout: number;\n private readonly defaultHeaders: Record<string, string>;\n\n constructor(options: ClientOptions = {}) {\n this.apiKey =\n options.apiKey ?? process.env.NAIJALINGO_API_KEY ?? \"\";\n const base =\n options.baseUrl ??\n process.env.NAIJALINGO_BASE_URL ??\n DEFAULT_BASE_URL;\n this.baseUrl = base.replace(/\\/+$/, \"\");\n this.timeout = options.timeout ?? DEFAULT_TIMEOUT_MS;\n\n this.defaultHeaders = {\n \"User-Agent\": \"naijalingo-js/0.1.2\",\n };\n if (this.apiKey) {\n this.defaultHeaders[\"X-API-Key\"] = this.apiKey;\n }\n }\n\n private async request(\n method: string,\n path: string,\n init: RequestInit & { timeoutMs?: number } = {},\n ): Promise<Response> {\n const url = `${this.baseUrl}${path.startsWith(\"/\") ? path : `/${path}`}`;\n const timeoutMs = init.timeoutMs ?? this.timeout;\n let lastError: unknown;\n\n for (let attempt = 0; attempt < 3; attempt++) {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeoutMs);\n try {\n const response = await fetch(url, {\n ...init,\n method,\n headers: {\n ...this.defaultHeaders,\n ...(init.headers as Record<string, string> | undefined),\n },\n signal: controller.signal,\n });\n clearTimeout(timer);\n\n if (response.ok) {\n return response;\n }\n await this.raiseForStatus(response);\n // unreachable\n return response;\n } catch (err) {\n clearTimeout(timer);\n if (err instanceof NaijaLingoError) {\n throw err;\n }\n lastError = err;\n const isAbort =\n err instanceof Error &&\n (err.name === \"AbortError\" || err.name === \"TimeoutError\");\n // Only retry connect-style failures, not aborts from long reads\n if (isAbort) {\n throw new ConnectionError(\n `Request timed out after ${timeoutMs}ms: ${String(err)}`,\n );\n }\n if (attempt < 2) {\n await sleep(1500);\n continue;\n }\n }\n }\n\n throw new ConnectionError(\n `Unable to connect to ${this.baseUrl}: ${String(lastError)}`,\n );\n }\n\n private async raiseForStatus(response: Response): Promise<never> {\n const status = response.status;\n let detail: string;\n let body: unknown;\n try {\n body = await response.json();\n detail =\n typeof body === \"object\" &&\n body !== null &&\n \"detail\" in body\n ? String((body as { detail: unknown }).detail)\n : JSON.stringify(body);\n } catch {\n detail = await response.text();\n }\n\n const normalizedDetail = detail.toLowerCase();\n if (status === 503 && (\n normalizedDetail.includes(\"inference capacity\")\n || normalizedDetail.includes(\"inference component has no capacity\")\n || normalizedDetail.includes(\"capacity is starting\")\n )) {\n throw new InferenceCapacityError(detail, status, body);\n }\n if (status === 401 || status === 403) {\n throw new AuthenticationError(detail, status, body);\n }\n if (status === 404) {\n throw new NotFoundError(detail, status, body);\n }\n if (status === 429) {\n throw new RateLimitError(detail, status, body);\n }\n if (status >= 500) {\n throw new ServerError(detail, status, body);\n }\n throw new NaijaLingoError(detail, status, body);\n }\n\n async getJson(\n path: string,\n params?: Record<string, string | undefined | null>,\n ): Promise<Record<string, unknown>> {\n let url = path;\n if (params) {\n const qs = new URLSearchParams();\n for (const [k, v] of Object.entries(params)) {\n if (v != null) qs.set(k, v);\n }\n const s = qs.toString();\n if (s) url = `${path}?${s}`;\n }\n const resp = await this.request(\"GET\", url);\n return (await resp.json()) as Record<string, unknown>;\n }\n\n async postBytes(\n path: string,\n body: Record<string, unknown>,\n ): Promise<Uint8Array> {\n const resp = await this.request(\"POST\", path, {\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(body),\n });\n return new Uint8Array(await resp.arrayBuffer());\n }\n\n async *postStream(\n path: string,\n body: Record<string, unknown>,\n ): AsyncGenerator<Uint8Array, void, unknown> {\n let lastError: unknown;\n for (let attempt = 0; attempt < 3; attempt++) {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.timeout);\n try {\n const response = await fetch(\n `${this.baseUrl}${path.startsWith(\"/\") ? path : `/${path}`}`,\n {\n method: \"POST\",\n headers: {\n ...this.defaultHeaders,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(body),\n signal: controller.signal,\n },\n );\n clearTimeout(timer);\n\n if (!response.ok) {\n await this.raiseForStatus(response);\n }\n if (!response.body) {\n throw new ConnectionError(\"No response body for stream\");\n }\n\n const reader = response.body.getReader();\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n if (value && value.length > 0) {\n yield value;\n }\n }\n } finally {\n reader.releaseLock();\n }\n return;\n } catch (err) {\n clearTimeout(timer);\n if (err instanceof NaijaLingoError) throw err;\n lastError = err;\n const isAbort =\n err instanceof Error &&\n (err.name === \"AbortError\" || err.name === \"TimeoutError\");\n if (isAbort) {\n throw new ConnectionError(`Request timed out: ${String(err)}`);\n }\n if (attempt < 2) {\n await sleep(1500);\n continue;\n }\n }\n }\n throw new ConnectionError(\n `Unable to connect to ${this.baseUrl}: ${String(lastError)}`,\n );\n }\n\n async postMultipart(\n path: string,\n form: FormData,\n timeoutMs?: number,\n ): Promise<Response> {\n return this.request(\"POST\", path, {\n body: form,\n timeoutMs: timeoutMs ?? Math.max(this.timeout, 600_000),\n // Let fetch set multipart boundary — do not set Content-Type\n });\n }\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n","import { mkdir, writeFile } from \"node:fs/promises\";\nimport { basename, dirname } from \"node:path\";\nimport { readFileSync } from \"node:fs\";\nimport { BaseClient } from \"./client.js\";\nimport {\n type HealthStatus,\n type LanguageList,\n type ResponseFormat,\n type Speaker,\n type SpeakerList,\n healthStatusFromDict,\n languageListFromDict,\n speakerFromDict,\n speakerListFromDict,\n} from \"./types.js\";\nimport {\n resolveCloneLangAndSpeaker,\n resolveTtsVoiceAndLang,\n} from \"./voice.js\";\n\nconst DEFAULT_MODEL_NAME = \"9jalingo-tts-1\";\n\nexport type GenerateOptions = {\n voice?: string;\n speaker?: string;\n lang?: string;\n language?: string;\n modelName?: string;\n speakerEmbedding?: number[];\n responseFormat?: ResponseFormat;\n temperature?: number;\n topP?: number;\n repetitionPenalty?: number;\n enableLongForm?: boolean;\n maxChunkDuration?: number;\n silenceDuration?: number;\n};\n\nexport type StreamOptions = Omit<\n GenerateOptions,\n \"modelName\" | \"responseFormat\"\n>;\n\nexport type CloneOptions = {\n voice?: string;\n lang?: string;\n speaker?: string;\n modelName?: string;\n temperature?: number;\n topP?: number;\n repetitionPenalty?: number;\n responseFormat?: ResponseFormat;\n};\n\nexport type ListSpeakersOptions = {\n language?: string;\n gender?: string;\n domain?: string;\n};\n\n/** Audio data returned from a generation request. */\nexport class AudioResponse {\n readonly content: Uint8Array;\n readonly mediaType: string;\n\n constructor(content: Uint8Array, mediaType = \"audio/wav\") {\n this.content = content;\n this.mediaType = mediaType;\n }\n\n /** Write the audio to a file. */\n async save(path: string): Promise<string> {\n await mkdir(dirname(path), { recursive: true });\n await writeFile(path, this.content);\n return path;\n }\n\n get length(): number {\n return this.content.length;\n }\n\n toString(): string {\n return `AudioResponse(${this.content.length} bytes, ${this.mediaType})`;\n }\n}\n\n/** Audio and reusable voice metadata returned from a clone request. */\nexport class CloneResponse extends AudioResponse {\n readonly voiceId: string | null;\n readonly voiceCode: string | null;\n readonly voiceName: string | null;\n readonly cloneId: string | null;\n readonly jobId: string | null;\n\n constructor(\n content: Uint8Array,\n mediaType: string,\n metadata: {\n voiceId: string | null;\n voiceCode: string | null;\n voiceName: string | null;\n cloneId: string | null;\n jobId: string | null;\n },\n ) {\n super(content, mediaType);\n this.voiceId = metadata.voiceId;\n this.voiceCode = metadata.voiceCode;\n this.voiceName = metadata.voiceName;\n this.cloneId = metadata.cloneId;\n this.jobId = metadata.jobId;\n }\n}\n\n/** Streaming audio response — yields byte chunks as they arrive. */\nexport class AudioStream implements AsyncIterable<Uint8Array> {\n private readonly chunks: AsyncIterable<Uint8Array>;\n private collected: Uint8Array | null = null;\n\n constructor(chunks: AsyncIterable<Uint8Array>) {\n this.chunks = chunks;\n }\n\n async *[Symbol.asyncIterator](): AsyncIterator<Uint8Array> {\n for await (const chunk of this.chunks) {\n yield chunk;\n }\n }\n\n /** Consume the entire stream and return an AudioResponse. */\n async collect(): Promise<AudioResponse> {\n if (this.collected == null) {\n const parts: Uint8Array[] = [];\n let total = 0;\n for await (const chunk of this.chunks) {\n parts.push(chunk);\n total += chunk.length;\n }\n const out = new Uint8Array(total);\n let offset = 0;\n for (const part of parts) {\n out.set(part, offset);\n offset += part.length;\n }\n this.collected = out;\n }\n return new AudioResponse(this.collected, \"audio/wav\");\n }\n}\n\nexport class TTS {\n private readonly client: BaseClient;\n\n constructor(client: BaseClient) {\n this.client = client;\n }\n\n /** Generate speech from text. */\n async generate(\n text: string,\n options: GenerateOptions = {},\n ): Promise<AudioResponse> {\n let [resolvedVoice, resolvedLang] = resolveTtsVoiceAndLang(options);\n if (resolvedVoice == null && options.speakerEmbedding == null) {\n resolvedVoice = \"blessing_pcm\";\n }\n const responseFormat = options.responseFormat ?? \"wav\";\n const body = buildBody({\n input: text,\n voice: resolvedVoice,\n lang: resolvedLang,\n model: options.modelName ?? DEFAULT_MODEL_NAME,\n speaker_embedding: options.speakerEmbedding,\n response_format: responseFormat,\n temperature: options.temperature,\n top_p: options.topP,\n repetition_penalty: options.repetitionPenalty,\n enable_long_form: options.enableLongForm ?? true,\n max_chunk_duration: options.maxChunkDuration,\n silence_duration: options.silenceDuration,\n });\n const content = await this.client.postBytes(\"/v1/audio/speech\", body);\n const mediaType = MEDIA_TYPES[responseFormat] ?? \"application/octet-stream\";\n return new AudioResponse(content, mediaType);\n }\n\n /** Stream speech generation — audio arrives as it's produced. */\n stream(text: string, options: StreamOptions = {}): AudioStream {\n let [resolvedVoice, resolvedLang] = resolveTtsVoiceAndLang(options);\n if (resolvedVoice == null && options.speakerEmbedding == null) {\n resolvedVoice = \"blessing_pcm\";\n }\n const body = buildBody({\n input: text,\n voice: resolvedVoice,\n lang: resolvedLang,\n speaker_embedding: options.speakerEmbedding,\n response_format: \"wav\",\n temperature: options.temperature,\n top_p: options.topP,\n repetition_penalty: options.repetitionPenalty,\n enable_long_form: options.enableLongForm ?? true,\n max_chunk_duration: options.maxChunkDuration,\n silence_duration: options.silenceDuration,\n });\n return new AudioStream(this.client.postStream(\"/v1/audio/speech/stream\", body));\n }\n\n /**\n * Generate speech using a cloned voice from a reference audio file.\n * `audioFile` may be a filesystem path, Buffer, Uint8Array, Blob, or File.\n */\n async clone(\n text: string,\n audioFile: string | Buffer | Uint8Array | Blob,\n options: CloneOptions = {},\n ): Promise<CloneResponse> {\n const voice = options.voice ?? \"pcm\";\n const [resolvedLang, resolvedSpeaker] = resolveCloneLangAndSpeaker(\n voice,\n { lang: options.lang, speaker: options.speaker },\n );\n const responseFormat = options.responseFormat ?? \"wav\";\n\n const form = new FormData();\n form.append(\"text\", text);\n form.append(\"lang\", resolvedLang);\n form.append(\"model_name\", options.modelName ?? DEFAULT_MODEL_NAME);\n form.append(\"response_format\", responseFormat);\n if (resolvedSpeaker) {\n form.append(\"voice\", resolvedSpeaker);\n }\n if (options.temperature != null) {\n form.append(\"temperature\", String(options.temperature));\n }\n if (options.topP != null) {\n form.append(\"top_p\", String(options.topP));\n }\n if (options.repetitionPenalty != null) {\n form.append(\"repetition_penalty\", String(options.repetitionPenalty));\n }\n\n const { blob, filename } = await toAudioBlob(audioFile);\n form.append(\"audio\", blob, filename);\n\n const response = await this.client.postMultipart(\"/v1/audio/clone\", form);\n const content = new Uint8Array(await response.arrayBuffer());\n const mediaType = MEDIA_TYPES[responseFormat] ?? \"application/octet-stream\";\n return new CloneResponse(content, mediaType, {\n voiceId: response.headers.get(\"X-Voice-ID\"),\n voiceCode: response.headers.get(\"X-Voice-Code\"),\n voiceName: response.headers.get(\"X-Voice-Name\"),\n cloneId: response.headers.get(\"X-Clone-ID\"),\n jobId: response.headers.get(\"X-Job-ID\"),\n });\n }\n\n async listSpeakers(\n options: ListSpeakersOptions = {},\n ): Promise<SpeakerList> {\n const data = await this.client.getJson(\"/v1/speakers\", {\n language: options.language,\n gender: options.gender,\n domain: options.domain,\n });\n return speakerListFromDict(data);\n }\n\n async getSpeaker(speakerId: string): Promise<Speaker> {\n const data = await this.client.getJson(`/v1/speakers/${speakerId}`);\n return speakerFromDict(data);\n }\n\n async listLanguages(): Promise<LanguageList> {\n const data = await this.client.getJson(\"/v1/languages\");\n return languageListFromDict(data);\n }\n\n async health(): Promise<HealthStatus> {\n const data = await this.client.getJson(\"/v1/health\");\n return healthStatusFromDict(data);\n }\n}\n\nconst MEDIA_TYPES: Record<string, string> = {\n wav: \"audio/wav\",\n pcm: \"application/octet-stream\",\n flac: \"audio/flac\",\n aac: \"audio/aac\",\n ogg: \"audio/ogg\",\n mp3: \"audio/mpeg\",\n alac: \"audio/alac\",\n};\n\nfunction buildBody(\n kwargs: Record<string, unknown>,\n): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(kwargs)) {\n if (v !== undefined && v !== null) out[k] = v;\n }\n return out;\n}\n\nasync function toAudioBlob(\n audioFile: string | Buffer | Uint8Array | Blob,\n): Promise<{ blob: Blob; filename: string }> {\n if (typeof audioFile === \"string\") {\n const bytes = readFileSync(audioFile);\n const filename = basename(audioFile);\n const mime = guessMime(filename);\n return {\n blob: new Blob([bytes], { type: mime }),\n filename,\n };\n }\n if (audioFile instanceof Blob) {\n return {\n blob: audioFile,\n filename: \"audio.wav\",\n };\n }\n // Buffer | Uint8Array\n const bytes =\n audioFile instanceof Uint8Array\n ? audioFile\n : new Uint8Array(audioFile);\n return {\n blob: new Blob([bytes], { type: \"application/octet-stream\" }),\n filename: \"audio.wav\",\n };\n}\n\nfunction guessMime(filename: string): string {\n const lower = filename.toLowerCase();\n if (lower.endsWith(\".wav\")) return \"audio/wav\";\n if (lower.endsWith(\".mp3\")) return \"audio/mpeg\";\n if (lower.endsWith(\".flac\")) return \"audio/flac\";\n if (lower.endsWith(\".ogg\")) return \"audio/ogg\";\n if (lower.endsWith(\".aac\") || lower.endsWith(\".m4a\")) return \"audio/aac\";\n return \"application/octet-stream\";\n}\n","/** A speaker voice identity. */\nexport interface Speaker {\n id: string;\n name: string;\n language: string;\n gender?: string | null;\n domain?: string | null;\n}\n\nexport function speakerFromDict(data: Record<string, unknown>): Speaker {\n return {\n id: String(data.id ?? data.speaker_id ?? \"\"),\n name: String(data.name ?? data.id ?? \"\"),\n language: String(data.language ?? \"\"),\n gender: (data.gender as string | null | undefined) ?? null,\n domain: (data.domain as string | null | undefined) ?? null,\n };\n}\n\n/** List of speakers with metadata. */\nexport interface SpeakerList {\n speakers: Speaker[];\n total: number;\n byLanguage: Record<string, number>;\n [Symbol.iterator](): Iterator<Speaker>;\n length: number;\n}\n\nexport function speakerListFromDict(data: Record<string, unknown>): SpeakerList {\n const raw = (data.speakers as Record<string, unknown>[] | undefined) ?? [];\n const speakers = raw.map(speakerFromDict);\n const total = typeof data.total === \"number\" ? data.total : speakers.length;\n const byLanguage =\n (data.by_language as Record<string, number> | undefined) ?? {};\n return {\n speakers,\n total,\n byLanguage,\n get length() {\n return total;\n },\n [Symbol.iterator]() {\n return speakers[Symbol.iterator]();\n },\n };\n}\n\n/** A supported language. */\nexport interface Language {\n code: string;\n name: string;\n speakerCount: number;\n}\n\nexport function languageFromDict(data: Record<string, unknown>): Language {\n return {\n code: String(data.code ?? \"\"),\n name: String(data.name ?? \"\"),\n speakerCount: Number(data.speaker_count ?? 0),\n };\n}\n\n/** List of supported languages and domains. */\nexport interface LanguageList {\n languages: Language[];\n domains: string[];\n}\n\nexport function languageListFromDict(data: Record<string, unknown>): LanguageList {\n const rawLangs = data.languages;\n let languages: Language[];\n\n if (rawLangs && typeof rawLangs === \"object\" && !Array.isArray(rawLangs)) {\n languages = Object.entries(rawLangs as Record<string, unknown>).map(\n ([code, value]) => {\n if (value && typeof value === \"object\") {\n const v = value as Record<string, unknown>;\n return {\n code,\n name: String(v.name ?? code),\n speakerCount: Number(v.speaker_count ?? 0),\n };\n }\n return { code, name: String(value), speakerCount: 0 };\n },\n );\n } else {\n const arr = (rawLangs as Record<string, unknown>[] | undefined) ?? [];\n languages = arr.map(languageFromDict);\n }\n\n return {\n languages,\n domains: (data.domains as string[] | undefined) ?? [],\n };\n}\n\n/** API health check result. */\nexport interface HealthStatus {\n status: string;\n engineReady: boolean;\n codecReady: boolean;\n totalSpeakers: number;\n languages: string[];\n voiceCloningAvailable: boolean;\n speakerProjectionLoaded: boolean;\n}\n\nexport function healthStatusFromDict(data: Record<string, unknown>): HealthStatus {\n const supported = data.supported_languages;\n let languages: string[] = [];\n if (Array.isArray(data.languages)) {\n languages = data.languages as string[];\n } else if (supported && typeof supported === \"object\") {\n languages = Object.keys(supported as Record<string, unknown>);\n }\n\n return {\n status: String(data.status ?? \"unknown\"),\n engineReady: Boolean(data.engine_ready ?? data.tts_initialized ?? false),\n codecReady: Boolean(data.codec_ready ?? false),\n totalSpeakers: Number(data.total_speakers ?? data.speakers_loaded ?? 0),\n languages,\n voiceCloningAvailable: Boolean(data.voice_cloning_available ?? false),\n speakerProjectionLoaded: Boolean(data.speaker_projection_loaded ?? false),\n };\n}\n\n/** An available TTS model. */\nexport interface Model {\n id: string;\n object: string;\n ownedBy: string;\n}\n\nexport function modelFromDict(data: Record<string, unknown>): Model {\n return {\n id: String(data.id ?? \"\"),\n object: String(data.object ?? \"model\"),\n ownedBy: String(data.owned_by ?? \"9jalingo\"),\n };\n}\n\n/** List of available models. */\nexport interface ModelList {\n models: Model[];\n object: string;\n [Symbol.iterator](): Iterator<Model>;\n length: number;\n}\n\nexport function modelListFromDict(data: Record<string, unknown>): ModelList {\n const raw = (data.data as Record<string, unknown>[] | undefined) ?? [];\n const models = raw.map(modelFromDict);\n return {\n models,\n object: String(data.object ?? \"list\"),\n get length() {\n return models.length;\n },\n [Symbol.iterator]() {\n return models[Symbol.iterator]();\n },\n };\n}\n\n/** Root API information returned by GET /. */\nexport interface APIInfo {\n name: string;\n version: string;\n description: string;\n endpoints: Record<string, string>;\n}\n\nexport function apiInfoFromDict(data: Record<string, unknown>): APIInfo {\n return {\n name: String(data.name ?? \"\"),\n version: String(data.version ?? \"\"),\n description: String(data.description ?? \"\"),\n endpoints: (data.endpoints as Record<string, string> | undefined) ?? {},\n };\n}\n\n/** Service metadata returned by GET /v1. */\nexport interface ServiceInfo {\n object: string;\n name: string;\n modelsUrl: string;\n speechUrl: string;\n speechStreamUrl: string;\n}\n\nexport function serviceInfoFromDict(data: Record<string, unknown>): ServiceInfo {\n return {\n object: String(data.object ?? \"service\"),\n name: String(data.name ?? \"\"),\n modelsUrl: String(data.models_url ?? \"\"),\n speechUrl: String(data.speech_url ?? \"\"),\n speechStreamUrl: String(data.speech_stream_url ?? \"\"),\n };\n}\n\nexport type ResponseFormat =\n | \"wav\"\n | \"pcm\"\n | \"flac\"\n | \"aac\"\n | \"ogg\"\n | \"mp3\"\n | \"alac\";\n","const LANG_ALIASES: Record<string, string> = {\n yo: \"yo\",\n yor: \"yo\",\n yoruba: \"yo\",\n ig: \"ig\",\n ibo: \"ig\",\n igbo: \"ig\",\n ha: \"ha\",\n hau: \"ha\",\n hausa: \"ha\",\n pcm: \"pcm\",\n pidgin: \"pcm\",\n};\n\nexport function normalizeLang(code: string): string | null {\n return LANG_ALIASES[code.trim().toLowerCase()] ?? null;\n}\n\n/**\n * Resolve speech API fields: voice/speaker + lang/language.\n * Returns [speakerId, langCode]. Bare language codes must be passed via lang/language.\n */\nexport function resolveTtsVoiceAndLang(options: {\n voice?: string | null;\n speaker?: string | null;\n lang?: string | null;\n language?: string | null;\n}): [string | null, string | null] {\n let resolvedLang: string | null = null;\n\n if (options.lang != null) {\n resolvedLang = normalizeLang(options.lang);\n if (resolvedLang == null) {\n throw new Error(\n `Unsupported language '${options.lang}'. Use ha, ig, yo, or pcm.`,\n );\n }\n } else if (options.language != null) {\n resolvedLang = normalizeLang(options.language);\n if (resolvedLang == null) {\n throw new Error(\n `Unsupported language '${options.language}'. Use ha, ig, yo, or pcm.`,\n );\n }\n }\n\n // speaker takes precedence over voice\n const candidate =\n options.speaker != null ? options.speaker : options.voice;\n if (candidate == null || !String(candidate).trim()) {\n return [null, resolvedLang];\n }\n\n const resolved = String(candidate).trim();\n const normalized = resolved.toLowerCase();\n if (normalized in LANG_ALIASES) {\n const langCode = LANG_ALIASES[normalized];\n throw new Error(\n `'${resolved}' is a language code, not a speaker ID. ` +\n `Pass speaker/voice='ada_pcm' (or another speaker ID) and ` +\n `lang='${langCode}' for the language. ` +\n `Browse speakers with: client.tts.listSpeakers({ language: '${langCode}' })`,\n );\n }\n\n if (resolvedLang == null && resolved.includes(\"_\")) {\n const suffix = resolved.split(\"_\").pop()!;\n resolvedLang = normalizeLang(suffix);\n }\n\n return [resolved, resolvedLang];\n}\n\n/**\n * Resolve clone form fields.\n * voice may be a language code (\"pcm\") or a speaker ID with a language suffix.\n */\nexport function resolveCloneLangAndSpeaker(\n voice: string,\n options: { lang?: string | null; speaker?: string | null } = {},\n): [string, string | null] {\n let resolvedLang =\n options.lang != null ? normalizeLang(options.lang) : null;\n let resolvedSpeaker = options.speaker?.trim() || null;\n\n const voiceStr = (voice || \"\").trim();\n const voiceNorm = voiceStr.toLowerCase();\n\n if (voiceNorm in LANG_ALIASES) {\n if (resolvedLang == null) {\n resolvedLang = LANG_ALIASES[voiceNorm];\n }\n } else if (voiceStr.includes(\"_\")) {\n if (resolvedSpeaker == null) {\n resolvedSpeaker = voiceStr;\n }\n if (resolvedLang == null) {\n const suffix = voiceStr.split(\"_\").pop()!;\n resolvedLang = normalizeLang(suffix);\n }\n } else if (voiceStr && resolvedLang == null) {\n throw new Error(\n `'${voice}' is not a language code (ha/ig/yo/pcm) or a speaker ID ` +\n `with a language suffix (e.g. 'daniel_pcm'). ` +\n `Pass voice='pcm' or lang='pcm'.`,\n );\n }\n\n if (!resolvedLang) {\n throw new Error(\n \"Clone requires a language. Pass voice='pcm' (or 'ha'/'ig'/'yo'), \" +\n \"lang='pcm', or a speaker ID ending in _pcm/_ha/_ig/_yo.\",\n );\n }\n\n return [resolvedLang, resolvedSpeaker];\n}\n","/**\n * 9jaLingo Node.js SDK\n *\n * Official SDK for the 9jaLingo API — Nigerian language Text-to-Speech.\n *\n * @example\n * ```ts\n * import { NaijaLingo } from \"naijalingo\";\n *\n * const client = new NaijaLingo(); // uses NAIJALINGO_API_KEY\n * const audio = await client.tts.generate(\"Bawo ni!\", {\n * voice: \"adeola_yo\",\n * lang: \"yo\",\n * });\n * await audio.save(\"greeting.wav\");\n * ```\n */\n\nimport { BaseClient, type ClientOptions } from \"./client.js\";\nimport { TTS } from \"./tts.js\";\nimport {\n apiInfoFromDict,\n modelListFromDict,\n serviceInfoFromDict,\n type APIInfo,\n type ModelList,\n type ServiceInfo,\n} from \"./types.js\";\n\nexport const VERSION = \"0.1.2\";\n\nexport {\n AuthenticationError,\n ConnectionError,\n InferenceCapacityError,\n NaijaLingoError,\n NotFoundError,\n RateLimitError,\n ServerError,\n} from \"./errors.js\";\n\nexport {\n AudioResponse,\n AudioStream,\n CloneResponse,\n TTS,\n type CloneOptions,\n type GenerateOptions,\n type ListSpeakersOptions,\n type StreamOptions,\n} from \"./tts.js\";\n\nexport type {\n APIInfo,\n HealthStatus,\n Language,\n LanguageList,\n Model,\n ModelList,\n ResponseFormat,\n ServiceInfo,\n Speaker,\n SpeakerList,\n} from \"./types.js\";\n\nexport type { ClientOptions };\n\nexport class NaijaLingo {\n private readonly _client: BaseClient;\n readonly tts: TTS;\n\n constructor(options: ClientOptions = {}) {\n this._client = new BaseClient(options);\n this.tts = new TTS(this._client);\n }\n\n /** List available TTS models. GET /v1/models */\n async listModels(): Promise<ModelList> {\n const data = await this._client.getJson(\"/v1/models\");\n return modelListFromDict(data);\n }\n\n /** Root API information. GET / */\n async apiInfo(): Promise<APIInfo> {\n const data = await this._client.getJson(\"/\");\n return apiInfoFromDict(data);\n }\n\n /** v1 service metadata. GET /v1 */\n async serviceInfo(): Promise<ServiceInfo> {\n const data = await this._client.getJson(\"/v1\");\n return serviceInfoFromDict(data);\n }\n}\n"],"mappings":"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","names":["bytes"]}
1
+ {"version":3,"sources":["../src/errors.ts","../src/client.ts","../src/tts.ts","../src/types.ts","../src/voice.ts","../src/index.ts"],"sourcesContent":["/** Base exception for all 9jaLingo SDK errors. */\nexport class NaijaLingoError extends Error {\n readonly statusCode?: number;\n readonly response?: unknown;\n\n constructor(message: string, statusCode?: number, response?: unknown) {\n super(message);\n this.name = \"NaijaLingoError\";\n this.statusCode = statusCode;\n this.response = response;\n }\n}\n\n/** Raised when the API key is missing or invalid. */\nexport class AuthenticationError extends NaijaLingoError {\n constructor(message: string, statusCode?: number, response?: unknown) {\n super(message, statusCode, response);\n this.name = \"AuthenticationError\";\n }\n}\n\n/** Raised when rate limit is exceeded. */\nexport class RateLimitError extends NaijaLingoError {\n constructor(message: string, statusCode?: number, response?: unknown) {\n super(message, statusCode, response);\n this.name = \"RateLimitError\";\n }\n}\n\n/** Raised when a requested resource is not found. */\nexport class NotFoundError extends NaijaLingoError {\n constructor(message: string, statusCode?: number, response?: unknown) {\n super(message, statusCode, response);\n this.name = \"NotFoundError\";\n }\n}\n\n/** Raised when the API returns a 5xx error. */\nexport class ServerError extends NaijaLingoError {\n constructor(message: string, statusCode?: number, response?: unknown) {\n super(message, statusCode, response);\n this.name = \"ServerError\";\n }\n}\n\n/** Raised when the inference GPU is waking from scale-to-zero. */\nexport class InferenceCapacityError extends ServerError {\n constructor(message: string, statusCode?: number, response?: unknown) {\n super(message, statusCode, response);\n this.name = \"InferenceCapacityError\";\n }\n}\n\n/** Raised when unable to connect to the API. */\nexport class ConnectionError extends NaijaLingoError {\n constructor(message: string, statusCode?: number, response?: unknown) {\n super(message, statusCode, response);\n this.name = \"ConnectionError\";\n }\n}\n","import {\n AuthenticationError,\n ConnectionError,\n InferenceCapacityError,\n NaijaLingoError,\n NotFoundError,\n RateLimitError,\n ServerError,\n} from \"./errors.js\";\n\nconst DEFAULT_BASE_URL = \"https://api.9jalingo.org\";\nconst DEFAULT_TIMEOUT_MS = 300_000;\n\nexport interface ClientOptions {\n apiKey?: string;\n baseUrl?: string;\n /** Request timeout in milliseconds (default 300000). */\n timeout?: number;\n}\n\nexport class BaseClient {\n readonly apiKey: string;\n readonly baseUrl: string;\n readonly timeout: number;\n private readonly defaultHeaders: Record<string, string>;\n\n constructor(options: ClientOptions = {}) {\n this.apiKey =\n options.apiKey ?? process.env.NAIJALINGO_API_KEY ?? \"\";\n const base =\n options.baseUrl ??\n process.env.NAIJALINGO_BASE_URL ??\n DEFAULT_BASE_URL;\n this.baseUrl = base.replace(/\\/+$/, \"\");\n this.timeout = options.timeout ?? DEFAULT_TIMEOUT_MS;\n\n this.defaultHeaders = {\n \"User-Agent\": \"naijalingo-js/0.1.2\",\n };\n if (this.apiKey) {\n this.defaultHeaders[\"X-API-Key\"] = this.apiKey;\n }\n }\n\n private async request(\n method: string,\n path: string,\n init: RequestInit & { timeoutMs?: number } = {},\n ): Promise<Response> {\n const url = `${this.baseUrl}${path.startsWith(\"/\") ? path : `/${path}`}`;\n const timeoutMs = init.timeoutMs ?? this.timeout;\n let lastError: unknown;\n\n for (let attempt = 0; attempt < 3; attempt++) {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeoutMs);\n try {\n const response = await fetch(url, {\n ...init,\n method,\n headers: {\n ...this.defaultHeaders,\n ...(init.headers as Record<string, string> | undefined),\n },\n signal: controller.signal,\n });\n clearTimeout(timer);\n\n if (response.ok) {\n return response;\n }\n await this.raiseForStatus(response);\n // unreachable\n return response;\n } catch (err) {\n clearTimeout(timer);\n if (err instanceof NaijaLingoError) {\n throw err;\n }\n lastError = err;\n const isAbort =\n err instanceof Error &&\n (err.name === \"AbortError\" || err.name === \"TimeoutError\");\n // Only retry connect-style failures, not aborts from long reads\n if (isAbort) {\n throw new ConnectionError(\n `Request timed out after ${timeoutMs}ms: ${String(err)}`,\n );\n }\n if (attempt < 2) {\n await sleep(1500);\n continue;\n }\n }\n }\n\n throw new ConnectionError(\n `Unable to connect to ${this.baseUrl}: ${String(lastError)}`,\n );\n }\n\n private async raiseForStatus(response: Response): Promise<never> {\n const status = response.status;\n let detail: string;\n let body: unknown;\n try {\n body = await response.json();\n detail =\n typeof body === \"object\" &&\n body !== null &&\n \"detail\" in body\n ? String((body as { detail: unknown }).detail)\n : JSON.stringify(body);\n } catch {\n detail = await response.text();\n }\n\n const normalizedDetail = detail.toLowerCase();\n if (status === 503 && (\n normalizedDetail.includes(\"inference capacity\")\n || normalizedDetail.includes(\"inference component has no capacity\")\n || normalizedDetail.includes(\"capacity is starting\")\n )) {\n throw new InferenceCapacityError(detail, status, body);\n }\n if (status === 401 || status === 403) {\n throw new AuthenticationError(detail, status, body);\n }\n if (status === 404) {\n throw new NotFoundError(detail, status, body);\n }\n if (status === 429) {\n throw new RateLimitError(detail, status, body);\n }\n if (status >= 500) {\n throw new ServerError(detail, status, body);\n }\n throw new NaijaLingoError(detail, status, body);\n }\n\n async getJson(\n path: string,\n params?: Record<string, string | undefined | null>,\n ): Promise<Record<string, unknown>> {\n let url = path;\n if (params) {\n const qs = new URLSearchParams();\n for (const [k, v] of Object.entries(params)) {\n if (v != null) qs.set(k, v);\n }\n const s = qs.toString();\n if (s) url = `${path}?${s}`;\n }\n const resp = await this.request(\"GET\", url);\n return (await resp.json()) as Record<string, unknown>;\n }\n\n async postBytes(\n path: string,\n body: Record<string, unknown>,\n ): Promise<Uint8Array> {\n const resp = await this.request(\"POST\", path, {\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(body),\n });\n return new Uint8Array(await resp.arrayBuffer());\n }\n\n async *postStream(\n path: string,\n body: Record<string, unknown>,\n ): AsyncGenerator<Uint8Array, void, unknown> {\n let lastError: unknown;\n for (let attempt = 0; attempt < 3; attempt++) {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.timeout);\n try {\n const response = await fetch(\n `${this.baseUrl}${path.startsWith(\"/\") ? path : `/${path}`}`,\n {\n method: \"POST\",\n headers: {\n ...this.defaultHeaders,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(body),\n signal: controller.signal,\n },\n );\n clearTimeout(timer);\n\n if (!response.ok) {\n await this.raiseForStatus(response);\n }\n if (!response.body) {\n throw new ConnectionError(\"No response body for stream\");\n }\n\n const reader = response.body.getReader();\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n if (value && value.length > 0) {\n yield value;\n }\n }\n } finally {\n reader.releaseLock();\n }\n return;\n } catch (err) {\n clearTimeout(timer);\n if (err instanceof NaijaLingoError) throw err;\n lastError = err;\n const isAbort =\n err instanceof Error &&\n (err.name === \"AbortError\" || err.name === \"TimeoutError\");\n if (isAbort) {\n throw new ConnectionError(`Request timed out: ${String(err)}`);\n }\n if (attempt < 2) {\n await sleep(1500);\n continue;\n }\n }\n }\n throw new ConnectionError(\n `Unable to connect to ${this.baseUrl}: ${String(lastError)}`,\n );\n }\n\n async postMultipart(\n path: string,\n form: FormData,\n timeoutMs?: number,\n ): Promise<Response> {\n return this.request(\"POST\", path, {\n body: form,\n timeoutMs: timeoutMs ?? Math.max(this.timeout, 600_000),\n // Let fetch set multipart boundary — do not set Content-Type\n });\n }\n\n async delete(path: string): Promise<void> {\n await this.request(\"DELETE\", path);\n }\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n","import { mkdir, writeFile } from \"node:fs/promises\";\nimport { basename, dirname } from \"node:path\";\nimport { readFileSync } from \"node:fs\";\nimport { BaseClient } from \"./client.js\";\nimport {\n type HealthStatus,\n type LanguageList,\n type ResponseFormat,\n type Speaker,\n type SpeakerList,\n healthStatusFromDict,\n languageListFromDict,\n speakerFromDict,\n speakerListFromDict,\n} from \"./types.js\";\nimport {\n resolveCloneLangAndSpeaker,\n resolveTtsVoiceAndLang,\n} from \"./voice.js\";\n\nconst DEFAULT_MODEL_NAME = \"9jalingo-tts-1\";\n\nexport type GenerateOptions = {\n voice?: string;\n speaker?: string;\n lang?: string;\n language?: string;\n modelName?: string;\n speakerEmbedding?: number[];\n responseFormat?: ResponseFormat;\n temperature?: number;\n topP?: number;\n repetitionPenalty?: number;\n enableLongForm?: boolean;\n maxChunkDuration?: number;\n silenceDuration?: number;\n};\n\nexport type StreamOptions = Omit<\n GenerateOptions,\n \"modelName\" | \"responseFormat\"\n>;\n\nexport type CloneOptions = {\n voice?: string;\n lang?: string;\n speaker?: string;\n modelName?: string;\n temperature?: number;\n topP?: number;\n repetitionPenalty?: number;\n responseFormat?: ResponseFormat;\n};\n\nexport type ListSpeakersOptions = {\n language?: string;\n gender?: string;\n domain?: string;\n};\n\n/** Audio data returned from a generation request. */\nexport class AudioResponse {\n readonly content: Uint8Array;\n readonly mediaType: string;\n\n constructor(content: Uint8Array, mediaType = \"audio/wav\") {\n this.content = content;\n this.mediaType = mediaType;\n }\n\n /** Write the audio to a file. */\n async save(path: string): Promise<string> {\n await mkdir(dirname(path), { recursive: true });\n await writeFile(path, this.content);\n return path;\n }\n\n get length(): number {\n return this.content.length;\n }\n\n toString(): string {\n return `AudioResponse(${this.content.length} bytes, ${this.mediaType})`;\n }\n}\n\n/** Audio and reusable voice metadata returned from a clone request. */\nexport class CloneResponse extends AudioResponse {\n readonly voiceId: string | null;\n readonly voiceCode: string | null;\n readonly voiceName: string | null;\n readonly cloneId: string | null;\n readonly jobId: string | null;\n\n constructor(\n content: Uint8Array,\n mediaType: string,\n metadata: {\n voiceId: string | null;\n voiceCode: string | null;\n voiceName: string | null;\n cloneId: string | null;\n jobId: string | null;\n },\n ) {\n super(content, mediaType);\n this.voiceId = metadata.voiceId;\n this.voiceCode = metadata.voiceCode;\n this.voiceName = metadata.voiceName;\n this.cloneId = metadata.cloneId;\n this.jobId = metadata.jobId;\n }\n}\n\n/** Streaming audio response — yields byte chunks as they arrive. */\nexport class AudioStream implements AsyncIterable<Uint8Array> {\n private readonly chunks: AsyncIterable<Uint8Array>;\n private collected: Uint8Array | null = null;\n\n constructor(chunks: AsyncIterable<Uint8Array>) {\n this.chunks = chunks;\n }\n\n async *[Symbol.asyncIterator](): AsyncIterator<Uint8Array> {\n for await (const chunk of this.chunks) {\n yield chunk;\n }\n }\n\n /** Consume the entire stream and return an AudioResponse. */\n async collect(): Promise<AudioResponse> {\n if (this.collected == null) {\n const parts: Uint8Array[] = [];\n let total = 0;\n for await (const chunk of this.chunks) {\n parts.push(chunk);\n total += chunk.length;\n }\n const out = new Uint8Array(total);\n let offset = 0;\n for (const part of parts) {\n out.set(part, offset);\n offset += part.length;\n }\n this.collected = out;\n }\n return new AudioResponse(this.collected, \"audio/wav\");\n }\n}\n\nexport class TTS {\n private readonly client: BaseClient;\n\n constructor(client: BaseClient) {\n this.client = client;\n }\n\n /** Generate speech from text. */\n async generate(\n text: string,\n options: GenerateOptions = {},\n ): Promise<AudioResponse> {\n let [resolvedVoice, resolvedLang] = resolveTtsVoiceAndLang(options);\n if (resolvedVoice == null && options.speakerEmbedding == null) {\n resolvedVoice = \"blessing_pcm\";\n }\n const responseFormat = options.responseFormat ?? \"wav\";\n const body = buildBody({\n input: text,\n voice: resolvedVoice,\n lang: resolvedLang,\n model: options.modelName ?? DEFAULT_MODEL_NAME,\n speaker_embedding: options.speakerEmbedding,\n response_format: responseFormat,\n temperature: options.temperature,\n top_p: options.topP,\n repetition_penalty: options.repetitionPenalty,\n enable_long_form: options.enableLongForm ?? true,\n max_chunk_duration: options.maxChunkDuration,\n silence_duration: options.silenceDuration,\n });\n const content = await this.client.postBytes(\"/v1/audio/speech\", body);\n const mediaType = MEDIA_TYPES[responseFormat] ?? \"application/octet-stream\";\n return new AudioResponse(content, mediaType);\n }\n\n /** Stream speech generation — audio arrives as it's produced. */\n stream(text: string, options: StreamOptions = {}): AudioStream {\n let [resolvedVoice, resolvedLang] = resolveTtsVoiceAndLang(options);\n if (resolvedVoice == null && options.speakerEmbedding == null) {\n resolvedVoice = \"blessing_pcm\";\n }\n const body = buildBody({\n input: text,\n voice: resolvedVoice,\n lang: resolvedLang,\n speaker_embedding: options.speakerEmbedding,\n response_format: \"wav\",\n temperature: options.temperature,\n top_p: options.topP,\n repetition_penalty: options.repetitionPenalty,\n enable_long_form: options.enableLongForm ?? true,\n max_chunk_duration: options.maxChunkDuration,\n silence_duration: options.silenceDuration,\n });\n return new AudioStream(this.client.postStream(\"/v1/audio/speech/stream\", body));\n }\n\n /**\n * Generate speech using a cloned voice from a reference audio file.\n * `audioFile` may be a filesystem path, Buffer, Uint8Array, Blob, or File.\n */\n async clone(\n text: string,\n audioFile: string | Buffer | Uint8Array | Blob,\n options: CloneOptions = {},\n ): Promise<CloneResponse> {\n const voice = options.voice ?? \"pcm\";\n const [resolvedLang, resolvedSpeaker] = resolveCloneLangAndSpeaker(\n voice,\n { lang: options.lang, speaker: options.speaker },\n );\n const responseFormat = options.responseFormat ?? \"wav\";\n\n const form = new FormData();\n form.append(\"text\", text);\n form.append(\"lang\", resolvedLang);\n form.append(\"model_name\", options.modelName ?? DEFAULT_MODEL_NAME);\n form.append(\"response_format\", responseFormat);\n if (resolvedSpeaker) {\n form.append(\"voice\", resolvedSpeaker);\n }\n if (options.temperature != null) {\n form.append(\"temperature\", String(options.temperature));\n }\n if (options.topP != null) {\n form.append(\"top_p\", String(options.topP));\n }\n if (options.repetitionPenalty != null) {\n form.append(\"repetition_penalty\", String(options.repetitionPenalty));\n }\n\n const { blob, filename } = await toAudioBlob(audioFile);\n form.append(\"audio\", blob, filename);\n\n const response = await this.client.postMultipart(\"/v1/audio/clone\", form);\n const content = new Uint8Array(await response.arrayBuffer());\n const mediaType = MEDIA_TYPES[responseFormat] ?? \"application/octet-stream\";\n return new CloneResponse(content, mediaType, {\n voiceId: response.headers.get(\"X-Voice-ID\"),\n voiceCode: response.headers.get(\"X-Voice-Code\"),\n voiceName: response.headers.get(\"X-Voice-Name\"),\n cloneId: response.headers.get(\"X-Clone-ID\"),\n jobId: response.headers.get(\"X-Job-ID\"),\n });\n }\n\n async listSpeakers(\n options: ListSpeakersOptions = {},\n ): Promise<SpeakerList> {\n const data = await this.client.getJson(\"/v1/speakers\", {\n language: options.language,\n gender: options.gender,\n domain: options.domain,\n });\n return speakerListFromDict(data);\n }\n\n async getSpeaker(speakerId: string): Promise<Speaker> {\n const data = await this.client.getJson(`/v1/speakers/${speakerId}`);\n return speakerFromDict(data);\n }\n\n /** Permanently delete a cloned voice owned by this API key. */\n async deleteVoice(voiceId: string): Promise<void> {\n const normalizedVoiceId = voiceId.trim();\n if (!normalizedVoiceId) {\n throw new Error(\"voiceId is required\");\n }\n await this.client.delete(`/v1/voices/${encodeURIComponent(normalizedVoiceId)}`);\n }\n\n async listLanguages(): Promise<LanguageList> {\n const data = await this.client.getJson(\"/v1/languages\");\n return languageListFromDict(data);\n }\n\n async health(): Promise<HealthStatus> {\n const data = await this.client.getJson(\"/v1/health\");\n return healthStatusFromDict(data);\n }\n}\n\nconst MEDIA_TYPES: Record<string, string> = {\n wav: \"audio/wav\",\n pcm: \"application/octet-stream\",\n flac: \"audio/flac\",\n aac: \"audio/aac\",\n ogg: \"audio/ogg\",\n mp3: \"audio/mpeg\",\n alac: \"audio/alac\",\n};\n\nfunction buildBody(\n kwargs: Record<string, unknown>,\n): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(kwargs)) {\n if (v !== undefined && v !== null) out[k] = v;\n }\n return out;\n}\n\nasync function toAudioBlob(\n audioFile: string | Buffer | Uint8Array | Blob,\n): Promise<{ blob: Blob; filename: string }> {\n if (typeof audioFile === \"string\") {\n const bytes = readFileSync(audioFile);\n const filename = basename(audioFile);\n const mime = guessMime(filename);\n return {\n blob: new Blob([bytes], { type: mime }),\n filename,\n };\n }\n if (audioFile instanceof Blob) {\n return {\n blob: audioFile,\n filename: \"audio.wav\",\n };\n }\n // Buffer | Uint8Array\n const bytes =\n audioFile instanceof Uint8Array\n ? audioFile\n : new Uint8Array(audioFile);\n return {\n blob: new Blob([bytes], { type: \"application/octet-stream\" }),\n filename: \"audio.wav\",\n };\n}\n\nfunction guessMime(filename: string): string {\n const lower = filename.toLowerCase();\n if (lower.endsWith(\".wav\")) return \"audio/wav\";\n if (lower.endsWith(\".mp3\")) return \"audio/mpeg\";\n if (lower.endsWith(\".flac\")) return \"audio/flac\";\n if (lower.endsWith(\".ogg\")) return \"audio/ogg\";\n if (lower.endsWith(\".aac\") || lower.endsWith(\".m4a\")) return \"audio/aac\";\n return \"application/octet-stream\";\n}\n","/** A speaker voice identity. */\nexport interface Speaker {\n id: string;\n name: string;\n language: string;\n gender?: string | null;\n domain?: string | null;\n}\n\nexport function speakerFromDict(data: Record<string, unknown>): Speaker {\n return {\n id: String(data.id ?? data.speaker_id ?? \"\"),\n name: String(data.name ?? data.id ?? \"\"),\n language: String(data.language ?? \"\"),\n gender: (data.gender as string | null | undefined) ?? null,\n domain: (data.domain as string | null | undefined) ?? null,\n };\n}\n\n/** List of speakers with metadata. */\nexport interface SpeakerList {\n speakers: Speaker[];\n total: number;\n byLanguage: Record<string, number>;\n [Symbol.iterator](): Iterator<Speaker>;\n length: number;\n}\n\nexport function speakerListFromDict(data: Record<string, unknown>): SpeakerList {\n const raw = (data.speakers as Record<string, unknown>[] | undefined) ?? [];\n const speakers = raw.map(speakerFromDict);\n const total = typeof data.total === \"number\" ? data.total : speakers.length;\n const byLanguage =\n (data.by_language as Record<string, number> | undefined) ?? {};\n return {\n speakers,\n total,\n byLanguage,\n get length() {\n return total;\n },\n [Symbol.iterator]() {\n return speakers[Symbol.iterator]();\n },\n };\n}\n\n/** A supported language. */\nexport interface Language {\n code: string;\n name: string;\n speakerCount: number;\n}\n\nexport function languageFromDict(data: Record<string, unknown>): Language {\n return {\n code: String(data.code ?? \"\"),\n name: String(data.name ?? \"\"),\n speakerCount: Number(data.speaker_count ?? 0),\n };\n}\n\n/** List of supported languages and domains. */\nexport interface LanguageList {\n languages: Language[];\n domains: string[];\n}\n\nexport function languageListFromDict(data: Record<string, unknown>): LanguageList {\n const rawLangs = data.languages;\n let languages: Language[];\n\n if (rawLangs && typeof rawLangs === \"object\" && !Array.isArray(rawLangs)) {\n languages = Object.entries(rawLangs as Record<string, unknown>).map(\n ([code, value]) => {\n if (value && typeof value === \"object\") {\n const v = value as Record<string, unknown>;\n return {\n code,\n name: String(v.name ?? code),\n speakerCount: Number(v.speaker_count ?? 0),\n };\n }\n return { code, name: String(value), speakerCount: 0 };\n },\n );\n } else {\n const arr = (rawLangs as Record<string, unknown>[] | undefined) ?? [];\n languages = arr.map(languageFromDict);\n }\n\n return {\n languages,\n domains: (data.domains as string[] | undefined) ?? [],\n };\n}\n\n/** API health check result. */\nexport interface HealthStatus {\n status: string;\n engineReady: boolean;\n codecReady: boolean;\n totalSpeakers: number;\n languages: string[];\n voiceCloningAvailable: boolean;\n speakerProjectionLoaded: boolean;\n}\n\nexport function healthStatusFromDict(data: Record<string, unknown>): HealthStatus {\n const supported = data.supported_languages;\n let languages: string[] = [];\n if (Array.isArray(data.languages)) {\n languages = data.languages as string[];\n } else if (supported && typeof supported === \"object\") {\n languages = Object.keys(supported as Record<string, unknown>);\n }\n\n return {\n status: String(data.status ?? \"unknown\"),\n engineReady: Boolean(data.engine_ready ?? data.tts_initialized ?? false),\n codecReady: Boolean(data.codec_ready ?? false),\n totalSpeakers: Number(data.total_speakers ?? data.speakers_loaded ?? 0),\n languages,\n voiceCloningAvailable: Boolean(data.voice_cloning_available ?? false),\n speakerProjectionLoaded: Boolean(data.speaker_projection_loaded ?? false),\n };\n}\n\n/** An available TTS model. */\nexport interface Model {\n id: string;\n object: string;\n ownedBy: string;\n}\n\nexport function modelFromDict(data: Record<string, unknown>): Model {\n return {\n id: String(data.id ?? \"\"),\n object: String(data.object ?? \"model\"),\n ownedBy: String(data.owned_by ?? \"9jalingo\"),\n };\n}\n\n/** List of available models. */\nexport interface ModelList {\n models: Model[];\n object: string;\n [Symbol.iterator](): Iterator<Model>;\n length: number;\n}\n\nexport function modelListFromDict(data: Record<string, unknown>): ModelList {\n const raw = (data.data as Record<string, unknown>[] | undefined) ?? [];\n const models = raw.map(modelFromDict);\n return {\n models,\n object: String(data.object ?? \"list\"),\n get length() {\n return models.length;\n },\n [Symbol.iterator]() {\n return models[Symbol.iterator]();\n },\n };\n}\n\n/** Root API information returned by GET /. */\nexport interface APIInfo {\n name: string;\n version: string;\n description: string;\n endpoints: Record<string, string>;\n}\n\nexport function apiInfoFromDict(data: Record<string, unknown>): APIInfo {\n return {\n name: String(data.name ?? \"\"),\n version: String(data.version ?? \"\"),\n description: String(data.description ?? \"\"),\n endpoints: (data.endpoints as Record<string, string> | undefined) ?? {},\n };\n}\n\n/** Service metadata returned by GET /v1. */\nexport interface ServiceInfo {\n object: string;\n name: string;\n modelsUrl: string;\n speechUrl: string;\n speechStreamUrl: string;\n}\n\nexport function serviceInfoFromDict(data: Record<string, unknown>): ServiceInfo {\n return {\n object: String(data.object ?? \"service\"),\n name: String(data.name ?? \"\"),\n modelsUrl: String(data.models_url ?? \"\"),\n speechUrl: String(data.speech_url ?? \"\"),\n speechStreamUrl: String(data.speech_stream_url ?? \"\"),\n };\n}\n\nexport type ResponseFormat =\n | \"wav\"\n | \"pcm\"\n | \"flac\"\n | \"aac\"\n | \"ogg\"\n | \"mp3\"\n | \"alac\";\n","const LANG_ALIASES: Record<string, string> = {\n yo: \"yo\",\n yor: \"yo\",\n yoruba: \"yo\",\n ig: \"ig\",\n ibo: \"ig\",\n igbo: \"ig\",\n ha: \"ha\",\n hau: \"ha\",\n hausa: \"ha\",\n pcm: \"pcm\",\n pidgin: \"pcm\",\n};\n\nexport function normalizeLang(code: string): string | null {\n return LANG_ALIASES[code.trim().toLowerCase()] ?? null;\n}\n\n/**\n * Resolve speech API fields: voice/speaker + lang/language.\n * Returns [speakerId, langCode]. Bare language codes must be passed via lang/language.\n */\nexport function resolveTtsVoiceAndLang(options: {\n voice?: string | null;\n speaker?: string | null;\n lang?: string | null;\n language?: string | null;\n}): [string | null, string | null] {\n let resolvedLang: string | null = null;\n\n if (options.lang != null) {\n resolvedLang = normalizeLang(options.lang);\n if (resolvedLang == null) {\n throw new Error(\n `Unsupported language '${options.lang}'. Use ha, ig, yo, or pcm.`,\n );\n }\n } else if (options.language != null) {\n resolvedLang = normalizeLang(options.language);\n if (resolvedLang == null) {\n throw new Error(\n `Unsupported language '${options.language}'. Use ha, ig, yo, or pcm.`,\n );\n }\n }\n\n // speaker takes precedence over voice\n const candidate =\n options.speaker != null ? options.speaker : options.voice;\n if (candidate == null || !String(candidate).trim()) {\n return [null, resolvedLang];\n }\n\n const resolved = String(candidate).trim();\n const normalized = resolved.toLowerCase();\n if (normalized in LANG_ALIASES) {\n const langCode = LANG_ALIASES[normalized];\n throw new Error(\n `'${resolved}' is a language code, not a speaker ID. ` +\n `Pass speaker/voice='ada_pcm' (or another speaker ID) and ` +\n `lang='${langCode}' for the language. ` +\n `Browse speakers with: client.tts.listSpeakers({ language: '${langCode}' })`,\n );\n }\n\n if (resolvedLang == null && resolved.includes(\"_\")) {\n const suffix = resolved.split(\"_\").pop()!;\n resolvedLang = normalizeLang(suffix);\n }\n\n return [resolved, resolvedLang];\n}\n\n/**\n * Resolve clone form fields.\n * voice may be a language code (\"pcm\") or a speaker ID with a language suffix.\n */\nexport function resolveCloneLangAndSpeaker(\n voice: string,\n options: { lang?: string | null; speaker?: string | null } = {},\n): [string, string | null] {\n let resolvedLang =\n options.lang != null ? normalizeLang(options.lang) : null;\n let resolvedSpeaker = options.speaker?.trim() || null;\n\n const voiceStr = (voice || \"\").trim();\n const voiceNorm = voiceStr.toLowerCase();\n\n if (voiceNorm in LANG_ALIASES) {\n if (resolvedLang == null) {\n resolvedLang = LANG_ALIASES[voiceNorm];\n }\n } else if (voiceStr.includes(\"_\")) {\n if (resolvedSpeaker == null) {\n resolvedSpeaker = voiceStr;\n }\n if (resolvedLang == null) {\n const suffix = voiceStr.split(\"_\").pop()!;\n resolvedLang = normalizeLang(suffix);\n }\n } else if (voiceStr && resolvedLang == null) {\n throw new Error(\n `'${voice}' is not a language code (ha/ig/yo/pcm) or a speaker ID ` +\n `with a language suffix (e.g. 'daniel_pcm'). ` +\n `Pass voice='pcm' or lang='pcm'.`,\n );\n }\n\n if (!resolvedLang) {\n throw new Error(\n \"Clone requires a language. Pass voice='pcm' (or 'ha'/'ig'/'yo'), \" +\n \"lang='pcm', or a speaker ID ending in _pcm/_ha/_ig/_yo.\",\n );\n }\n\n return [resolvedLang, resolvedSpeaker];\n}\n","/**\n * 9jaLingo Node.js SDK\n *\n * Official SDK for the 9jaLingo API — Nigerian language Text-to-Speech.\n *\n * @example\n * ```ts\n * import { NaijaLingo } from \"naijalingo\";\n *\n * const client = new NaijaLingo(); // uses NAIJALINGO_API_KEY\n * const audio = await client.tts.generate(\"Bawo ni!\", {\n * voice: \"adeola_yo\",\n * lang: \"yo\",\n * });\n * await audio.save(\"greeting.wav\");\n * ```\n */\n\nimport { BaseClient, type ClientOptions } from \"./client.js\";\nimport { TTS } from \"./tts.js\";\nimport {\n apiInfoFromDict,\n modelListFromDict,\n serviceInfoFromDict,\n type APIInfo,\n type ModelList,\n type ServiceInfo,\n} from \"./types.js\";\n\nexport const VERSION = \"0.1.2\";\n\nexport {\n AuthenticationError,\n ConnectionError,\n InferenceCapacityError,\n NaijaLingoError,\n NotFoundError,\n RateLimitError,\n ServerError,\n} from \"./errors.js\";\n\nexport {\n AudioResponse,\n AudioStream,\n CloneResponse,\n TTS,\n type CloneOptions,\n type GenerateOptions,\n type ListSpeakersOptions,\n type StreamOptions,\n} from \"./tts.js\";\n\nexport type {\n APIInfo,\n HealthStatus,\n Language,\n LanguageList,\n Model,\n ModelList,\n ResponseFormat,\n ServiceInfo,\n Speaker,\n SpeakerList,\n} from \"./types.js\";\n\nexport type { ClientOptions };\n\nexport class NaijaLingo {\n private readonly _client: BaseClient;\n readonly tts: TTS;\n\n constructor(options: ClientOptions = {}) {\n this._client = new BaseClient(options);\n this.tts = new TTS(this._client);\n }\n\n /** List available TTS models. GET /v1/models */\n async listModels(): Promise<ModelList> {\n const data = await this._client.getJson(\"/v1/models\");\n return modelListFromDict(data);\n }\n\n /** Root API information. GET / */\n async apiInfo(): Promise<APIInfo> {\n const data = await this._client.getJson(\"/\");\n return apiInfoFromDict(data);\n }\n\n /** v1 service metadata. GET /v1 */\n async serviceInfo(): Promise<ServiceInfo> {\n const data = await this._client.getJson(\"/v1\");\n return serviceInfoFromDict(data);\n }\n}\n"],"mappings":"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","names":["bytes"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "naijalingo",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "Official Node.js SDK for 9jaLingo — AI-powered Text-to-Speech and Voice Cloning for Nigerian languages including Hausa, Igbo, Yoruba, and Nigerian Pidgin with 240+ speaker voices.",
5
5
  "license": "MIT",
6
6
  "author": "9jaLingo <support@9jalingo.org>",