@juspay/neurolink 9.66.0 → 9.67.0

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.
Files changed (60) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/README.md +12 -12
  3. package/dist/avatar/index.d.ts +13 -0
  4. package/dist/avatar/index.js +72 -0
  5. package/dist/browser/neurolink.min.js +357 -357
  6. package/dist/core/baseProvider.js +49 -8
  7. package/dist/factories/providerRegistry.js +23 -0
  8. package/dist/index.d.ts +10 -1
  9. package/dist/index.js +36 -1
  10. package/dist/lib/avatar/index.d.ts +13 -0
  11. package/dist/lib/avatar/index.js +72 -0
  12. package/dist/lib/core/baseProvider.js +49 -8
  13. package/dist/lib/factories/providerRegistry.js +23 -0
  14. package/dist/lib/files/fileTools.d.ts +1 -1
  15. package/dist/lib/index.d.ts +10 -1
  16. package/dist/lib/index.js +36 -1
  17. package/dist/lib/music/index.d.ts +14 -0
  18. package/dist/lib/music/index.js +80 -0
  19. package/dist/lib/types/avatar.d.ts +8 -1
  20. package/dist/lib/types/multimodal.d.ts +20 -7
  21. package/dist/lib/types/music.d.ts +8 -1
  22. package/dist/lib/types/tts.d.ts +9 -1
  23. package/dist/lib/utils/avatarProcessor.d.ts +7 -1
  24. package/dist/lib/utils/avatarProcessor.js +6 -0
  25. package/dist/lib/utils/musicProcessor.d.ts +7 -1
  26. package/dist/lib/utils/musicProcessor.js +6 -0
  27. package/dist/lib/utils/parameterValidation.js +5 -1
  28. package/dist/lib/utils/sttProcessor.d.ts +5 -3
  29. package/dist/lib/utils/sttProcessor.js +4 -2
  30. package/dist/lib/utils/ttsProcessor.d.ts +6 -3
  31. package/dist/lib/utils/ttsProcessor.js +5 -2
  32. package/dist/lib/voice/RealtimeVoiceAPI.d.ts +5 -2
  33. package/dist/lib/voice/RealtimeVoiceAPI.js +4 -1
  34. package/dist/lib/voice/index.d.ts +23 -0
  35. package/dist/lib/voice/index.js +124 -2
  36. package/dist/lib/voice/providers/CartesiaTTS.d.ts +31 -0
  37. package/dist/lib/voice/providers/CartesiaTTS.js +189 -0
  38. package/dist/lib/workflow/config.d.ts +3 -3
  39. package/dist/music/index.d.ts +14 -0
  40. package/dist/music/index.js +80 -0
  41. package/dist/types/avatar.d.ts +8 -1
  42. package/dist/types/multimodal.d.ts +20 -7
  43. package/dist/types/music.d.ts +8 -1
  44. package/dist/types/tts.d.ts +9 -1
  45. package/dist/utils/avatarProcessor.d.ts +7 -1
  46. package/dist/utils/avatarProcessor.js +6 -0
  47. package/dist/utils/musicProcessor.d.ts +7 -1
  48. package/dist/utils/musicProcessor.js +6 -0
  49. package/dist/utils/parameterValidation.js +5 -1
  50. package/dist/utils/sttProcessor.d.ts +5 -3
  51. package/dist/utils/sttProcessor.js +4 -2
  52. package/dist/utils/ttsProcessor.d.ts +6 -3
  53. package/dist/utils/ttsProcessor.js +5 -2
  54. package/dist/voice/RealtimeVoiceAPI.d.ts +5 -2
  55. package/dist/voice/RealtimeVoiceAPI.js +4 -1
  56. package/dist/voice/index.d.ts +23 -0
  57. package/dist/voice/index.js +124 -2
  58. package/dist/voice/providers/CartesiaTTS.d.ts +31 -0
  59. package/dist/voice/providers/CartesiaTTS.js +188 -0
  60. package/package.json +65 -2
@@ -0,0 +1,189 @@
1
+ /**
2
+ * Cartesia TTS Handler (synchronous /tts/bytes endpoint)
3
+ *
4
+ * Implements the standard `TTSHandler` synchronous-request contract on top
5
+ * of Cartesia's REST `/tts/bytes` endpoint. The pre-existing
6
+ * `adapters/tts/cartesiaHandler.ts` (`CartesiaStream`) targets the
7
+ * realtime WebSocket flow used by the voice server and does NOT implement
8
+ * `TTSHandler`; this file fills the gap so `nl.generate({ tts: { provider:
9
+ * "cartesia" } })` works through the same `TTSProcessor` dispatch as
10
+ * every other shipped TTS provider.
11
+ *
12
+ * @module voice/providers/CartesiaTTS
13
+ * @see https://docs.cartesia.ai/api-reference/tts/bytes
14
+ */
15
+ import { ErrorCategory, ErrorSeverity } from "../../constants/enums.js";
16
+ import { withTimeout, TimeoutError } from "../../utils/async/withTimeout.js";
17
+ import { logger } from "../../utils/logger.js";
18
+ import { TTS_ERROR_CODES, TTSError } from "../../utils/ttsProcessor.js";
19
+ const DEFAULT_BASE_URL = "https://api.cartesia.ai";
20
+ const DEFAULT_API_VERSION = "2025-04-16";
21
+ const DEFAULT_MODEL = "sonic-2";
22
+ // Same default voice as the streaming handler — a publicly available
23
+ // Cartesia voice id ("Bright Female"). Override per-call via TTSOptions.voice.
24
+ const DEFAULT_VOICE_ID = "694f9389-aac1-45b6-b726-9d9369183238";
25
+ const REQUEST_TIMEOUT_MS = 30_000;
26
+ /**
27
+ * Cartesia synchronous TTS handler.
28
+ *
29
+ * Auth: `X-API-Key: ${CARTESIA_API_KEY}` + `Cartesia-Version` header.
30
+ */
31
+ export class CartesiaTTS {
32
+ maxTextLength = 5000;
33
+ apiKey;
34
+ baseUrl;
35
+ apiVersion;
36
+ constructor(apiKey) {
37
+ const resolved = (apiKey ?? process.env.CARTESIA_API_KEY ?? "").trim();
38
+ this.apiKey = resolved.length > 0 ? resolved : null;
39
+ this.baseUrl = (process.env.CARTESIA_BASE_URL ?? DEFAULT_BASE_URL).replace(/\/$/, "");
40
+ this.apiVersion = process.env.CARTESIA_API_VERSION ?? DEFAULT_API_VERSION;
41
+ }
42
+ isConfigured() {
43
+ return this.apiKey !== null;
44
+ }
45
+ async synthesize(text, options = {}) {
46
+ if (!this.apiKey) {
47
+ throw new TTSError({
48
+ code: TTS_ERROR_CODES.PROVIDER_NOT_CONFIGURED,
49
+ message: "CARTESIA_API_KEY not configured",
50
+ category: ErrorCategory.CONFIGURATION,
51
+ severity: ErrorSeverity.HIGH,
52
+ retriable: false,
53
+ });
54
+ }
55
+ const startTime = Date.now();
56
+ const voiceId = options.voice ?? process.env.CARTESIA_VOICE_ID ?? DEFAULT_VOICE_ID;
57
+ const requestedFormat = options.format ?? "mp3";
58
+ const { container, encoding, sampleRate } = this.mapOutputFormat(requestedFormat);
59
+ const cartesiaOpts = options;
60
+ const model = cartesiaOpts.model ?? process.env.CARTESIA_MODEL ?? DEFAULT_MODEL;
61
+ const body = {
62
+ model_id: model,
63
+ transcript: text,
64
+ voice: { mode: "id", id: voiceId },
65
+ output_format: {
66
+ container,
67
+ encoding,
68
+ sample_rate: sampleRate,
69
+ },
70
+ language: cartesiaOpts.language ?? "en",
71
+ };
72
+ let response;
73
+ try {
74
+ response = await withTimeout(fetch(`${this.baseUrl}/tts/bytes`, {
75
+ method: "POST",
76
+ headers: {
77
+ "X-API-Key": this.apiKey,
78
+ "Cartesia-Version": this.apiVersion,
79
+ "Content-Type": "application/json",
80
+ },
81
+ body: JSON.stringify(body),
82
+ }), REQUEST_TIMEOUT_MS, `Cartesia request timed out after ${REQUEST_TIMEOUT_MS / 1000}s`);
83
+ }
84
+ catch (err) {
85
+ if (err instanceof TimeoutError) {
86
+ throw new TTSError({
87
+ code: TTS_ERROR_CODES.SYNTHESIS_FAILED,
88
+ message: err.message,
89
+ category: ErrorCategory.NETWORK,
90
+ severity: ErrorSeverity.HIGH,
91
+ retriable: true,
92
+ originalError: err,
93
+ });
94
+ }
95
+ throw new TTSError({
96
+ code: TTS_ERROR_CODES.SYNTHESIS_FAILED,
97
+ message: `Cartesia network error: ${err instanceof Error ? err.message : String(err)}`,
98
+ category: ErrorCategory.NETWORK,
99
+ severity: ErrorSeverity.HIGH,
100
+ retriable: true,
101
+ originalError: err instanceof Error ? err : undefined,
102
+ });
103
+ }
104
+ if (!response.ok) {
105
+ const text = await response.text();
106
+ const retriable = response.status === 408 ||
107
+ response.status === 429 ||
108
+ response.status >= 500;
109
+ throw new TTSError({
110
+ code: TTS_ERROR_CODES.SYNTHESIS_FAILED,
111
+ message: `Cartesia synthesis failed: ${response.status} — ${text}`,
112
+ category: retriable ? ErrorCategory.NETWORK : ErrorCategory.EXECUTION,
113
+ severity: ErrorSeverity.HIGH,
114
+ retriable,
115
+ context: { status: response.status, voiceId, container, encoding },
116
+ });
117
+ }
118
+ const arrayBuffer = await response.arrayBuffer();
119
+ const audioBuffer = Buffer.from(arrayBuffer);
120
+ const latency = Date.now() - startTime;
121
+ const effectiveFormat = this.effectiveFormat(container, encoding);
122
+ const result = {
123
+ buffer: audioBuffer,
124
+ format: effectiveFormat,
125
+ size: audioBuffer.length,
126
+ voice: voiceId,
127
+ sampleRate,
128
+ metadata: {
129
+ latency,
130
+ provider: "cartesia",
131
+ model,
132
+ requestedFormat: options.format,
133
+ container,
134
+ encoding,
135
+ },
136
+ };
137
+ logger.info(`[CartesiaTTS] Synthesized ${audioBuffer.length} bytes in ${latency}ms`);
138
+ return result;
139
+ }
140
+ mapOutputFormat(format) {
141
+ switch (format) {
142
+ case "mp3":
143
+ return { container: "mp3", encoding: "mp3", sampleRate: 44_100 };
144
+ case "wav":
145
+ return { container: "wav", encoding: "pcm_s16le", sampleRate: 44_100 };
146
+ case "pcm16":
147
+ return { container: "raw", encoding: "pcm_s16le", sampleRate: 24_000 };
148
+ default:
149
+ // Cartesia only supports mp3 / wav / pcm16 today. Fail fast instead
150
+ // of silently downgrading so callers passing ogg / flac / m4a /
151
+ // opus / webm see a clear error rather than mislabeled MP3 bytes.
152
+ throw new TTSError({
153
+ code: TTS_ERROR_CODES.SYNTHESIS_FAILED,
154
+ message: `Cartesia does not support output format "${format}". Supported: mp3, wav, pcm16.`,
155
+ category: ErrorCategory.VALIDATION,
156
+ severity: ErrorSeverity.MEDIUM,
157
+ retriable: false,
158
+ context: {
159
+ format,
160
+ supported: ["mp3", "wav", "pcm16"],
161
+ },
162
+ });
163
+ }
164
+ }
165
+ effectiveFormat(container, encoding) {
166
+ if (container === "mp3") {
167
+ return "mp3";
168
+ }
169
+ if (container === "wav") {
170
+ return "wav";
171
+ }
172
+ if (encoding === "pcm_s16le") {
173
+ return "pcm16";
174
+ }
175
+ // In practice mapOutputFormat() throws before we reach this branch
176
+ // (it only emits mp3/wav/raw containers from a validated input).
177
+ // Throwing here too means a future container/encoding combination
178
+ // surfaces clearly instead of returning mislabeled bytes as "mp3".
179
+ throw new TTSError({
180
+ code: TTS_ERROR_CODES.SYNTHESIS_FAILED,
181
+ message: `Unsupported Cartesia output combination: container=${container}, encoding=${encoding}`,
182
+ category: ErrorCategory.EXECUTION,
183
+ severity: ErrorSeverity.HIGH,
184
+ retriable: false,
185
+ context: { container, encoding },
186
+ });
187
+ }
188
+ }
189
+ //# sourceMappingURL=CartesiaTTS.js.map
@@ -41,9 +41,9 @@ export declare const JudgeConfigSchema: z.ZodObject<{
41
41
  criteria: z.ZodArray<z.ZodString>;
42
42
  outputFormat: z.ZodEnum<{
43
43
  scores: "scores";
44
+ detailed: "detailed";
44
45
  ranking: "ranking";
45
46
  best: "best";
46
- detailed: "detailed";
47
47
  }>;
48
48
  customPrompt: z.ZodOptional<z.ZodString>;
49
49
  systemPrompt: z.ZodOptional<z.ZodString>;
@@ -195,9 +195,9 @@ export declare const WorkflowConfigSchema: z.ZodObject<{
195
195
  criteria: z.ZodArray<z.ZodString>;
196
196
  outputFormat: z.ZodEnum<{
197
197
  scores: "scores";
198
+ detailed: "detailed";
198
199
  ranking: "ranking";
199
200
  best: "best";
200
- detailed: "detailed";
201
201
  }>;
202
202
  customPrompt: z.ZodOptional<z.ZodString>;
203
203
  systemPrompt: z.ZodOptional<z.ZodString>;
@@ -219,9 +219,9 @@ export declare const WorkflowConfigSchema: z.ZodObject<{
219
219
  criteria: z.ZodArray<z.ZodString>;
220
220
  outputFormat: z.ZodEnum<{
221
221
  scores: "scores";
222
+ detailed: "detailed";
222
223
  ranking: "ranking";
223
224
  best: "best";
224
- detailed: "detailed";
225
225
  }>;
226
226
  customPrompt: z.ZodOptional<z.ZodString>;
227
227
  systemPrompt: z.ZodOptional<z.ZodString>;
@@ -7,7 +7,21 @@
7
7
  * Use `MusicProcessor.generate(provider, options)` to dispatch to the
8
8
  * registered handler for `provider`.
9
9
  *
10
+ * Importing this module also auto-registers every shipped music handler
11
+ * whose backing API key is present in `process.env`. Registration is
12
+ * idempotent and silently skipped if a provider is already registered or
13
+ * its constructor throws (e.g. missing optional native dependency).
14
+ *
10
15
  * @module music
11
16
  */
12
17
  export { MUSIC_ERROR_CODES, MusicError, MusicProcessor, } from "../utils/musicProcessor.js";
13
18
  export { BeatovenMusic, BeatovenMusic as BeatovenMusicHandler, } from "./providers/BeatovenMusic.js";
19
+ export { ElevenLabsMusic, ElevenLabsMusic as ElevenLabsMusicHandler, } from "./providers/ElevenLabsMusic.js";
20
+ export { LyriaMusic, LyriaMusic as LyriaMusicHandler, } from "./providers/LyriaMusic.js";
21
+ export { ReplicateMusic, ReplicateMusic as ReplicateMusicHandler, } from "./providers/ReplicateMusic.js";
22
+ /**
23
+ * Register every shipped music handler whose backing credentials are
24
+ * present in the environment. Safe to call multiple times — existing
25
+ * registrations are preserved.
26
+ */
27
+ export declare function registerDefaultMusicHandlers(): void;
@@ -7,7 +7,87 @@
7
7
  * Use `MusicProcessor.generate(provider, options)` to dispatch to the
8
8
  * registered handler for `provider`.
9
9
  *
10
+ * Importing this module also auto-registers every shipped music handler
11
+ * whose backing API key is present in `process.env`. Registration is
12
+ * idempotent and silently skipped if a provider is already registered or
13
+ * its constructor throws (e.g. missing optional native dependency).
14
+ *
10
15
  * @module music
11
16
  */
17
+ import { logger } from "../utils/logger.js";
18
+ import { MusicProcessor } from "../utils/musicProcessor.js";
12
19
  export { MUSIC_ERROR_CODES, MusicError, MusicProcessor, } from "../utils/musicProcessor.js";
20
+ // ============================================================================
21
+ // HANDLER CLASSES
22
+ // ============================================================================
13
23
  export { BeatovenMusic, BeatovenMusic as BeatovenMusicHandler, } from "./providers/BeatovenMusic.js";
24
+ export { ElevenLabsMusic, ElevenLabsMusic as ElevenLabsMusicHandler, } from "./providers/ElevenLabsMusic.js";
25
+ export { LyriaMusic, LyriaMusic as LyriaMusicHandler, } from "./providers/LyriaMusic.js";
26
+ export { ReplicateMusic, ReplicateMusic as ReplicateMusicHandler, } from "./providers/ReplicateMusic.js";
27
+ // ============================================================================
28
+ // AUTO-REGISTRATION
29
+ // ============================================================================
30
+ import { BeatovenMusic } from "./providers/BeatovenMusic.js";
31
+ import { ElevenLabsMusic } from "./providers/ElevenLabsMusic.js";
32
+ import { LyriaMusic } from "./providers/LyriaMusic.js";
33
+ import { ReplicateMusic } from "./providers/ReplicateMusic.js";
34
+ const MUSIC_HANDLER_CANDIDATES = [
35
+ { name: "beatoven", factory: () => new BeatovenMusic() },
36
+ {
37
+ name: "elevenlabs-music",
38
+ aliases: ["elevenlabs-sound"],
39
+ factory: () => new ElevenLabsMusic(),
40
+ },
41
+ { name: "lyria", factory: () => new LyriaMusic() },
42
+ {
43
+ name: "replicate",
44
+ aliases: ["musicgen"],
45
+ factory: () => new ReplicateMusic(),
46
+ },
47
+ ];
48
+ /**
49
+ * Register every shipped music handler whose backing credentials are
50
+ * present in the environment. Safe to call multiple times — existing
51
+ * registrations are preserved.
52
+ */
53
+ export function registerDefaultMusicHandlers() {
54
+ for (const { name, aliases, factory } of MUSIC_HANDLER_CANDIDATES) {
55
+ // Compute missingName / missingAliases separately so a pre-registered
56
+ // primary doesn't block alias backfill — keeps "musicgen" reachable
57
+ // when only "replicate" was wired up via another path (and likewise
58
+ // "elevenlabs-sound" vs "elevenlabs-music").
59
+ const missingName = !MusicProcessor.supports(name);
60
+ const missingAliases = (aliases ?? []).filter((alias) => !MusicProcessor.supports(alias));
61
+ if (!missingName && missingAliases.length === 0) {
62
+ continue;
63
+ }
64
+ try {
65
+ // Reuse the already-registered primary's handler for alias backfill
66
+ // when one exists — wiring an alias to a factory-fresh instance
67
+ // would silently diverge from the canonical primary's config.
68
+ let handler;
69
+ if (!missingName) {
70
+ handler = MusicProcessor.getHandler(name);
71
+ }
72
+ if (!handler) {
73
+ handler = factory();
74
+ if (!handler.isConfigured()) {
75
+ continue;
76
+ }
77
+ }
78
+ if (missingName) {
79
+ MusicProcessor.registerHandler(name, handler);
80
+ }
81
+ for (const alias of missingAliases) {
82
+ MusicProcessor.registerHandler(alias, handler);
83
+ }
84
+ }
85
+ catch (err) {
86
+ logger.debug(`[music] ${name} auto-registration skipped: ${err instanceof Error ? err.message : String(err)}`);
87
+ }
88
+ }
89
+ }
90
+ // Run once at module import so consumers who follow the documented
91
+ // `nl.generate(...)` flow get every configured handler without manually
92
+ // calling `registerHandler`.
93
+ registerDefaultMusicHandlers();
@@ -20,6 +20,13 @@ export type AvatarVideoFormat = "mp4" | "webm" | "mov";
20
20
  * - MuseTalk (Replicate): single quality only; "hd" is no-op
21
21
  */
22
22
  export type AvatarQuality = "standard" | "hd";
23
+ /**
24
+ * Known avatar provider identifiers shipped with NeuroLink.
25
+ *
26
+ * `(string & {})` keeps the union open for custom provider names
27
+ * registered via `AvatarProcessor.registerHandler()`.
28
+ */
29
+ export type AvatarProviderName = "d-id" | "heygen" | "replicate" | "musetalk" | (string & {});
23
30
  /**
24
31
  * Options for avatar video generation.
25
32
  */
@@ -42,7 +49,7 @@ export type AvatarOptions = {
42
49
  /** Voice id passed through to the TTS provider when `text` is used. */
43
50
  voice?: string;
44
51
  /** Avatar provider override (e.g. "d-id", "heygen", "replicate"). */
45
- provider?: string;
52
+ provider?: AvatarProviderName;
46
53
  /** Output quality preset. */
47
54
  quality?: AvatarQuality;
48
55
  /** Output format (default: "mp4"). */
@@ -124,6 +124,13 @@ export type AudioContent = {
124
124
  language?: string;
125
125
  };
126
126
  };
127
+ /**
128
+ * Known video provider identifiers shipped with NeuroLink.
129
+ *
130
+ * `(string & {})` keeps the union open for custom provider names
131
+ * registered via `VideoProcessor.registerHandler()`.
132
+ */
133
+ export type VideoProviderName = "vertex" | "kling" | "runway" | "replicate" | (string & {});
127
134
  /**
128
135
  * Video output configuration options for video generation
129
136
  *
@@ -148,14 +155,15 @@ export type VideoOutputOptions = {
148
155
  */
149
156
  abortSignal?: AbortSignal;
150
157
  /**
151
- * Override the video-gen provider. Defaults to "vertex" or to the LLM
152
- * provider name if it is also a registered video handler.
158
+ * Override the video-gen provider. Defaults to `"vertex"` when omitted.
153
159
  *
154
160
  * Registered providers are managed via `VideoProcessor.registerHandler`
155
- * (see src/lib/utils/videoProcessor.ts). Examples: "vertex", "kling",
156
- * "runway", "replicate".
161
+ * (see src/lib/utils/videoProcessor.ts). Examples: `"vertex"`, `"kling"`,
162
+ * `"runway"`, `"replicate"`. An unknown provider throws
163
+ * `VIDEO_ERROR_CODES.PROVIDER_NOT_SUPPORTED` — there is no implicit
164
+ * fallback to the LLM provider name.
157
165
  */
158
- provider?: string;
166
+ provider?: VideoProviderName;
159
167
  /**
160
168
  * Specific model to use within the provider. Provider-specific shape
161
169
  * (e.g. "veo-3.1-generate-001" for vertex; "atonamy/wan-alpha:..." for
@@ -164,8 +172,13 @@ export type VideoOutputOptions = {
164
172
  model?: string;
165
173
  /** Output resolution - "720p" (1280x720) or "1080p" (1920x1080) */
166
174
  resolution?: "720p" | "1080p";
167
- /** Video duration in seconds (4, 6, or 8 seconds supported) */
168
- length?: 4 | 6 | 8;
175
+ /**
176
+ * Video duration in seconds. Provider-specific support — Vertex Veo
177
+ * accepts 4 / 6 / 8 s, Kling and Runway accept 5 / 10 s, Replicate is
178
+ * model-specific. The type intentionally enumerates the common shipped
179
+ * values; pass any other positive number for custom Replicate models.
180
+ */
181
+ length?: 4 | 5 | 6 | 8 | 10 | (number & {});
169
182
  /** Aspect ratio - "9:16" for portrait, "16:9" for landscape, "1:1" for square */
170
183
  aspectRatio?: "9:16" | "16:9" | "1:1";
171
184
  /** Enable audio generation (default: true) */
@@ -27,6 +27,13 @@ export type MusicGenre = string;
27
27
  * "mysterious", "romantic", "epic".
28
28
  */
29
29
  export type MusicMood = string;
30
+ /**
31
+ * Known music provider identifiers shipped with NeuroLink.
32
+ *
33
+ * `(string & {})` keeps the union open for custom provider names
34
+ * registered via `MusicProcessor.registerHandler()`.
35
+ */
36
+ export type MusicProviderName = "beatoven" | "elevenlabs-music" | "elevenlabs-sound" | "lyria" | "replicate" | "musicgen" | (string & {});
30
37
  /**
31
38
  * Options for music generation requests.
32
39
  */
@@ -44,7 +51,7 @@ export type MusicOptions = {
44
51
  /** Tempo in BPM (provider-specific support). */
45
52
  tempo?: number;
46
53
  /** Override the music provider (e.g. "beatoven", "elevenlabs-music", "lyria", "replicate"). */
47
- provider?: string;
54
+ provider?: MusicProviderName;
48
55
  /** Reference audio for melody / style guidance (Buffer or path). */
49
56
  referenceAudio?: Buffer | string;
50
57
  /** Output file path (optional — buffer is always returned in result). */
@@ -17,6 +17,14 @@ export type TTSAudioFormat = "mp3" | "wav" | "ogg" | "opus" | "m4a" | "flac" | "
17
17
  * TTS quality settings
18
18
  */
19
19
  export type TTSQuality = "standard" | "hd";
20
+ /**
21
+ * Known TTS provider identifiers shipped with NeuroLink.
22
+ *
23
+ * The `(string & {})` intersection keeps the union open for custom
24
+ * provider names registered via `TTSProcessor.registerHandler()` while
25
+ * still surfacing the built-in choices in editor autocomplete.
26
+ */
27
+ export type TTSProviderName = "google-ai" | "vertex" | "openai-tts" | "elevenlabs" | "elevenlabs-tts" | "azure-tts" | "fish-audio" | "cartesia" | (string & {});
20
28
  /**
21
29
  * TTS configuration options
22
30
  */
@@ -69,7 +77,7 @@ export type TTSOptions = {
69
77
  /** Auto-play audio after generation (default: false) */
70
78
  play?: boolean;
71
79
  /** Override TTS provider (e.g., "elevenlabs", "openai-tts", "azure-tts") */
72
- provider?: string;
80
+ provider?: TTSProviderName;
73
81
  };
74
82
  /**
75
83
  * TTS audio result returned from generation
@@ -56,7 +56,13 @@ export declare class AvatarProcessor {
56
56
  * List the names of all registered providers.
57
57
  */
58
58
  static listProviders(): string[];
59
- private static getHandler;
59
+ /**
60
+ * Get a registered avatar handler by provider name.
61
+ *
62
+ * Exposed publicly so module-level auto-registration code can reuse an
63
+ * already-registered primary handler when backfilling its aliases.
64
+ */
65
+ static getHandler(providerName: string): AvatarHandler | undefined;
60
66
  private static buildSpanAttributes;
61
67
  /**
62
68
  * Generate an avatar video via the registered handler.
@@ -80,6 +80,12 @@ export class AvatarProcessor {
80
80
  static listProviders() {
81
81
  return Array.from(this.handlers.keys());
82
82
  }
83
+ /**
84
+ * Get a registered avatar handler by provider name.
85
+ *
86
+ * Exposed publicly so module-level auto-registration code can reuse an
87
+ * already-registered primary handler when backfilling its aliases.
88
+ */
83
89
  static getHandler(providerName) {
84
90
  return this.handlers.get(providerName.toLowerCase());
85
91
  }
@@ -55,7 +55,13 @@ export declare class MusicProcessor {
55
55
  * List the names of all registered providers.
56
56
  */
57
57
  static listProviders(): string[];
58
- private static getHandler;
58
+ /**
59
+ * Get a registered music handler by provider name.
60
+ *
61
+ * Exposed publicly so module-level auto-registration code can reuse an
62
+ * already-registered primary handler when backfilling its aliases.
63
+ */
64
+ static getHandler(providerName: string): MusicHandler | undefined;
59
65
  private static buildSpanAttributes;
60
66
  /**
61
67
  * Generate a music track via the registered handler.
@@ -79,6 +79,12 @@ export class MusicProcessor {
79
79
  static listProviders() {
80
80
  return Array.from(this.handlers.keys());
81
81
  }
82
+ /**
83
+ * Get a registered music handler by provider name.
84
+ *
85
+ * Exposed publicly so module-level auto-registration code can reuse an
86
+ * already-registered primary handler when backfilling its aliases.
87
+ */
82
88
  static getHandler(providerName) {
83
89
  return this.handlers.get(providerName.toLowerCase());
84
90
  }
@@ -435,7 +435,11 @@ function toValidationError(error) {
435
435
  * Valid video generation options
436
436
  */
437
437
  const VALID_VIDEO_RESOLUTIONS = ["720p", "1080p"];
438
- const VALID_VIDEO_LENGTHS = [4, 6, 8];
438
+ // Cross-provider literal whitelist: Vertex Veo uses 4 / 6 / 8 s, Kling and
439
+ // Runway use 5 / 10 s. The handler-level adapter is the source of truth
440
+ // for per-provider rejection (e.g. Runway 400 for length=4); this gate
441
+ // just rejects obviously invalid integers.
442
+ const VALID_VIDEO_LENGTHS = [4, 5, 6, 8, 10];
439
443
  const VALID_VIDEO_ASPECT_RATIOS = ["9:16", "16:9"];
440
444
  const MAX_VIDEO_PROMPT_LENGTH = 500;
441
445
  const MAX_VIDEO_IMAGE_SIZE = 10 * 1024 * 1024; // 10MB
@@ -63,13 +63,15 @@ export declare class STTProcessor {
63
63
  */
64
64
  static registerHandler(providerName: string, handler: STTHandler): void;
65
65
  /**
66
- * Get a registered STT handler by provider name
66
+ * Get a registered STT handler by provider name.
67
+ *
68
+ * Exposed publicly so module-level auto-registration code can reuse an
69
+ * already-registered primary handler when backfilling its aliases.
67
70
  *
68
- * @private
69
71
  * @param providerName - Provider identifier
70
72
  * @returns Handler instance or undefined if not registered
71
73
  */
72
- private static getHandler;
74
+ static getHandler(providerName: string): STTHandler | undefined;
73
75
  /**
74
76
  * Check if a provider is supported (has a registered STT handler)
75
77
  *
@@ -80,9 +80,11 @@ export class STTProcessor {
80
80
  logger.debug(`[STTProcessor] Registered STT handler for provider: ${normalizedName}`);
81
81
  }
82
82
  /**
83
- * Get a registered STT handler by provider name
83
+ * Get a registered STT handler by provider name.
84
+ *
85
+ * Exposed publicly so module-level auto-registration code can reuse an
86
+ * already-registered primary handler when backfilling its aliases.
84
87
  *
85
- * @private
86
88
  * @param providerName - Provider identifier
87
89
  * @returns Handler instance or undefined if not registered
88
90
  */
@@ -90,13 +90,16 @@ export declare class TTSProcessor {
90
90
  */
91
91
  static registerHandler(providerName: string, handler: TTSHandler): void;
92
92
  /**
93
- * Get a registered TTS handler by provider name
93
+ * Get a registered TTS handler by provider name.
94
+ *
95
+ * Exposed publicly so module-level auto-registration code can reuse an
96
+ * already-registered primary handler when backfilling its aliases —
97
+ * see `src/lib/voice/index.ts:registerDefaultTTSHandlers`.
94
98
  *
95
- * @private
96
99
  * @param providerName - Provider identifier
97
100
  * @returns Handler instance or undefined if not registered
98
101
  */
99
- private static getHandler;
102
+ static getHandler(providerName: string): TTSHandler | undefined;
100
103
  /**
101
104
  * Check if a provider is supported (has a registered TTS handler)
102
105
  *
@@ -107,9 +107,12 @@ export class TTSProcessor {
107
107
  logger.debug(`[TTSProcessor] Registered TTS handler for provider: ${normalizedName}`);
108
108
  }
109
109
  /**
110
- * Get a registered TTS handler by provider name
110
+ * Get a registered TTS handler by provider name.
111
+ *
112
+ * Exposed publicly so module-level auto-registration code can reuse an
113
+ * already-registered primary handler when backfilling its aliases —
114
+ * see `src/lib/voice/index.ts:registerDefaultTTSHandlers`.
111
115
  *
112
- * @private
113
116
  * @param providerName - Provider identifier
114
117
  * @returns Handler instance or undefined if not registered
115
118
  */
@@ -49,9 +49,12 @@ export declare class RealtimeProcessor {
49
49
  */
50
50
  static registerHandler(providerName: string, handler: RealtimeHandler): void;
51
51
  /**
52
- * Get a registered Realtime handler by provider name
52
+ * Get a registered Realtime handler by provider name.
53
+ *
54
+ * Exposed publicly so module-level auto-registration code can reuse an
55
+ * already-registered primary handler when backfilling its aliases.
53
56
  */
54
- private static getHandler;
57
+ static getHandler(providerName: string): RealtimeHandler | undefined;
55
58
  /**
56
59
  * Check if a provider is supported
57
60
  */
@@ -65,7 +65,10 @@ export class RealtimeProcessor {
65
65
  logger.debug(`[RealtimeProcessor] Registered Realtime handler for provider: ${normalizedName}`);
66
66
  }
67
67
  /**
68
- * Get a registered Realtime handler by provider name
68
+ * Get a registered Realtime handler by provider name.
69
+ *
70
+ * Exposed publicly so module-level auto-registration code can reuse an
71
+ * already-registered primary handler when backfilling its aliases.
69
72
  */
70
73
  static getHandler(providerName) {
71
74
  const normalizedName = providerName.toLowerCase();