@cartesia/cartesia-js 1.0.0-alpha.4 → 1.0.1

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 (56) hide show
  1. package/.turbo/turbo-build.log +49 -49
  2. package/CHANGELOG.md +23 -0
  3. package/LICENSE.md +21 -0
  4. package/README.md +102 -21
  5. package/dist/{chunk-VK7LBMVI.js → chunk-2NA5SEML.js} +2 -2
  6. package/dist/{chunk-PQ5EVEEH.js → chunk-5M33ZF3Y.js} +1 -1
  7. package/dist/{chunk-PQ6CIPFW.js → chunk-6YQ6KDIQ.js} +44 -5
  8. package/dist/{chunk-IQAXBRHU.js → chunk-ASZKHN7Q.js} +53 -29
  9. package/dist/{chunk-RO7TY474.js → chunk-BHY7MNGT.js} +11 -6
  10. package/dist/{chunk-WIFMLPT5.js → chunk-GHY2WEOK.js} +13 -0
  11. package/dist/{chunk-SGXUEFII.js → chunk-KUSVZXDT.js} +2 -2
  12. package/dist/{chunk-36JBKJUN.js → chunk-LZO6K34D.js} +20 -7
  13. package/dist/{chunk-3FL2SNIR.js → chunk-NQVZNVOU.js} +1 -1
  14. package/dist/{chunk-ISRU7PLL.js → chunk-OFH3ML4L.js} +3 -3
  15. package/dist/index.cjs +129 -39
  16. package/dist/index.d.cts +4 -4
  17. package/dist/index.d.ts +4 -4
  18. package/dist/index.js +15 -9
  19. package/dist/lib/client.js +2 -2
  20. package/dist/lib/constants.js +1 -1
  21. package/dist/lib/index.cjs +106 -33
  22. package/dist/lib/index.js +8 -8
  23. package/dist/react/index.cjs +231 -92
  24. package/dist/react/index.d.cts +4 -3
  25. package/dist/react/index.d.ts +4 -3
  26. package/dist/react/index.js +117 -64
  27. package/dist/react/utils.js +2 -2
  28. package/dist/tts/index.cjs +106 -33
  29. package/dist/tts/index.js +6 -6
  30. package/dist/tts/player.cjs +23 -5
  31. package/dist/tts/player.d.cts +6 -0
  32. package/dist/tts/player.d.ts +6 -0
  33. package/dist/tts/player.js +4 -3
  34. package/dist/tts/source.cjs +50 -4
  35. package/dist/tts/source.d.cts +16 -6
  36. package/dist/tts/source.d.ts +16 -6
  37. package/dist/tts/source.js +4 -2
  38. package/dist/tts/utils.cjs +18 -6
  39. package/dist/tts/utils.d.cts +7 -5
  40. package/dist/tts/utils.d.ts +7 -5
  41. package/dist/tts/utils.js +3 -2
  42. package/dist/tts/websocket.cjs +106 -33
  43. package/dist/tts/websocket.d.cts +20 -10
  44. package/dist/tts/websocket.d.ts +20 -10
  45. package/dist/tts/websocket.js +5 -5
  46. package/dist/types/index.d.cts +60 -4
  47. package/dist/types/index.d.ts +60 -4
  48. package/dist/voices/index.js +3 -3
  49. package/package.json +1 -1
  50. package/src/index.ts +2 -0
  51. package/src/react/index.ts +117 -62
  52. package/src/tts/player.ts +15 -8
  53. package/src/tts/source.ts +53 -7
  54. package/src/tts/utils.ts +26 -12
  55. package/src/tts/websocket.ts +42 -19
  56. package/src/types/index.ts +81 -3
@@ -22,6 +22,18 @@ var __spreadValues = (a, b) => {
22
22
  return a;
23
23
  };
24
24
  var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
25
+ var __objRest = (source, exclude) => {
26
+ var target = {};
27
+ for (var prop in source)
28
+ if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
29
+ target[prop] = source[prop];
30
+ if (source != null && __getOwnPropSymbols)
31
+ for (var prop of __getOwnPropSymbols(source)) {
32
+ if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
33
+ target[prop] = source[prop];
34
+ }
35
+ return target;
36
+ };
25
37
  var __export = (target, all) => {
26
38
  for (var name in all)
27
39
  __defProp(target, name, { get: all[name], enumerable: true });
@@ -135,7 +147,13 @@ var import_partysocket = require("partysocket");
135
147
 
136
148
  // src/tts/source.ts
137
149
  var import_emittery = __toESM(require("emittery"), 1);
138
- var _emitter, _buffer, _readIndex, _writeIndex, _closed, _sampleRate;
150
+ var ENCODING_MAP = {
151
+ pcm_f32le: { arrayType: Float32Array, bytesPerElement: 4 },
152
+ pcm_s16le: { arrayType: Int16Array, bytesPerElement: 2 },
153
+ pcm_alaw: { arrayType: Uint8Array, bytesPerElement: 1 },
154
+ pcm_mulaw: { arrayType: Uint8Array, bytesPerElement: 1 }
155
+ };
156
+ var _emitter, _buffer, _readIndex, _writeIndex, _closed, _sampleRate, _encoding, _container, _createBuffer, createBuffer_fn;
139
157
  var Source = class {
140
158
  /**
141
159
  * Create a new Source.
@@ -143,23 +161,44 @@ var Source = class {
143
161
  * @param options - Options for the Source.
144
162
  * @param options.sampleRate - The sample rate of the audio.
145
163
  */
146
- constructor({ sampleRate }) {
164
+ constructor({
165
+ sampleRate,
166
+ encoding,
167
+ container
168
+ }) {
169
+ /**
170
+ * Create a new buffer for the source.
171
+ *
172
+ * @param size - The size of the buffer to create.
173
+ * @returns The new buffer as a TypedArray based on the encoding.
174
+ */
175
+ __privateAdd(this, _createBuffer);
147
176
  __privateAdd(this, _emitter, new import_emittery.default());
148
177
  __privateAdd(this, _buffer, void 0);
149
178
  __privateAdd(this, _readIndex, 0);
150
179
  __privateAdd(this, _writeIndex, 0);
151
180
  __privateAdd(this, _closed, false);
152
181
  __privateAdd(this, _sampleRate, void 0);
182
+ __privateAdd(this, _encoding, void 0);
183
+ __privateAdd(this, _container, void 0);
153
184
  this.on = __privateGet(this, _emitter).on.bind(__privateGet(this, _emitter));
154
185
  this.once = __privateGet(this, _emitter).once.bind(__privateGet(this, _emitter));
155
186
  this.events = __privateGet(this, _emitter).events.bind(__privateGet(this, _emitter));
156
187
  this.off = __privateGet(this, _emitter).off.bind(__privateGet(this, _emitter));
157
188
  __privateSet(this, _sampleRate, sampleRate);
158
- __privateSet(this, _buffer, new Float32Array(1024));
189
+ __privateSet(this, _encoding, encoding);
190
+ __privateSet(this, _container, container);
191
+ __privateSet(this, _buffer, __privateMethod(this, _createBuffer, createBuffer_fn).call(this, 1024));
159
192
  }
160
193
  get sampleRate() {
161
194
  return __privateGet(this, _sampleRate);
162
195
  }
196
+ get encoding() {
197
+ return __privateGet(this, _encoding);
198
+ }
199
+ get container() {
200
+ return __privateGet(this, _container);
201
+ }
163
202
  /**
164
203
  * Append audio to the buffer.
165
204
  *
@@ -173,7 +212,7 @@ var Source = class {
173
212
  while (newCapacity < requiredCapacity) {
174
213
  newCapacity *= 2;
175
214
  }
176
- const newBuffer = new Float32Array(newCapacity);
215
+ const newBuffer = __privateMethod(this, _createBuffer, createBuffer_fn).call(this, newCapacity);
177
216
  newBuffer.set(__privateGet(this, _buffer));
178
217
  __privateSet(this, _buffer, newBuffer);
179
218
  }
@@ -221,6 +260,9 @@ var Source = class {
221
260
  get readIndex() {
222
261
  return __privateGet(this, _readIndex);
223
262
  }
263
+ get writeIndex() {
264
+ return __privateGet(this, _writeIndex);
265
+ }
224
266
  /**
225
267
  * Close the source. This signals that no more audio will be enqueued.
226
268
  *
@@ -242,19 +284,27 @@ _readIndex = new WeakMap();
242
284
  _writeIndex = new WeakMap();
243
285
  _closed = new WeakMap();
244
286
  _sampleRate = new WeakMap();
287
+ _encoding = new WeakMap();
288
+ _container = new WeakMap();
289
+ _createBuffer = new WeakSet();
290
+ createBuffer_fn = function(size) {
291
+ const { arrayType: ArrayType } = ENCODING_MAP[__privateGet(this, _encoding)];
292
+ return new ArrayType(size);
293
+ };
245
294
 
246
295
  // src/tts/utils.ts
247
296
  var import_base64_js = __toESM(require("base64-js"), 1);
248
- function base64ToArray(b64) {
297
+ function base64ToArray(b64, encoding) {
249
298
  const byteArrays = filterSentinel(b64).map((b) => import_base64_js.default.toByteArray(b));
299
+ const { arrayType: ArrayType, bytesPerElement } = ENCODING_MAP[encoding];
250
300
  const totalLength = byteArrays.reduce(
251
- (acc, arr) => acc + arr.length / Float32Array.BYTES_PER_ELEMENT,
301
+ (acc, arr) => acc + arr.length / bytesPerElement,
252
302
  0
253
303
  );
254
- const result = new Float32Array(totalLength);
304
+ const result = new ArrayType(totalLength);
255
305
  let offset = 0;
256
306
  for (const arr of byteArrays) {
257
- const floats = new Float32Array(arr.buffer);
307
+ const floats = new ArrayType(arr.buffer);
258
308
  result.set(floats, offset);
259
309
  offset += floats.length;
260
310
  }
@@ -285,10 +335,10 @@ function createMessageHandlerForContextId(contextId, handler) {
285
335
  let chunk;
286
336
  if (message.done) {
287
337
  chunk = getSentinel();
288
- } else {
338
+ } else if (message.type === "chunk") {
289
339
  chunk = message.data;
290
340
  }
291
- handler({ chunk, message: event.data });
341
+ handler({ chunk, message: event.data, data: message });
292
342
  };
293
343
  }
294
344
  function getSentinel() {
@@ -312,14 +362,14 @@ function getEmitteryCallbacks(emitter) {
312
362
  }
313
363
 
314
364
  // src/tts/websocket.ts
315
- var _isConnected, _sampleRate2, _generateId, generateId_fn;
365
+ var _isConnected, _sampleRate2, _container2, _encoding2, _generateId, generateId_fn;
316
366
  var WebSocket = class extends Client {
317
367
  /**
318
368
  * Create a new WebSocket client.
319
369
  *
320
370
  * @param args - Arguments to pass to the Client constructor.
321
371
  */
322
- constructor({ sampleRate }, ...args) {
372
+ constructor({ sampleRate, container, encoding }, ...args) {
323
373
  super(...args);
324
374
  /**
325
375
  * Generate a unique ID suitable for a streaming context.
@@ -332,37 +382,47 @@ var WebSocket = class extends Client {
332
382
  __privateAdd(this, _generateId);
333
383
  __privateAdd(this, _isConnected, false);
334
384
  __privateAdd(this, _sampleRate2, void 0);
385
+ __privateAdd(this, _container2, void 0);
386
+ __privateAdd(this, _encoding2, void 0);
335
387
  __privateSet(this, _sampleRate2, sampleRate);
388
+ __privateSet(this, _container2, container != null ? container : "raw");
389
+ __privateSet(this, _encoding2, encoding != null ? encoding : "pcm_f32le");
336
390
  }
337
391
  /**
338
- * Send a message over the WebSocket in order to start a stream.
392
+ * Send a message over the WebSocket to start a stream.
339
393
  *
340
- * @param inputs - Stream options.
394
+ * @param inputs - Stream options. Defined in the StreamRequest type.
341
395
  * @param options - Options for the stream.
342
396
  * @param options.timeout - The maximum time to wait for a chunk before cancelling the stream.
343
- * If `0`, the stream will not time out.
397
+ * If set to `0`, the stream will not time out.
344
398
  * @returns A Source object that can be passed to a Player to play the audio.
399
+ * @returns An Emittery instance that emits messages from the WebSocket.
400
+ * @returns An abort function that can be called to cancel the stream.
345
401
  */
346
- send(inputs, { timeout = 0 } = {}) {
347
- var _a, _b, _c, _d;
402
+ send(_a, { timeout = 0 } = {}) {
403
+ var inputs = __objRest(_a, []);
404
+ var _a2, _b, _c, _d;
348
405
  if (!__privateGet(this, _isConnected)) {
349
406
  throw new Error("Not connected to WebSocket. Call .connect() first.");
350
407
  }
351
- const contextId = __privateMethod(this, _generateId, generateId_fn).call(this);
352
- (_a = this.socket) == null ? void 0 : _a.send(
353
- JSON.stringify(__spreadProps(__spreadValues({
354
- context_id: contextId
355
- }, inputs), {
356
- output_format: {
357
- container: "raw",
358
- encoding: "pcm_f32le",
359
- sample_rate: __privateGet(this, _sampleRate2)
360
- }
361
- }))
408
+ if (!inputs.context_id) {
409
+ inputs.context_id = __privateMethod(this, _generateId, generateId_fn).call(this);
410
+ }
411
+ if (!inputs.output_format) {
412
+ inputs.output_format = {
413
+ container: __privateGet(this, _container2),
414
+ encoding: __privateGet(this, _encoding2),
415
+ sample_rate: __privateGet(this, _sampleRate2)
416
+ };
417
+ }
418
+ (_a2 = this.socket) == null ? void 0 : _a2.send(
419
+ JSON.stringify(__spreadValues({}, inputs))
362
420
  );
363
421
  const emitter = new import_emittery2.default();
364
422
  const source = new Source({
365
- sampleRate: __privateGet(this, _sampleRate2)
423
+ sampleRate: __privateGet(this, _sampleRate2),
424
+ encoding: __privateGet(this, _encoding2),
425
+ container: __privateGet(this, _container2)
366
426
  });
367
427
  const streamCompleteController = new AbortController();
368
428
  let timeoutId = null;
@@ -370,19 +430,26 @@ var WebSocket = class extends Client {
370
430
  timeoutId = setTimeout(streamCompleteController.abort, timeout);
371
431
  }
372
432
  const handleMessage = createMessageHandlerForContextId(
373
- contextId,
374
- (_0) => __async(this, [_0], function* ({ chunk, message }) {
433
+ inputs.context_id,
434
+ (_0) => __async(this, [_0], function* ({ chunk, message, data }) {
375
435
  emitter.emit("message", message);
436
+ if (data.type === "timestamps") {
437
+ emitter.emit("timestamps", data.word_timestamps);
438
+ return;
439
+ }
376
440
  if (isSentinel(chunk)) {
377
441
  yield source.close();
378
442
  streamCompleteController.abort();
379
443
  return;
380
444
  }
381
- yield source.enqueue(base64ToArray([chunk]));
382
445
  if (timeoutId) {
383
446
  clearTimeout(timeoutId);
384
447
  timeoutId = setTimeout(streamCompleteController.abort, timeout);
385
448
  }
449
+ if (!chunk) {
450
+ return;
451
+ }
452
+ yield source.enqueue(base64ToArray([chunk], __privateGet(this, _encoding2)));
386
453
  })
387
454
  );
388
455
  (_b = this.socket) == null ? void 0 : _b.addEventListener("message", handleMessage, {
@@ -412,7 +479,11 @@ var WebSocket = class extends Client {
412
479
  clearTimeout(timeoutId);
413
480
  }
414
481
  });
415
- return __spreadValues({ source }, getEmitteryCallbacks(emitter));
482
+ return __spreadProps(__spreadValues({
483
+ source
484
+ }, getEmitteryCallbacks(emitter)), {
485
+ stop: streamCompleteController.abort.bind(streamCompleteController)
486
+ });
416
487
  }
417
488
  /**
418
489
  * Authenticate and connect to a Cartesia streaming WebSocket.
@@ -482,6 +553,8 @@ var WebSocket = class extends Client {
482
553
  };
483
554
  _isConnected = new WeakMap();
484
555
  _sampleRate2 = new WeakMap();
556
+ _container2 = new WeakMap();
557
+ _encoding2 = new WeakMap();
485
558
  _generateId = new WeakSet();
486
559
  generateId_fn = function() {
487
560
  return (0, import_human_id.humanId)({
@@ -563,8 +636,7 @@ var Cartesia = class extends Client {
563
636
  };
564
637
 
565
638
  // src/tts/player.ts
566
- var import_emittery3 = __toESM(require("emittery"), 1);
567
- var _context, _startNextPlaybackAt, _bufferDuration, _emitter2, _playBuffer, playBuffer_fn;
639
+ var _context, _startNextPlaybackAt, _bufferDuration, _playBuffer, playBuffer_fn;
568
640
  var Player = class {
569
641
  /**
570
642
  * Create a new Player.
@@ -577,7 +649,6 @@ var Player = class {
577
649
  __privateAdd(this, _context, null);
578
650
  __privateAdd(this, _startNextPlaybackAt, 0);
579
651
  __privateAdd(this, _bufferDuration, void 0);
580
- __privateAdd(this, _emitter2, new import_emittery3.default());
581
652
  __privateSet(this, _bufferDuration, bufferDuration);
582
653
  }
583
654
  /**
@@ -599,7 +670,6 @@ var Player = class {
599
670
  const playableAudio = buffer.subarray(0, read);
600
671
  plays.push(__privateMethod(this, _playBuffer, playBuffer_fn).call(this, playableAudio, source.sampleRate));
601
672
  if (read < buffer.length) {
602
- yield __privateGet(this, _emitter2).emit("finish");
603
673
  break;
604
674
  }
605
675
  }
@@ -649,17 +719,33 @@ var Player = class {
649
719
  }
650
720
  });
651
721
  }
722
+ /**
723
+ * Stop the audio.
724
+ *
725
+ * @returns A promise that resolves when the audio has been stopped.
726
+ */
727
+ stop() {
728
+ return __async(this, null, function* () {
729
+ var _a;
730
+ if (!__privateGet(this, _context)) {
731
+ throw new Error("AudioContext not initialized.");
732
+ }
733
+ yield (_a = __privateGet(this, _context)) == null ? void 0 : _a.close();
734
+ });
735
+ }
652
736
  };
653
737
  _context = new WeakMap();
654
738
  _startNextPlaybackAt = new WeakMap();
655
739
  _bufferDuration = new WeakMap();
656
- _emitter2 = new WeakMap();
657
740
  _playBuffer = new WeakSet();
658
741
  playBuffer_fn = function(buf, sampleRate) {
659
742
  return __async(this, null, function* () {
660
743
  if (!__privateGet(this, _context)) {
661
744
  throw new Error("AudioContext not initialized.");
662
745
  }
746
+ if (buf.length === 0) {
747
+ return;
748
+ }
663
749
  const startAt = __privateGet(this, _startNextPlaybackAt);
664
750
  const duration = buf.length / sampleRate;
665
751
  __privateSet(this, _startNextPlaybackAt, duration + Math.max(__privateGet(this, _context).currentTime, __privateGet(this, _startNextPlaybackAt)));
@@ -683,7 +769,8 @@ var DEFAULT_BUFFER_DURATION = 0.01;
683
769
  function useTTS({
684
770
  apiKey,
685
771
  baseUrl,
686
- sampleRate
772
+ sampleRate,
773
+ onError
687
774
  }) {
688
775
  var _a, _b;
689
776
  if (typeof window === "undefined") {
@@ -714,7 +801,11 @@ function useTTS({
714
801
  }
715
802
  const cartesia = new Cartesia({ apiKey, baseUrl });
716
803
  baseUrl = baseUrl != null ? baseUrl : cartesia.baseUrl;
717
- return cartesia.tts.websocket({ sampleRate });
804
+ return cartesia.tts.websocket({
805
+ container: "raw",
806
+ encoding: "pcm_f32le",
807
+ sampleRate
808
+ });
718
809
  }, [apiKey, baseUrl, sampleRate]);
719
810
  const websocketReturn = (0, import_react.useRef)(null);
720
811
  const player = (0, import_react.useRef)(null);
@@ -726,21 +817,34 @@ function useTTS({
726
817
  const [messages, setMessages] = (0, import_react.useState)([]);
727
818
  const buffer = (0, import_react.useCallback)(
728
819
  (options) => __async(this, null, function* () {
729
- var _a2;
730
- setMessages([]);
731
- setBufferStatus("buffering");
732
- websocketReturn.current = (_a2 = websocket == null ? void 0 : websocket.send(options)) != null ? _a2 : null;
733
- if (!websocketReturn.current) {
734
- return;
820
+ var _a2, _b2;
821
+ (_a2 = websocketReturn.current) == null ? void 0 : _a2.stop();
822
+ try {
823
+ setMessages([]);
824
+ setBufferStatus("buffering");
825
+ websocketReturn.current = (_b2 = websocket == null ? void 0 : websocket.send(options)) != null ? _b2 : null;
826
+ if (!websocketReturn.current) {
827
+ return;
828
+ }
829
+ const unsubscribe = websocketReturn.current.on("message", (message) => {
830
+ const parsedMessage = JSON.parse(message);
831
+ setMessages((messages2) => [...messages2, parsedMessage]);
832
+ if (parsedMessage.error) {
833
+ onError == null ? void 0 : onError(new Error(parsedMessage.error));
834
+ }
835
+ });
836
+ yield websocketReturn.current.source.once("close");
837
+ setBufferStatus("buffered");
838
+ unsubscribe();
839
+ } catch (error) {
840
+ if (error instanceof Error) {
841
+ onError == null ? void 0 : onError(error);
842
+ } else {
843
+ console.error(error);
844
+ }
735
845
  }
736
- const unsubscribe = websocketReturn.current.on("message", (message) => {
737
- setMessages((messages2) => [...messages2, JSON.parse(message)]);
738
- });
739
- yield websocketReturn.current.source.once("close");
740
- setBufferStatus("buffered");
741
- unsubscribe();
742
846
  }),
743
- [websocket]
847
+ [websocket, onError]
744
848
  );
745
849
  const metrics = (0, import_react.useMemo)(() => {
746
850
  var _a2;
@@ -809,53 +913,88 @@ function useTTS({
809
913
  return () => cleanup == null ? void 0 : cleanup();
810
914
  }, [websocket, baseUrl]);
811
915
  const play = (0, import_react.useCallback)(() => __async(this, null, function* () {
812
- if (playbackStatus === "playing" || !websocketReturn.current) {
813
- return;
814
- }
815
- setPlaybackStatus("playing");
816
- const unsubscribes = [];
817
- unsubscribes.push(
818
- websocketReturn.current.source.on("wait", () => {
819
- setIsWaiting(true);
820
- })
821
- );
822
- unsubscribes.push(
823
- websocketReturn.current.source.on("read", () => {
824
- setIsWaiting(false);
825
- })
826
- );
827
- player.current = new Player({
828
- bufferDuration: bufferDuration != null ? bufferDuration : DEFAULT_BUFFER_DURATION
829
- });
830
- yield player.current.play(websocketReturn.current.source);
831
- for (const unsubscribe of unsubscribes) {
832
- unsubscribe();
916
+ try {
917
+ if (playbackStatus === "playing" || !websocketReturn.current) {
918
+ return;
919
+ }
920
+ if (player.current) {
921
+ yield player.current.stop();
922
+ }
923
+ setPlaybackStatus("playing");
924
+ const unsubscribes = [];
925
+ unsubscribes.push(
926
+ websocketReturn.current.source.on("wait", () => {
927
+ setIsWaiting(true);
928
+ })
929
+ );
930
+ unsubscribes.push(
931
+ websocketReturn.current.source.on("read", () => {
932
+ setIsWaiting(false);
933
+ })
934
+ );
935
+ player.current = new Player({
936
+ bufferDuration: bufferDuration != null ? bufferDuration : DEFAULT_BUFFER_DURATION
937
+ });
938
+ yield player.current.play(websocketReturn.current.source);
939
+ for (const unsubscribe of unsubscribes) {
940
+ unsubscribe();
941
+ }
942
+ setPlaybackStatus("finished");
943
+ } catch (error) {
944
+ if (error instanceof Error) {
945
+ onError == null ? void 0 : onError(error);
946
+ } else {
947
+ console.error(error);
948
+ }
833
949
  }
834
- setPlaybackStatus("finished");
835
- }), [playbackStatus, bufferDuration]);
950
+ }), [playbackStatus, bufferDuration, onError]);
836
951
  const pause = (0, import_react.useCallback)(() => __async(this, null, function* () {
837
952
  var _a2;
838
- yield (_a2 = player.current) == null ? void 0 : _a2.pause();
839
- setPlaybackStatus("paused");
840
- }), []);
953
+ try {
954
+ yield (_a2 = player.current) == null ? void 0 : _a2.pause();
955
+ setPlaybackStatus("paused");
956
+ } catch (error) {
957
+ if (error instanceof Error) {
958
+ onError == null ? void 0 : onError(error);
959
+ } else {
960
+ console.error(error);
961
+ }
962
+ }
963
+ }), [onError]);
841
964
  const resume = (0, import_react.useCallback)(() => __async(this, null, function* () {
842
965
  var _a2;
843
- yield (_a2 = player.current) == null ? void 0 : _a2.resume();
844
- setPlaybackStatus("playing");
845
- }), []);
966
+ try {
967
+ yield (_a2 = player.current) == null ? void 0 : _a2.resume();
968
+ setPlaybackStatus("playing");
969
+ } catch (error) {
970
+ if (error instanceof Error) {
971
+ onError == null ? void 0 : onError(error);
972
+ } else {
973
+ console.error(error);
974
+ }
975
+ }
976
+ }), [onError]);
846
977
  const toggle = (0, import_react.useCallback)(() => __async(this, null, function* () {
847
978
  var _a2;
848
- yield (_a2 = player.current) == null ? void 0 : _a2.toggle();
849
- setPlaybackStatus((status) => {
850
- if (status === "playing") {
851
- return "paused";
852
- }
853
- if (status === "paused") {
854
- return "playing";
979
+ try {
980
+ yield (_a2 = player.current) == null ? void 0 : _a2.toggle();
981
+ setPlaybackStatus((status) => {
982
+ if (status === "playing") {
983
+ return "paused";
984
+ }
985
+ if (status === "paused") {
986
+ return "playing";
987
+ }
988
+ return status;
989
+ });
990
+ } catch (error) {
991
+ if (error instanceof Error) {
992
+ onError == null ? void 0 : onError(error);
993
+ } else {
994
+ console.error(error);
855
995
  }
856
- return status;
857
- });
858
- }), []);
996
+ }
997
+ }), [onError]);
859
998
  return {
860
999
  buffer,
861
1000
  play,
@@ -1,11 +1,12 @@
1
1
  import Source from '../tts/source.cjs';
2
+ import { StreamRequest } from '../types/index.cjs';
2
3
  import 'emittery';
3
- import '../types/index.cjs';
4
4
 
5
5
  type UseTTSOptions = {
6
6
  apiKey: string | null;
7
7
  baseUrl?: string;
8
8
  sampleRate: number;
9
+ onError?: (error: Error) => void;
9
10
  };
10
11
  type PlaybackStatus = "inactive" | "playing" | "paused" | "finished";
11
12
  type BufferStatus = "inactive" | "buffering" | "buffered";
@@ -13,7 +14,7 @@ type Metrics = {
13
14
  modelLatency: number | null;
14
15
  };
15
16
  interface UseTTSReturn {
16
- buffer: (options: object) => Promise<void>;
17
+ buffer: (options: StreamRequest) => Promise<void>;
17
18
  play: (bufferDuration?: number) => Promise<void>;
18
19
  pause: () => Promise<void>;
19
20
  resume: () => Promise<void>;
@@ -28,6 +29,6 @@ interface UseTTSReturn {
28
29
  /**
29
30
  * React hook to use the Cartesia audio API.
30
31
  */
31
- declare function useTTS({ apiKey, baseUrl, sampleRate, }: UseTTSOptions): UseTTSReturn;
32
+ declare function useTTS({ apiKey, baseUrl, sampleRate, onError, }: UseTTSOptions): UseTTSReturn;
32
33
 
33
34
  export { type BufferStatus, type Metrics, type PlaybackStatus, type UseTTSOptions, type UseTTSReturn, useTTS };
@@ -1,11 +1,12 @@
1
1
  import Source from '../tts/source.js';
2
+ import { StreamRequest } from '../types/index.js';
2
3
  import 'emittery';
3
- import '../types/index.js';
4
4
 
5
5
  type UseTTSOptions = {
6
6
  apiKey: string | null;
7
7
  baseUrl?: string;
8
8
  sampleRate: number;
9
+ onError?: (error: Error) => void;
9
10
  };
10
11
  type PlaybackStatus = "inactive" | "playing" | "paused" | "finished";
11
12
  type BufferStatus = "inactive" | "buffering" | "buffered";
@@ -13,7 +14,7 @@ type Metrics = {
13
14
  modelLatency: number | null;
14
15
  };
15
16
  interface UseTTSReturn {
16
- buffer: (options: object) => Promise<void>;
17
+ buffer: (options: StreamRequest) => Promise<void>;
17
18
  play: (bufferDuration?: number) => Promise<void>;
18
19
  pause: () => Promise<void>;
19
20
  resume: () => Promise<void>;
@@ -28,6 +29,6 @@ interface UseTTSReturn {
28
29
  /**
29
30
  * React hook to use the Cartesia audio API.
30
31
  */
31
- declare function useTTS({ apiKey, baseUrl, sampleRate, }: UseTTSOptions): UseTTSReturn;
32
+ declare function useTTS({ apiKey, baseUrl, sampleRate, onError, }: UseTTSOptions): UseTTSReturn;
32
33
 
33
34
  export { type BufferStatus, type Metrics, type PlaybackStatus, type UseTTSOptions, type UseTTSReturn, useTTS };