@speechos/core 0.2.5 → 0.2.7

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/config.d.cts CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Configuration management for SpeechOS Core SDK
3
3
  */
4
- import type { SpeechOSCoreConfig } from "./types.js";
4
+ import type { SpeechOSCoreConfig, WebSocketFactory } from "./types.js";
5
5
  /**
6
6
  * Default host - can be overridden by SPEECHOS_HOST env var at build time
7
7
  */
@@ -14,6 +14,8 @@ interface ResolvedConfig {
14
14
  userId: string;
15
15
  host: string;
16
16
  debug: boolean;
17
+ /** Custom WebSocket factory (undefined means use native WebSocket) */
18
+ webSocketFactory: WebSocketFactory | undefined;
17
19
  }
18
20
  /**
19
21
  * Validates and merges user config with defaults
package/dist/config.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Configuration management for SpeechOS Core SDK
3
3
  */
4
- import type { SpeechOSCoreConfig } from "./types.js";
4
+ import type { SpeechOSCoreConfig, WebSocketFactory } from "./types.js";
5
5
  /**
6
6
  * Default host - can be overridden by SPEECHOS_HOST env var at build time
7
7
  */
@@ -14,6 +14,8 @@ interface ResolvedConfig {
14
14
  userId: string;
15
15
  host: string;
16
16
  debug: boolean;
17
+ /** Custom WebSocket factory (undefined means use native WebSocket) */
18
+ webSocketFactory: WebSocketFactory | undefined;
17
19
  }
18
20
  /**
19
21
  * Validates and merges user config with defaults
package/dist/index.cjs CHANGED
@@ -35,7 +35,8 @@ const defaultConfig = {
35
35
  apiKey: "",
36
36
  userId: "",
37
37
  host: DEFAULT_HOST,
38
- debug: false
38
+ debug: false,
39
+ webSocketFactory: void 0
39
40
  };
40
41
  /**
41
42
  * Validates and merges user config with defaults
@@ -48,7 +49,8 @@ function validateConfig(userConfig) {
48
49
  apiKey: userConfig.apiKey,
49
50
  userId: userConfig.userId ?? defaultConfig.userId,
50
51
  host: userConfig.host ?? defaultConfig.host,
51
- debug: userConfig.debug ?? defaultConfig.debug
52
+ debug: userConfig.debug ?? defaultConfig.debug,
53
+ webSocketFactory: userConfig.webSocketFactory ?? defaultConfig.webSocketFactory
52
54
  };
53
55
  }
54
56
  /**
@@ -337,14 +339,16 @@ var StateManager = class {
337
339
  });
338
340
  }
339
341
  /**
340
- * Complete the recording flow and return to idle
342
+ * Complete the recording flow and return to idle.
343
+ * Keeps widget visible but collapsed (just mic button, no action bubbles).
341
344
  */
342
345
  completeRecording() {
343
346
  this.setState({
344
347
  recordingState: "idle",
345
348
  activeAction: null,
346
349
  isConnected: false,
347
- isMicEnabled: false
350
+ isMicEnabled: false,
351
+ isExpanded: false
348
352
  });
349
353
  }
350
354
  /**
@@ -1418,6 +1422,8 @@ const MESSAGE_TYPE_EDITED_TEXT = "edited_text";
1418
1422
  const MESSAGE_TYPE_EXECUTE_COMMAND = "execute_command";
1419
1423
  const MESSAGE_TYPE_COMMAND_RESULT = "command_result";
1420
1424
  const MESSAGE_TYPE_ERROR = "error";
1425
+ const WS_OPEN = 1;
1426
+ const WS_CLOSED = 3;
1421
1427
  /**
1422
1428
  * Response timeout in milliseconds.
1423
1429
  */
@@ -1536,7 +1542,10 @@ var WebSocketManager = class {
1536
1542
  state.setMicEnabled(true);
1537
1543
  const wsUrl = this.getWebSocketUrl();
1538
1544
  if (config.debug) console.log("[SpeechOS] Connecting to WebSocket:", wsUrl);
1539
- this.ws = new WebSocket(wsUrl);
1545
+ this.pendingAuth = new Deferred$1();
1546
+ this.pendingAuth.setTimeout(RESPONSE_TIMEOUT_MS, "Connection timed out", "connection_timeout", "connection");
1547
+ const factory = config.webSocketFactory ?? ((url) => new WebSocket(url));
1548
+ this.ws = factory(wsUrl);
1540
1549
  this.ws.onopen = () => {
1541
1550
  if (config.debug) console.log("[SpeechOS] WebSocket connected, authenticating...");
1542
1551
  this.authenticate();
@@ -1545,19 +1554,21 @@ var WebSocketManager = class {
1545
1554
  this.handleMessage(event.data);
1546
1555
  };
1547
1556
  this.ws.onerror = (event) => {
1548
- console.error("[SpeechOS] WebSocket error:", event);
1557
+ const isConnectionBlocked = this.ws?.readyState === WS_CLOSED;
1558
+ const errorCode = isConnectionBlocked ? "connection_blocked" : "websocket_error";
1559
+ const errorMessage = isConnectionBlocked ? "This site's CSP blocks the extension. Try embedded mode instead." : "WebSocket connection error";
1560
+ console.error("[SpeechOS] WebSocket error:", event, { isConnectionBlocked });
1549
1561
  events.emit("error", {
1550
- code: "websocket_error",
1551
- message: "WebSocket connection error",
1562
+ code: errorCode,
1563
+ message: errorMessage,
1552
1564
  source: "connection"
1553
1565
  });
1566
+ if (this.pendingAuth) this.pendingAuth.reject(new Error(errorMessage));
1554
1567
  };
1555
1568
  this.ws.onclose = (event) => {
1556
1569
  if (config.debug) console.log("[SpeechOS] WebSocket closed:", event.code, event.reason);
1557
1570
  state.setConnected(false);
1558
1571
  };
1559
- this.pendingAuth = new Deferred$1();
1560
- this.pendingAuth.setTimeout(RESPONSE_TIMEOUT_MS, "Connection timed out", "connection_timeout", "connection");
1561
1572
  await this.pendingAuth.promise;
1562
1573
  this.pendingAuth = null;
1563
1574
  if (this.audioCapture) this.audioCapture.setReady();
@@ -1606,7 +1617,7 @@ var WebSocketManager = class {
1606
1617
  * Actually send the audio chunk (async operation).
1607
1618
  */
1608
1619
  async doSendAudioChunk(chunk) {
1609
- if (this.ws && this.ws.readyState === WebSocket.OPEN) {
1620
+ if (this.ws && this.ws.readyState === WS_OPEN) {
1610
1621
  const arrayBuffer = await chunk.arrayBuffer();
1611
1622
  this.ws.send(arrayBuffer);
1612
1623
  }
@@ -1792,7 +1803,7 @@ var WebSocketManager = class {
1792
1803
  * the transcript. Uses the same pattern as LiveKit's ReadableStream approach.
1793
1804
  */
1794
1805
  async waitForBufferDrain() {
1795
- if (!this.ws || this.ws.readyState !== WebSocket.OPEN) return;
1806
+ if (!this.ws || this.ws.readyState !== WS_OPEN) return;
1796
1807
  const config = getConfig();
1797
1808
  const startTime = Date.now();
1798
1809
  while (this.ws.bufferedAmount > 0) {
@@ -1808,7 +1819,7 @@ var WebSocketManager = class {
1808
1819
  * Send a JSON message over the WebSocket.
1809
1820
  */
1810
1821
  sendMessage(message) {
1811
- if (this.ws && this.ws.readyState === WebSocket.OPEN) this.ws.send(JSON.stringify(message));
1822
+ if (this.ws && this.ws.readyState === WS_OPEN) this.ws.send(JSON.stringify(message));
1812
1823
  }
1813
1824
  /**
1814
1825
  * Disconnect from the WebSocket.
@@ -1850,7 +1861,7 @@ var WebSocketManager = class {
1850
1861
  * Check if connected to WebSocket.
1851
1862
  */
1852
1863
  isConnected() {
1853
- return this.ws !== null && this.ws.readyState === WebSocket.OPEN;
1864
+ return this.ws !== null && this.ws.readyState === WS_OPEN;
1854
1865
  }
1855
1866
  /**
1856
1867
  * Get the last input text from a command result.