@tanstack/ai-elevenlabs 0.2.0 → 0.2.2

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.
@@ -1,4 +1,5 @@
1
1
  import { ElevenLabsClient } from '@elevenlabs/elevenlabs-js';
2
+ import { generateId as sharedGenerateId } from '@tanstack/ai-utils';
2
3
  import { ElevenLabsOutputFormat } from '../model-meta.js';
3
4
  /**
4
5
  * Configuration for any ElevenLabs adapter. When `apiKey` is omitted we read
@@ -24,7 +25,7 @@ export declare function getElevenLabsAgentIdFromEnv(): string;
24
25
  * pass in an explicit key without needing `process.env`.
25
26
  */
26
27
  export declare function createElevenLabsClient(config?: ElevenLabsClientConfig): ElevenLabsClient;
27
- export declare function generateId(prefix: string): string;
28
+ export declare const generateId: typeof sharedGenerateId;
28
29
  /**
29
30
  * Convert an ArrayBuffer to base64 in a cross-runtime way.
30
31
  *
@@ -1,4 +1,5 @@
1
1
  import { ElevenLabsClient } from "@elevenlabs/elevenlabs-js";
2
+ import { getApiKeyFromEnv, generateId as generateId$1 } from "@tanstack/ai-utils";
2
3
  function getEnvironment() {
3
4
  if (typeof globalThis !== "undefined") {
4
5
  const win = globalThis.window;
@@ -10,13 +11,7 @@ function getEnvironment() {
10
11
  return void 0;
11
12
  }
12
13
  function getElevenLabsApiKeyFromEnv() {
13
- const key = getEnvironment()?.ELEVENLABS_API_KEY;
14
- if (!key) {
15
- throw new Error(
16
- "ELEVENLABS_API_KEY is required. Please set it in your environment variables or pass it explicitly to the adapter factory."
17
- );
18
- }
19
- return key;
14
+ return getApiKeyFromEnv("ELEVENLABS_API_KEY");
20
15
  }
21
16
  function getElevenLabsAgentIdFromEnv() {
22
17
  const id = getEnvironment()?.ELEVENLABS_AGENT_ID;
@@ -37,9 +32,7 @@ function createElevenLabsClient(config) {
37
32
  ...config?.headers ? { headers: config.headers } : {}
38
33
  });
39
34
  }
40
- function generateId(prefix) {
41
- return `${prefix}-${Date.now()}-${Math.random().toString(36).substring(2)}`;
42
- }
35
+ const generateId = generateId$1;
43
36
  function arrayBufferToBase64(buffer) {
44
37
  if (typeof Buffer !== "undefined" && typeof Buffer.from === "function") {
45
38
  return Buffer.from(buffer).toString("base64");
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","sources":["../../../src/utils/client.ts"],"sourcesContent":["import { ElevenLabsClient } from '@elevenlabs/elevenlabs-js'\nimport type { ElevenLabsOutputFormat } from '../model-meta'\n\n/**\n * Configuration for any ElevenLabs adapter. When `apiKey` is omitted we read\n * `ELEVENLABS_API_KEY` from `process.env` / `window.env` to match the\n * pattern the realtime adapters already use.\n */\nexport interface ElevenLabsClientConfig {\n apiKey?: string\n /** Override the API base URL — handy for tests + self-hosted proxies. */\n baseUrl?: string\n /** Per-request timeout passed through to the SDK (ms). */\n timeoutInSeconds?: number\n /** Override the number of SDK-level retries. */\n maxRetries?: number\n /** Extra headers attached to every request (e.g. test multiplexing). */\n headers?: Record<string, string>\n}\n\ninterface EnvObject {\n ELEVENLABS_API_KEY?: string\n ELEVENLABS_AGENT_ID?: string\n}\n\ninterface WindowWithEnv {\n env?: EnvObject\n}\n\nfunction getEnvironment(): EnvObject | undefined {\n if (typeof globalThis !== 'undefined') {\n const win = (globalThis as { window?: WindowWithEnv }).window\n if (win?.env) return win.env\n }\n if (typeof process !== 'undefined') {\n return process.env as EnvObject\n }\n return undefined\n}\n\nexport function getElevenLabsApiKeyFromEnv(): string {\n const key = getEnvironment()?.ELEVENLABS_API_KEY\n if (!key) {\n throw new Error(\n 'ELEVENLABS_API_KEY is required. Please set it in your environment ' +\n 'variables or pass it explicitly to the adapter factory.',\n )\n }\n return key\n}\n\nexport function getElevenLabsAgentIdFromEnv(): string {\n const id = getEnvironment()?.ELEVENLABS_AGENT_ID\n if (!id) {\n throw new Error(\n 'ELEVENLABS_AGENT_ID is required. Please set it in your environment ' +\n 'variables or pass `agentId` explicitly to elevenlabsRealtimeToken().',\n )\n }\n return id\n}\n\n/**\n * Build an `ElevenLabsClient` with env-based or explicit credentials.\n * Each adapter calls this once at construction time so unit tests can\n * pass in an explicit key without needing `process.env`.\n */\nexport function createElevenLabsClient(\n config?: ElevenLabsClientConfig,\n): ElevenLabsClient {\n const apiKey = config?.apiKey ?? getElevenLabsApiKeyFromEnv()\n return new ElevenLabsClient({\n apiKey,\n ...(config?.baseUrl ? { baseUrl: config.baseUrl } : {}),\n ...(config?.timeoutInSeconds != null\n ? { timeoutInSeconds: config.timeoutInSeconds }\n : {}),\n ...(config?.maxRetries != null ? { maxRetries: config.maxRetries } : {}),\n ...(config?.headers ? { headers: config.headers } : {}),\n })\n}\n\nexport function generateId(prefix: string): string {\n return `${prefix}-${Date.now()}-${Math.random().toString(36).substring(2)}`\n}\n\n/**\n * Convert an ArrayBuffer to base64 in a cross-runtime way.\n *\n * The naive `btoa(String.fromCharCode(...bytes))` form blows up V8's argument\n * limit (~65k) on realistic audio payloads, so we either use `Buffer`\n * (Node / Bun) or walk the byte array in a single loop (browser).\n */\nexport function arrayBufferToBase64(buffer: ArrayBuffer): string {\n if (typeof Buffer !== 'undefined' && typeof Buffer.from === 'function') {\n return Buffer.from(buffer).toString('base64')\n }\n const view = new Uint8Array(buffer)\n let binary = ''\n for (let i = 0; i < view.byteLength; i += 1) {\n binary += String.fromCharCode(view[i]!)\n }\n return btoa(binary)\n}\n\n/**\n * Drain a `ReadableStream<Uint8Array>` (what the ElevenLabs SDK returns for\n * audio endpoints) into a single `Uint8Array`, then expose it as an\n * `ArrayBuffer` slice. We concatenate ourselves rather than going through\n * `new Response(stream).arrayBuffer()` so we stay runtime-agnostic.\n */\nexport async function readStreamToArrayBuffer(\n stream: ReadableStream<Uint8Array>,\n): Promise<ArrayBuffer> {\n const reader = stream.getReader()\n const chunks: Array<Uint8Array> = []\n let total = 0\n try {\n let result = await reader.read()\n while (!result.done) {\n chunks.push(result.value)\n total += result.value.byteLength\n result = await reader.read()\n }\n } finally {\n reader.releaseLock()\n }\n const merged = new Uint8Array(total)\n let offset = 0\n for (const chunk of chunks) {\n merged.set(chunk, offset)\n offset += chunk.byteLength\n }\n return merged.buffer.slice(\n merged.byteOffset,\n merged.byteOffset + merged.byteLength,\n )\n}\n\n/**\n * Decode a `data:` URL into a Blob for upload to the ElevenLabs STT API\n * (which only accepts multipart files or https URLs). Supports base64 and\n * URL-encoded payloads. Returns `undefined` for non-data-URL strings so the\n * caller can fall through to treating the input as an https URL.\n */\nexport function dataUrlToBlob(value: string): Blob | undefined {\n if (!value.startsWith('data:')) return undefined\n const commaIndex = value.indexOf(',')\n if (commaIndex === -1) return undefined\n\n const header = value.slice(5, commaIndex)\n const payload = value.slice(commaIndex + 1)\n const isBase64 = /;base64$/i.test(header)\n const mimeType = header.split(';')[0] || 'application/octet-stream'\n\n if (isBase64) {\n const binary = atob(payload)\n const bytes = new Uint8Array(binary.length)\n for (let i = 0; i < binary.length; i += 1) {\n bytes[i] = binary.charCodeAt(i)\n }\n return new Blob([bytes], { type: mimeType })\n }\n\n return new Blob([decodeURIComponent(payload)], { type: mimeType })\n}\n\n/**\n * Break an ElevenLabs `output_format` string (`mp3_44100_128`,\n * `pcm_24000`, `opus_48000_64`, `ulaw_8000`, ...) into a file extension and\n * content-type suitable for `TTSResult` / `AudioGenerationResult` consumers.\n *\n * Unknown codecs fall back to `mp3` / `audio/mpeg` because the ElevenLabs\n * default is `mp3_44100_128` — mispredicting on an exotic format is safer\n * than throwing in the adapter.\n */\nexport function parseOutputFormat(fmt: ElevenLabsOutputFormat | undefined): {\n format: string\n contentType: string\n} {\n const codec = (fmt || 'mp3_44100_128').split('_')[0]?.toLowerCase()\n switch (codec) {\n case 'mp3':\n return { format: 'mp3', contentType: 'audio/mpeg' }\n case 'pcm':\n return { format: 'pcm', contentType: 'audio/pcm' }\n case 'opus':\n return { format: 'opus', contentType: 'audio/opus' }\n case 'ulaw':\n return { format: 'ulaw', contentType: 'audio/basic' }\n case 'alaw':\n return { format: 'alaw', contentType: 'audio/x-alaw-basic' }\n default:\n return { format: 'mp3', contentType: 'audio/mpeg' }\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"client.js","sources":["../../../src/utils/client.ts"],"sourcesContent":["import { ElevenLabsClient } from '@elevenlabs/elevenlabs-js'\nimport {\n getApiKeyFromEnv,\n generateId as sharedGenerateId,\n} from '@tanstack/ai-utils'\nimport type { ElevenLabsOutputFormat } from '../model-meta'\n\n/**\n * Configuration for any ElevenLabs adapter. When `apiKey` is omitted we read\n * `ELEVENLABS_API_KEY` from `process.env` / `window.env` to match the\n * pattern the realtime adapters already use.\n */\nexport interface ElevenLabsClientConfig {\n apiKey?: string\n /** Override the API base URL — handy for tests + self-hosted proxies. */\n baseUrl?: string\n /** Per-request timeout passed through to the SDK (ms). */\n timeoutInSeconds?: number\n /** Override the number of SDK-level retries. */\n maxRetries?: number\n /** Extra headers attached to every request (e.g. test multiplexing). */\n headers?: Record<string, string>\n}\n\ninterface EnvObject {\n ELEVENLABS_API_KEY?: string\n ELEVENLABS_AGENT_ID?: string\n}\n\ninterface WindowWithEnv {\n env?: EnvObject\n}\n\nfunction getEnvironment(): EnvObject | undefined {\n if (typeof globalThis !== 'undefined') {\n const win = (globalThis as { window?: WindowWithEnv }).window\n if (win?.env) return win.env\n }\n if (typeof process !== 'undefined') {\n return process.env as EnvObject\n }\n return undefined\n}\n\nexport function getElevenLabsApiKeyFromEnv(): string {\n return getApiKeyFromEnv('ELEVENLABS_API_KEY')\n}\n\nexport function getElevenLabsAgentIdFromEnv(): string {\n const id = getEnvironment()?.ELEVENLABS_AGENT_ID\n if (!id) {\n throw new Error(\n 'ELEVENLABS_AGENT_ID is required. Please set it in your environment ' +\n 'variables or pass `agentId` explicitly to elevenlabsRealtimeToken().',\n )\n }\n return id\n}\n\n/**\n * Build an `ElevenLabsClient` with env-based or explicit credentials.\n * Each adapter calls this once at construction time so unit tests can\n * pass in an explicit key without needing `process.env`.\n */\nexport function createElevenLabsClient(\n config?: ElevenLabsClientConfig,\n): ElevenLabsClient {\n const apiKey = config?.apiKey ?? getElevenLabsApiKeyFromEnv()\n return new ElevenLabsClient({\n apiKey,\n ...(config?.baseUrl ? { baseUrl: config.baseUrl } : {}),\n ...(config?.timeoutInSeconds != null\n ? { timeoutInSeconds: config.timeoutInSeconds }\n : {}),\n ...(config?.maxRetries != null ? { maxRetries: config.maxRetries } : {}),\n ...(config?.headers ? { headers: config.headers } : {}),\n })\n}\n\n// Re-exported from `@tanstack/ai-utils` so existing callers keep working\n// while the implementation stays deduped across provider packages.\nexport const generateId = sharedGenerateId\n\n/**\n * Convert an ArrayBuffer to base64 in a cross-runtime way.\n *\n * The naive `btoa(String.fromCharCode(...bytes))` form blows up V8's argument\n * limit (~65k) on realistic audio payloads, so we either use `Buffer`\n * (Node / Bun) or walk the byte array in a single loop (browser).\n */\nexport function arrayBufferToBase64(buffer: ArrayBuffer): string {\n if (typeof Buffer !== 'undefined' && typeof Buffer.from === 'function') {\n return Buffer.from(buffer).toString('base64')\n }\n const view = new Uint8Array(buffer)\n let binary = ''\n for (let i = 0; i < view.byteLength; i += 1) {\n binary += String.fromCharCode(view[i]!)\n }\n return btoa(binary)\n}\n\n/**\n * Drain a `ReadableStream<Uint8Array>` (what the ElevenLabs SDK returns for\n * audio endpoints) into a single `Uint8Array`, then expose it as an\n * `ArrayBuffer` slice. We concatenate ourselves rather than going through\n * `new Response(stream).arrayBuffer()` so we stay runtime-agnostic.\n */\nexport async function readStreamToArrayBuffer(\n stream: ReadableStream<Uint8Array>,\n): Promise<ArrayBuffer> {\n const reader = stream.getReader()\n const chunks: Array<Uint8Array> = []\n let total = 0\n try {\n let result = await reader.read()\n while (!result.done) {\n chunks.push(result.value)\n total += result.value.byteLength\n result = await reader.read()\n }\n } finally {\n reader.releaseLock()\n }\n const merged = new Uint8Array(total)\n let offset = 0\n for (const chunk of chunks) {\n merged.set(chunk, offset)\n offset += chunk.byteLength\n }\n return merged.buffer.slice(\n merged.byteOffset,\n merged.byteOffset + merged.byteLength,\n )\n}\n\n/**\n * Decode a `data:` URL into a Blob for upload to the ElevenLabs STT API\n * (which only accepts multipart files or https URLs). Supports base64 and\n * URL-encoded payloads. Returns `undefined` for non-data-URL strings so the\n * caller can fall through to treating the input as an https URL.\n */\nexport function dataUrlToBlob(value: string): Blob | undefined {\n if (!value.startsWith('data:')) return undefined\n const commaIndex = value.indexOf(',')\n if (commaIndex === -1) return undefined\n\n const header = value.slice(5, commaIndex)\n const payload = value.slice(commaIndex + 1)\n const isBase64 = /;base64$/i.test(header)\n const mimeType = header.split(';')[0] || 'application/octet-stream'\n\n if (isBase64) {\n const binary = atob(payload)\n const bytes = new Uint8Array(binary.length)\n for (let i = 0; i < binary.length; i += 1) {\n bytes[i] = binary.charCodeAt(i)\n }\n return new Blob([bytes], { type: mimeType })\n }\n\n return new Blob([decodeURIComponent(payload)], { type: mimeType })\n}\n\n/**\n * Break an ElevenLabs `output_format` string (`mp3_44100_128`,\n * `pcm_24000`, `opus_48000_64`, `ulaw_8000`, ...) into a file extension and\n * content-type suitable for `TTSResult` / `AudioGenerationResult` consumers.\n *\n * Unknown codecs fall back to `mp3` / `audio/mpeg` because the ElevenLabs\n * default is `mp3_44100_128` — mispredicting on an exotic format is safer\n * than throwing in the adapter.\n */\nexport function parseOutputFormat(fmt: ElevenLabsOutputFormat | undefined): {\n format: string\n contentType: string\n} {\n const codec = (fmt || 'mp3_44100_128').split('_')[0]?.toLowerCase()\n switch (codec) {\n case 'mp3':\n return { format: 'mp3', contentType: 'audio/mpeg' }\n case 'pcm':\n return { format: 'pcm', contentType: 'audio/pcm' }\n case 'opus':\n return { format: 'opus', contentType: 'audio/opus' }\n case 'ulaw':\n return { format: 'ulaw', contentType: 'audio/basic' }\n case 'alaw':\n return { format: 'alaw', contentType: 'audio/x-alaw-basic' }\n default:\n return { format: 'mp3', contentType: 'audio/mpeg' }\n }\n}\n"],"names":["sharedGenerateId"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tanstack/ai-elevenlabs",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "ElevenLabs adapter for TanStack AI realtime voice",
5
5
  "author": "",
6
6
  "license": "MIT",
@@ -39,16 +39,17 @@
39
39
  ],
40
40
  "dependencies": {
41
41
  "@elevenlabs/client": "^1.3.1",
42
- "@elevenlabs/elevenlabs-js": "^2.44.0"
42
+ "@elevenlabs/elevenlabs-js": "^2.44.0",
43
+ "@tanstack/ai-utils": "0.2.0"
43
44
  },
44
45
  "peerDependencies": {
45
- "@tanstack/ai": "^0.14.0",
46
- "@tanstack/ai-client": "^0.8.0"
46
+ "@tanstack/ai": "^0.15.0",
47
+ "@tanstack/ai-client": "^0.9.0"
47
48
  },
48
49
  "devDependencies": {
49
50
  "@vitest/coverage-v8": "4.0.14",
50
- "@tanstack/ai": "0.14.0",
51
- "@tanstack/ai-client": "0.8.0"
51
+ "@tanstack/ai": "0.15.0",
52
+ "@tanstack/ai-client": "0.9.0"
52
53
  },
53
54
  "scripts": {
54
55
  "build": "vite build",
@@ -1,4 +1,8 @@
1
1
  import { ElevenLabsClient } from '@elevenlabs/elevenlabs-js'
2
+ import {
3
+ getApiKeyFromEnv,
4
+ generateId as sharedGenerateId,
5
+ } from '@tanstack/ai-utils'
2
6
  import type { ElevenLabsOutputFormat } from '../model-meta'
3
7
 
4
8
  /**
@@ -39,14 +43,7 @@ function getEnvironment(): EnvObject | undefined {
39
43
  }
40
44
 
41
45
  export function getElevenLabsApiKeyFromEnv(): string {
42
- const key = getEnvironment()?.ELEVENLABS_API_KEY
43
- if (!key) {
44
- throw new Error(
45
- 'ELEVENLABS_API_KEY is required. Please set it in your environment ' +
46
- 'variables or pass it explicitly to the adapter factory.',
47
- )
48
- }
49
- return key
46
+ return getApiKeyFromEnv('ELEVENLABS_API_KEY')
50
47
  }
51
48
 
52
49
  export function getElevenLabsAgentIdFromEnv(): string {
@@ -80,9 +77,9 @@ export function createElevenLabsClient(
80
77
  })
81
78
  }
82
79
 
83
- export function generateId(prefix: string): string {
84
- return `${prefix}-${Date.now()}-${Math.random().toString(36).substring(2)}`
85
- }
80
+ // Re-exported from `@tanstack/ai-utils` so existing callers keep working
81
+ // while the implementation stays deduped across provider packages.
82
+ export const generateId = sharedGenerateId
86
83
 
87
84
  /**
88
85
  * Convert an ArrayBuffer to base64 in a cross-runtime way.