@estuary-ai/sdk 0.1.28 → 0.1.30

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.mjs CHANGED
@@ -31007,24 +31007,24 @@ async function isLiveKitAvailable() {
31007
31007
  async function createVoiceManager(transport, socketManager, sampleRate, logger) {
31008
31008
  if (transport === "websocket") {
31009
31009
  const { WebSocketVoiceManager: WebSocketVoiceManager2 } = await Promise.resolve().then(() => (init_websocket_voice(), websocket_voice_exports));
31010
- return new WebSocketVoiceManager2(socketManager, sampleRate, logger);
31010
+ return { manager: new WebSocketVoiceManager2(socketManager, sampleRate, logger), resolvedTransport: "websocket" };
31011
31011
  }
31012
31012
  if (transport === "livekit") {
31013
31013
  if (await isLiveKitAvailable()) {
31014
31014
  const { LiveKitVoiceManager: LiveKitVoiceManager2 } = await Promise.resolve().then(() => (init_livekit_voice(), livekit_voice_exports));
31015
- return new LiveKitVoiceManager2(socketManager, logger);
31015
+ return { manager: new LiveKitVoiceManager2(socketManager, logger), resolvedTransport: "livekit" };
31016
31016
  }
31017
31017
  logger.warn("livekit-client not installed, falling back to WebSocket voice");
31018
31018
  const { WebSocketVoiceManager: WebSocketVoiceManager2 } = await Promise.resolve().then(() => (init_websocket_voice(), websocket_voice_exports));
31019
- return new WebSocketVoiceManager2(socketManager, sampleRate, logger);
31019
+ return { manager: new WebSocketVoiceManager2(socketManager, sampleRate, logger), resolvedTransport: "websocket" };
31020
31020
  }
31021
31021
  if (transport === "auto") {
31022
31022
  if (await isLiveKitAvailable()) {
31023
31023
  const { LiveKitVoiceManager: LiveKitVoiceManager2 } = await Promise.resolve().then(() => (init_livekit_voice(), livekit_voice_exports));
31024
- return new LiveKitVoiceManager2(socketManager, logger);
31024
+ return { manager: new LiveKitVoiceManager2(socketManager, logger), resolvedTransport: "livekit" };
31025
31025
  }
31026
31026
  const { WebSocketVoiceManager: WebSocketVoiceManager2 } = await Promise.resolve().then(() => (init_websocket_voice(), websocket_voice_exports));
31027
- return new WebSocketVoiceManager2(socketManager, sampleRate, logger);
31027
+ return { manager: new WebSocketVoiceManager2(socketManager, sampleRate, logger), resolvedTransport: "websocket" };
31028
31028
  }
31029
31029
  return null;
31030
31030
  }
@@ -31159,7 +31159,7 @@ var CharacterClient = class {
31159
31159
  };
31160
31160
 
31161
31161
  // src/audio/audio-player.ts
31162
- var AudioPlayer = class {
31162
+ var AudioPlayer = class _AudioPlayer {
31163
31163
  sampleRate;
31164
31164
  onEvent;
31165
31165
  audioContext = null;
@@ -31171,6 +31171,8 @@ var AudioPlayer = class {
31171
31171
  isPlaying = false;
31172
31172
  _isCleared = false;
31173
31173
  _interruptedMessageId = null;
31174
+ _drainTimer = null;
31175
+ static DRAIN_DELAY_MS = 300;
31174
31176
  constructor(sampleRate, onEvent) {
31175
31177
  this.sampleRate = sampleRate;
31176
31178
  this.onEvent = onEvent;
@@ -31193,6 +31195,7 @@ var AudioPlayer = class {
31193
31195
  this._interruptedMessageId = null;
31194
31196
  }
31195
31197
  this._isCleared = false;
31198
+ this.cancelDrain();
31196
31199
  const ctx = this.getAudioContext();
31197
31200
  if (!ctx) return;
31198
31201
  const pcm16 = base64ToInt16Array(voice.audio);
@@ -31206,6 +31209,7 @@ var AudioPlayer = class {
31206
31209
  }
31207
31210
  clear() {
31208
31211
  this._isCleared = true;
31212
+ this.cancelDrain();
31209
31213
  this.queue.length = 0;
31210
31214
  if (this.currentSource) {
31211
31215
  try {
@@ -31231,6 +31235,7 @@ var AudioPlayer = class {
31231
31235
  this.currentMessageId = null;
31232
31236
  }
31233
31237
  dispose() {
31238
+ this.cancelDrain();
31234
31239
  this.clear();
31235
31240
  if (this.audioElement) {
31236
31241
  this.audioElement.pause();
@@ -31248,6 +31253,25 @@ var AudioPlayer = class {
31248
31253
  this.audioContext = null;
31249
31254
  }
31250
31255
  }
31256
+ /** Schedule a deferred 'complete' event. Cancelled if new chunks arrive. */
31257
+ scheduleDrain() {
31258
+ if (this._drainTimer !== null) return;
31259
+ this._drainTimer = setTimeout(() => {
31260
+ this._drainTimer = null;
31261
+ if (this._isCleared) return;
31262
+ if (this.queue.length === 0 && this.isPlaying && this.currentMessageId) {
31263
+ this.onEvent({ type: "complete", messageId: this.currentMessageId });
31264
+ this.isPlaying = false;
31265
+ this.currentMessageId = null;
31266
+ }
31267
+ }, _AudioPlayer.DRAIN_DELAY_MS);
31268
+ }
31269
+ cancelDrain() {
31270
+ if (this._drainTimer !== null) {
31271
+ clearTimeout(this._drainTimer);
31272
+ this._drainTimer = null;
31273
+ }
31274
+ }
31251
31275
  getAudioContext() {
31252
31276
  if (this.audioContext) return this.audioContext;
31253
31277
  if (typeof AudioContext === "undefined" && typeof globalThis.webkitAudioContext === "undefined") {
@@ -31274,10 +31298,8 @@ var AudioPlayer = class {
31274
31298
  const ctx = this.getAudioContext();
31275
31299
  if (!ctx || this.queue.length === 0) {
31276
31300
  if (this.isPlaying && this.currentMessageId) {
31277
- this.onEvent({ type: "complete", messageId: this.currentMessageId });
31301
+ this.scheduleDrain();
31278
31302
  }
31279
- this.isPlaying = false;
31280
- this.currentMessageId = null;
31281
31303
  return;
31282
31304
  }
31283
31305
  const { buffer, messageId } = this.queue.shift();
@@ -31512,11 +31534,12 @@ var EstuaryClient = class extends TypedEventEmitter {
31512
31534
  }
31513
31535
  const transport = this.config.voiceTransport ?? "auto";
31514
31536
  const sampleRate = this.config.audioSampleRate ?? DEFAULT_SAMPLE_RATE;
31515
- this.voiceManager = await createVoiceManager(transport, this.socketManager, sampleRate, this.logger);
31516
- if (!this.voiceManager) {
31537
+ const result = await createVoiceManager(transport, this.socketManager, sampleRate, this.logger);
31538
+ if (!result) {
31517
31539
  throw new EstuaryError("VOICE_NOT_SUPPORTED" /* VOICE_NOT_SUPPORTED */, "No voice transport available");
31518
31540
  }
31519
- if (!this.audioPlayer && typeof AudioContext !== "undefined") {
31541
+ this.voiceManager = result.manager;
31542
+ if (!this.audioPlayer && result.resolvedTransport === "websocket" && typeof AudioContext !== "undefined") {
31520
31543
  this.audioPlayer = new AudioPlayer(sampleRate, (event) => {
31521
31544
  if (event.type === "started") {
31522
31545
  this._hasAutoInterrupted = true;