@jchaffin/voicekit 0.2.1 → 0.2.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.
@@ -73,18 +73,21 @@ var DeepgramSession = class extends EventEmitter {
73
73
  if (this.options.model) url.searchParams.set("model", this.options.model);
74
74
  if (this.options.language) url.searchParams.set("language", this.options.language);
75
75
  this.ws = new WebSocket(url.toString());
76
- try {
77
- await new Promise((resolve, reject) => {
78
- const ws = this.ws;
79
- ws.onopen = () => resolve();
80
- ws.onerror = () => reject(new Error("WebSocket connection failed"));
81
- ws.onclose = () => this.emit("status_change", "DISCONNECTED");
82
- });
83
- } catch (err) {
84
- this.ws?.close();
85
- this.ws = null;
86
- throw err;
87
- }
76
+ await new Promise((resolve, reject) => {
77
+ const ws = this.ws;
78
+ let opened = false;
79
+ ws.onopen = () => {
80
+ opened = true;
81
+ resolve();
82
+ };
83
+ ws.onerror = () => {
84
+ if (!opened) reject(new Error("WebSocket connection failed"));
85
+ };
86
+ ws.onclose = () => {
87
+ this.emit("status_change", "DISCONNECTED");
88
+ if (!opened) reject(new Error("WebSocket closed before connection opened"));
89
+ };
90
+ });
88
91
  this.ws.onmessage = (event) => {
89
92
  try {
90
93
  const msg = JSON.parse(event.data);
@@ -19,18 +19,21 @@ var DeepgramSession = class extends EventEmitter {
19
19
  if (this.options.model) url.searchParams.set("model", this.options.model);
20
20
  if (this.options.language) url.searchParams.set("language", this.options.language);
21
21
  this.ws = new WebSocket(url.toString());
22
- try {
23
- await new Promise((resolve, reject) => {
24
- const ws = this.ws;
25
- ws.onopen = () => resolve();
26
- ws.onerror = () => reject(new Error("WebSocket connection failed"));
27
- ws.onclose = () => this.emit("status_change", "DISCONNECTED");
28
- });
29
- } catch (err) {
30
- this.ws?.close();
31
- this.ws = null;
32
- throw err;
33
- }
22
+ await new Promise((resolve, reject) => {
23
+ const ws = this.ws;
24
+ let opened = false;
25
+ ws.onopen = () => {
26
+ opened = true;
27
+ resolve();
28
+ };
29
+ ws.onerror = () => {
30
+ if (!opened) reject(new Error("WebSocket connection failed"));
31
+ };
32
+ ws.onclose = () => {
33
+ this.emit("status_change", "DISCONNECTED");
34
+ if (!opened) reject(new Error("WebSocket closed before connection opened"));
35
+ };
36
+ });
34
37
  this.ws.onmessage = (event) => {
35
38
  try {
36
39
  const msg = JSON.parse(event.data);
@@ -73,17 +73,11 @@ var ElevenLabsSession = class extends EventEmitter {
73
73
  async connect(config) {
74
74
  const wsUrl = config.authToken?.startsWith("wss://") ? config.authToken : `${ELEVENLABS_WS_BASE}?agent_id=${this.agentId}`;
75
75
  this.ws = new WebSocket(wsUrl);
76
- try {
77
- await new Promise((resolve, reject) => {
78
- const ws = this.ws;
79
- ws.onopen = () => resolve();
80
- ws.onerror = () => reject(new Error("ElevenLabs WebSocket connection failed"));
81
- });
82
- } catch (err) {
83
- this.ws?.close();
84
- this.ws = null;
85
- throw err;
86
- }
76
+ await new Promise((resolve, reject) => {
77
+ const ws = this.ws;
78
+ ws.onopen = () => resolve();
79
+ ws.onerror = () => reject(new Error("ElevenLabs WebSocket connection failed"));
80
+ });
87
81
  this.ws.onmessage = (event) => {
88
82
  try {
89
83
  const msg = JSON.parse(event.data);
@@ -19,17 +19,11 @@ var ElevenLabsSession = class extends EventEmitter {
19
19
  async connect(config) {
20
20
  const wsUrl = config.authToken?.startsWith("wss://") ? config.authToken : `${ELEVENLABS_WS_BASE}?agent_id=${this.agentId}`;
21
21
  this.ws = new WebSocket(wsUrl);
22
- try {
23
- await new Promise((resolve, reject) => {
24
- const ws = this.ws;
25
- ws.onopen = () => resolve();
26
- ws.onerror = () => reject(new Error("ElevenLabs WebSocket connection failed"));
27
- });
28
- } catch (err) {
29
- this.ws?.close();
30
- this.ws = null;
31
- throw err;
32
- }
22
+ await new Promise((resolve, reject) => {
23
+ const ws = this.ws;
24
+ ws.onopen = () => resolve();
25
+ ws.onerror = () => reject(new Error("ElevenLabs WebSocket connection failed"));
26
+ });
33
27
  this.ws.onmessage = (event) => {
34
28
  try {
35
29
  const msg = JSON.parse(event.data);
@@ -106,15 +106,9 @@ var LiveKitSession = class extends EventEmitter {
106
106
  this.room.on(RoomEvent.Reconnected, () => {
107
107
  this.emit("status_change", "CONNECTED");
108
108
  });
109
- try {
110
- await this.room.connect(this.serverUrl, config.authToken);
111
- await this.room.localParticipant.setMicrophoneEnabled(true);
112
- this.emit("status_change", "CONNECTED");
113
- } catch (err) {
114
- await this.room.disconnect();
115
- this.room = null;
116
- throw err;
117
- }
109
+ await this.room.connect(this.serverUrl, config.authToken);
110
+ await this.room.localParticipant.setMicrophoneEnabled(true);
111
+ this.emit("status_change", "CONNECTED");
118
112
  }
119
113
  async disconnect() {
120
114
  if (this.room) {
@@ -42,15 +42,9 @@ var LiveKitSession = class extends EventEmitter {
42
42
  this.room.on(RoomEvent.Reconnected, () => {
43
43
  this.emit("status_change", "CONNECTED");
44
44
  });
45
- try {
46
- await this.room.connect(this.serverUrl, config.authToken);
47
- await this.room.localParticipant.setMicrophoneEnabled(true);
48
- this.emit("status_change", "CONNECTED");
49
- } catch (err) {
50
- await this.room.disconnect();
51
- this.room = null;
52
- throw err;
53
- }
45
+ await this.room.connect(this.serverUrl, config.authToken);
46
+ await this.room.localParticipant.setMicrophoneEnabled(true);
47
+ this.emit("status_change", "CONNECTED");
54
48
  }
55
49
  async disconnect() {
56
50
  if (this.room) {
package/dist/index.js CHANGED
@@ -217,7 +217,12 @@ function VoiceProvider({
217
217
  }, 500);
218
218
  } catch (error) {
219
219
  console.error("VoiceKit connection failed:", error);
220
+ try {
221
+ await sessionRef.current?.disconnect();
222
+ } catch {
223
+ }
220
224
  sessionRef.current = null;
225
+ currentMsgIdRef.current = null;
221
226
  onError?.(error instanceof Error ? error : new Error(String(error)));
222
227
  updateStatus("DISCONNECTED");
223
228
  }
@@ -824,7 +829,6 @@ function useAudioRecorder() {
824
829
  if (mediaRecorderRef.current?.state === "recording") {
825
830
  return;
826
831
  }
827
- recordedChunksRef.current = [];
828
832
  try {
829
833
  const mediaRecorder = new MediaRecorder(stream, { mimeType: "audio/webm" });
830
834
  mediaRecorder.ondataavailable = (event) => {
@@ -1107,6 +1111,8 @@ function useSessionHistory() {
1107
1111
  updateTranscriptMessage,
1108
1112
  updateTranscriptItem
1109
1113
  } = useTranscript();
1114
+ const transcriptItemsRef = (0, import_react7.useRef)(transcriptItems);
1115
+ transcriptItemsRef.current = transcriptItems;
1110
1116
  const { logServerEvent } = useEvent();
1111
1117
  const accumulatedTextRef = (0, import_react7.useRef)(/* @__PURE__ */ new Map());
1112
1118
  const pendingDeltasRef = (0, import_react7.useRef)(/* @__PURE__ */ new Map());
@@ -1272,8 +1278,6 @@ function useSessionHistory() {
1272
1278
  });
1273
1279
  }
1274
1280
  }
1275
- const transcriptItemsRef = (0, import_react7.useRef)(transcriptItems);
1276
- transcriptItemsRef.current = transcriptItems;
1277
1281
  const handlersRef = (0, import_react7.useRef)({
1278
1282
  handleAgentToolStart,
1279
1283
  handleAgentToolEnd,
package/dist/index.mjs CHANGED
@@ -159,7 +159,12 @@ function VoiceProvider({
159
159
  }, 500);
160
160
  } catch (error) {
161
161
  console.error("VoiceKit connection failed:", error);
162
+ try {
163
+ await sessionRef.current?.disconnect();
164
+ } catch {
165
+ }
162
166
  sessionRef.current = null;
167
+ currentMsgIdRef.current = null;
163
168
  onError?.(error instanceof Error ? error : new Error(String(error)));
164
169
  updateStatus("DISCONNECTED");
165
170
  }
@@ -605,7 +610,6 @@ function useAudioRecorder() {
605
610
  if (mediaRecorderRef.current?.state === "recording") {
606
611
  return;
607
612
  }
608
- recordedChunksRef.current = [];
609
613
  try {
610
614
  const mediaRecorder = new MediaRecorder(stream, { mimeType: "audio/webm" });
611
615
  mediaRecorder.ondataavailable = (event) => {
@@ -893,6 +897,8 @@ function useSessionHistory() {
893
897
  updateTranscriptMessage,
894
898
  updateTranscriptItem
895
899
  } = useTranscript();
900
+ const transcriptItemsRef = useRef5(transcriptItems);
901
+ transcriptItemsRef.current = transcriptItems;
896
902
  const { logServerEvent } = useEvent();
897
903
  const accumulatedTextRef = useRef5(/* @__PURE__ */ new Map());
898
904
  const pendingDeltasRef = useRef5(/* @__PURE__ */ new Map());
@@ -1058,8 +1064,6 @@ function useSessionHistory() {
1058
1064
  });
1059
1065
  }
1060
1066
  }
1061
- const transcriptItemsRef = useRef5(transcriptItems);
1062
- transcriptItemsRef.current = transcriptItems;
1063
1067
  const handlersRef = useRef5({
1064
1068
  handleAgentToolStart,
1065
1069
  handleAgentToolEnd,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jchaffin/voicekit",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "description": "A provider-agnostic React library for building voice-enabled AI agents",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -42,11 +42,12 @@
42
42
  "README.md"
43
43
  ],
44
44
  "scripts": {
45
- "build": "tsup src/index.ts src/server.ts src/adapters/openai.ts src/adapters/livekit.ts src/adapters/deepgram.ts src/adapters/elevenlabs.ts --format cjs,esm --dts --external react --external react-dom --external @openai/agents --external livekit-client --external livekit-server-sdk --external @deepgram/sdk",
46
- "dev": "tsup src/index.ts src/server.ts src/adapters/openai.ts src/adapters/livekit.ts src/adapters/deepgram.ts src/adapters/elevenlabs.ts --format cjs,esm --dts --watch --external react --external react-dom --external @openai/agents --external livekit-client --external livekit-server-sdk --external @deepgram/sdk",
45
+ "build": "tsup",
46
+ "dev": "tsup --watch",
47
+ "prepare": "tsup",
47
48
  "lint": "eslint src/",
48
49
  "typecheck": "tsc --noEmit",
49
- "prepublishOnly": "npm run build"
50
+ "prepublishOnly": "tsup"
50
51
  },
51
52
  "keywords": [
52
53
  "voice",
@@ -59,11 +60,13 @@
59
60
  "react",
60
61
  "agent",
61
62
  "webrtc",
62
- "speech",
63
- "provider-agnostic"
63
+ "speech"
64
64
  ],
65
65
  "author": "Jacob Chaffin",
66
66
  "license": "MIT",
67
+ "publishConfig": {
68
+ "access": "public"
69
+ },
67
70
  "peerDependencies": {
68
71
  "react": ">=18.0.0",
69
72
  "react-dom": ">=18.0.0",
@@ -88,6 +91,7 @@
88
91
  },
89
92
  "devDependencies": {
90
93
  "@openai/agents": ">=0.0.15",
94
+ "@types/node": "^25.6.0",
91
95
  "@types/react": "^18.2.0",
92
96
  "@types/react-dom": "^18.2.0",
93
97
  "tsup": "^8.0.0",