kugelaudio 0.1.12 → 0.1.14

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.js CHANGED
@@ -136,25 +136,34 @@ function createWavBlob(audio, sampleRate) {
136
136
  }
137
137
 
138
138
  // src/websocket.ts
139
- var isBrowser = typeof window !== "undefined" && typeof window.WebSocket !== "undefined";
139
+ var _cachedWs = null;
140
140
  function getWebSocket() {
141
- if (isBrowser) {
142
- return window.WebSocket;
141
+ if (_cachedWs) return _cachedWs;
142
+ if (typeof globalThis !== "undefined" && typeof globalThis.WebSocket !== "undefined") {
143
+ _cachedWs = globalThis.WebSocket;
144
+ return _cachedWs;
143
145
  }
144
146
  try {
145
- const ws = require("ws");
146
- return ws;
147
+ const _require = typeof require !== "undefined" ? require : Function('return typeof require !== "undefined" ? require : undefined')();
148
+ if (_require) {
149
+ const ws = _require("ws");
150
+ _cachedWs = ws.default || ws;
151
+ return _cachedWs;
152
+ }
147
153
  } catch {
148
- throw new Error(
149
- 'WebSocket not available. In Node.js, install the "ws" package: npm install ws'
150
- );
151
154
  }
155
+ throw new Error(
156
+ 'WebSocket not available. In Node.js, install the "ws" package: npm install ws'
157
+ );
152
158
  }
153
- var WebSocketCompat = getWebSocket();
154
159
 
155
160
  // src/client.ts
156
161
  var DEFAULT_API_URL = "https://api.kugelaudio.com";
157
- var WebSocketImpl = getWebSocket();
162
+ function createWs(url) {
163
+ const WS = getWebSocket();
164
+ return new WS(url);
165
+ }
166
+ var WS_OPEN = 1;
158
167
  var ModelsResource = class {
159
168
  constructor(client) {
160
169
  this.client = client;
@@ -260,7 +269,7 @@ var TTSResource = class {
260
269
  * Check if WebSocket connection is established and open.
261
270
  */
262
271
  isConnected() {
263
- return this.wsConnection !== null && this.wsConnection.readyState === WebSocketImpl.OPEN;
272
+ return this.wsConnection !== null && this.wsConnection.readyState === WS_OPEN;
264
273
  }
265
274
  /**
266
275
  * Generate audio from text with streaming via WebSocket.
@@ -318,7 +327,7 @@ var TTSResource = class {
318
327
  */
319
328
  async getConnection() {
320
329
  const url = this.buildWsUrl();
321
- if (this.wsConnection && this.wsUrl === url && this.wsConnection.readyState === WebSocketImpl.OPEN) {
330
+ if (this.wsConnection && this.wsUrl === url && this.wsConnection.readyState === WS_OPEN) {
322
331
  return this.wsConnection;
323
332
  }
324
333
  if (this.wsConnection) {
@@ -329,7 +338,7 @@ var TTSResource = class {
329
338
  this.wsConnection = null;
330
339
  }
331
340
  return new Promise((resolve, reject) => {
332
- const ws = new WebSocketImpl(url);
341
+ const ws = createWs(url);
333
342
  ws.onopen = () => {
334
343
  this.wsConnection = ws;
335
344
  this.wsUrl = url;
@@ -451,7 +460,7 @@ var TTSResource = class {
451
460
  streamWithoutPooling(options, callbacks) {
452
461
  return new Promise((resolve, reject) => {
453
462
  const url = this.buildWsUrl();
454
- const ws = new WebSocketImpl(url);
463
+ const ws = createWs(url);
455
464
  ws.onopen = () => {
456
465
  callbacks.onOpen?.();
457
466
  ws.send(JSON.stringify({
@@ -614,7 +623,7 @@ var MultiContextSession = class {
614
623
  authParam = "api_key";
615
624
  }
616
625
  const url = `${wsUrl}/ws/tts/multi?${authParam}=${this.client.apiKey}`;
617
- this.ws = new WebSocketImpl(url);
626
+ this.ws = createWs(url);
618
627
  this.ws.onopen = () => {
619
628
  };
620
629
  this.ws.onmessage = (event) => {
@@ -684,7 +693,7 @@ var MultiContextSession = class {
684
693
  * Create a new context with optional voice settings.
685
694
  */
686
695
  createContext(contextId, options) {
687
- if (!this.ws || this.ws.readyState !== WebSocketImpl.OPEN) {
696
+ if (!this.ws || this.ws.readyState !== WS_OPEN) {
688
697
  throw new KugelAudioError("WebSocket not connected");
689
698
  }
690
699
  const msg = {
@@ -715,7 +724,7 @@ var MultiContextSession = class {
715
724
  * Send text to a specific context.
716
725
  */
717
726
  send(contextId, text, flush = false) {
718
- if (!this.ws || this.ws.readyState !== WebSocketImpl.OPEN) {
727
+ if (!this.ws || this.ws.readyState !== WS_OPEN) {
719
728
  throw new KugelAudioError("WebSocket not connected");
720
729
  }
721
730
  if (!this.contexts.has(contextId) && !this.isStarted) {
@@ -731,7 +740,7 @@ var MultiContextSession = class {
731
740
  * Flush a context's buffer.
732
741
  */
733
742
  flush(contextId) {
734
- if (!this.ws || this.ws.readyState !== WebSocketImpl.OPEN) return;
743
+ if (!this.ws || this.ws.readyState !== WS_OPEN) return;
735
744
  this.ws.send(JSON.stringify({
736
745
  flush: true,
737
746
  context_id: contextId
@@ -741,7 +750,7 @@ var MultiContextSession = class {
741
750
  * Close a specific context.
742
751
  */
743
752
  closeContext(contextId) {
744
- if (!this.ws || this.ws.readyState !== WebSocketImpl.OPEN) return;
753
+ if (!this.ws || this.ws.readyState !== WS_OPEN) return;
745
754
  this.ws.send(JSON.stringify({
746
755
  close_context: true,
747
756
  context_id: contextId
@@ -751,7 +760,7 @@ var MultiContextSession = class {
751
760
  * Send keep-alive to reset a context's inactivity timeout.
752
761
  */
753
762
  keepAlive(contextId) {
754
- if (!this.ws || this.ws.readyState !== WebSocketImpl.OPEN) return;
763
+ if (!this.ws || this.ws.readyState !== WS_OPEN) return;
755
764
  this.ws.send(JSON.stringify({
756
765
  text: "",
757
766
  context_id: contextId
@@ -761,7 +770,7 @@ var MultiContextSession = class {
761
770
  * Close the session and all contexts.
762
771
  */
763
772
  close() {
764
- if (this.ws && this.ws.readyState === WebSocketImpl.OPEN) {
773
+ if (this.ws && this.ws.readyState === WS_OPEN) {
765
774
  this.ws.send(JSON.stringify({ close_socket: true }));
766
775
  this.ws.close();
767
776
  }
@@ -779,7 +788,7 @@ var MultiContextSession = class {
779
788
  * Check if connected.
780
789
  */
781
790
  get isConnected() {
782
- return this.ws !== null && this.ws.readyState === WebSocketImpl.OPEN;
791
+ return this.ws !== null && this.ws.readyState === WS_OPEN;
783
792
  }
784
793
  };
785
794
  var KugelAudio = class _KugelAudio {
package/dist/index.mjs CHANGED
@@ -107,25 +107,34 @@ function createWavBlob(audio, sampleRate) {
107
107
  }
108
108
 
109
109
  // src/websocket.ts
110
- var isBrowser = typeof window !== "undefined" && typeof window.WebSocket !== "undefined";
110
+ var _cachedWs = null;
111
111
  function getWebSocket() {
112
- if (isBrowser) {
113
- return window.WebSocket;
112
+ if (_cachedWs) return _cachedWs;
113
+ if (typeof globalThis !== "undefined" && typeof globalThis.WebSocket !== "undefined") {
114
+ _cachedWs = globalThis.WebSocket;
115
+ return _cachedWs;
114
116
  }
115
117
  try {
116
- const ws = __require("ws");
117
- return ws;
118
+ const _require = typeof __require !== "undefined" ? __require : Function('return typeof require !== "undefined" ? require : undefined')();
119
+ if (_require) {
120
+ const ws = _require("ws");
121
+ _cachedWs = ws.default || ws;
122
+ return _cachedWs;
123
+ }
118
124
  } catch {
119
- throw new Error(
120
- 'WebSocket not available. In Node.js, install the "ws" package: npm install ws'
121
- );
122
125
  }
126
+ throw new Error(
127
+ 'WebSocket not available. In Node.js, install the "ws" package: npm install ws'
128
+ );
123
129
  }
124
- var WebSocketCompat = getWebSocket();
125
130
 
126
131
  // src/client.ts
127
132
  var DEFAULT_API_URL = "https://api.kugelaudio.com";
128
- var WebSocketImpl = getWebSocket();
133
+ function createWs(url) {
134
+ const WS = getWebSocket();
135
+ return new WS(url);
136
+ }
137
+ var WS_OPEN = 1;
129
138
  var ModelsResource = class {
130
139
  constructor(client) {
131
140
  this.client = client;
@@ -231,7 +240,7 @@ var TTSResource = class {
231
240
  * Check if WebSocket connection is established and open.
232
241
  */
233
242
  isConnected() {
234
- return this.wsConnection !== null && this.wsConnection.readyState === WebSocketImpl.OPEN;
243
+ return this.wsConnection !== null && this.wsConnection.readyState === WS_OPEN;
235
244
  }
236
245
  /**
237
246
  * Generate audio from text with streaming via WebSocket.
@@ -289,7 +298,7 @@ var TTSResource = class {
289
298
  */
290
299
  async getConnection() {
291
300
  const url = this.buildWsUrl();
292
- if (this.wsConnection && this.wsUrl === url && this.wsConnection.readyState === WebSocketImpl.OPEN) {
301
+ if (this.wsConnection && this.wsUrl === url && this.wsConnection.readyState === WS_OPEN) {
293
302
  return this.wsConnection;
294
303
  }
295
304
  if (this.wsConnection) {
@@ -300,7 +309,7 @@ var TTSResource = class {
300
309
  this.wsConnection = null;
301
310
  }
302
311
  return new Promise((resolve, reject) => {
303
- const ws = new WebSocketImpl(url);
312
+ const ws = createWs(url);
304
313
  ws.onopen = () => {
305
314
  this.wsConnection = ws;
306
315
  this.wsUrl = url;
@@ -422,7 +431,7 @@ var TTSResource = class {
422
431
  streamWithoutPooling(options, callbacks) {
423
432
  return new Promise((resolve, reject) => {
424
433
  const url = this.buildWsUrl();
425
- const ws = new WebSocketImpl(url);
434
+ const ws = createWs(url);
426
435
  ws.onopen = () => {
427
436
  callbacks.onOpen?.();
428
437
  ws.send(JSON.stringify({
@@ -585,7 +594,7 @@ var MultiContextSession = class {
585
594
  authParam = "api_key";
586
595
  }
587
596
  const url = `${wsUrl}/ws/tts/multi?${authParam}=${this.client.apiKey}`;
588
- this.ws = new WebSocketImpl(url);
597
+ this.ws = createWs(url);
589
598
  this.ws.onopen = () => {
590
599
  };
591
600
  this.ws.onmessage = (event) => {
@@ -655,7 +664,7 @@ var MultiContextSession = class {
655
664
  * Create a new context with optional voice settings.
656
665
  */
657
666
  createContext(contextId, options) {
658
- if (!this.ws || this.ws.readyState !== WebSocketImpl.OPEN) {
667
+ if (!this.ws || this.ws.readyState !== WS_OPEN) {
659
668
  throw new KugelAudioError("WebSocket not connected");
660
669
  }
661
670
  const msg = {
@@ -686,7 +695,7 @@ var MultiContextSession = class {
686
695
  * Send text to a specific context.
687
696
  */
688
697
  send(contextId, text, flush = false) {
689
- if (!this.ws || this.ws.readyState !== WebSocketImpl.OPEN) {
698
+ if (!this.ws || this.ws.readyState !== WS_OPEN) {
690
699
  throw new KugelAudioError("WebSocket not connected");
691
700
  }
692
701
  if (!this.contexts.has(contextId) && !this.isStarted) {
@@ -702,7 +711,7 @@ var MultiContextSession = class {
702
711
  * Flush a context's buffer.
703
712
  */
704
713
  flush(contextId) {
705
- if (!this.ws || this.ws.readyState !== WebSocketImpl.OPEN) return;
714
+ if (!this.ws || this.ws.readyState !== WS_OPEN) return;
706
715
  this.ws.send(JSON.stringify({
707
716
  flush: true,
708
717
  context_id: contextId
@@ -712,7 +721,7 @@ var MultiContextSession = class {
712
721
  * Close a specific context.
713
722
  */
714
723
  closeContext(contextId) {
715
- if (!this.ws || this.ws.readyState !== WebSocketImpl.OPEN) return;
724
+ if (!this.ws || this.ws.readyState !== WS_OPEN) return;
716
725
  this.ws.send(JSON.stringify({
717
726
  close_context: true,
718
727
  context_id: contextId
@@ -722,7 +731,7 @@ var MultiContextSession = class {
722
731
  * Send keep-alive to reset a context's inactivity timeout.
723
732
  */
724
733
  keepAlive(contextId) {
725
- if (!this.ws || this.ws.readyState !== WebSocketImpl.OPEN) return;
734
+ if (!this.ws || this.ws.readyState !== WS_OPEN) return;
726
735
  this.ws.send(JSON.stringify({
727
736
  text: "",
728
737
  context_id: contextId
@@ -732,7 +741,7 @@ var MultiContextSession = class {
732
741
  * Close the session and all contexts.
733
742
  */
734
743
  close() {
735
- if (this.ws && this.ws.readyState === WebSocketImpl.OPEN) {
744
+ if (this.ws && this.ws.readyState === WS_OPEN) {
736
745
  this.ws.send(JSON.stringify({ close_socket: true }));
737
746
  this.ws.close();
738
747
  }
@@ -750,7 +759,7 @@ var MultiContextSession = class {
750
759
  * Check if connected.
751
760
  */
752
761
  get isConnected() {
753
- return this.ws !== null && this.ws.readyState === WebSocketImpl.OPEN;
762
+ return this.ws !== null && this.ws.readyState === WS_OPEN;
754
763
  }
755
764
  };
756
765
  var KugelAudio = class _KugelAudio {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kugelaudio",
3
- "version": "0.1.12",
3
+ "version": "0.1.14",
4
4
  "description": "Official JavaScript/TypeScript SDK for KugelAudio TTS API",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
package/src/client.ts CHANGED
@@ -23,8 +23,18 @@ import { getWebSocket } from './websocket';
23
23
 
24
24
  const DEFAULT_API_URL = 'https://api.kugelaudio.com';
25
25
 
26
- // Get WebSocket constructor for current environment
27
- const WebSocketImpl = getWebSocket();
26
+ /**
27
+ * Create a new WebSocket instance.
28
+ * Lazily resolves the constructor to avoid top-level side-effects
29
+ * that break server-side bundlers (Turbopack/Webpack).
30
+ */
31
+ function createWs(url: string): WebSocket {
32
+ const WS = getWebSocket();
33
+ return new WS(url);
34
+ }
35
+
36
+ /** WebSocket OPEN readyState constant. */
37
+ const WS_OPEN = 1;
28
38
 
29
39
  /**
30
40
  * Models resource for listing TTS models.
@@ -116,7 +126,7 @@ class VoicesResource {
116
126
  */
117
127
  class TTSResource {
118
128
  // Using any for WebSocket to support both browser WebSocket and ws package
119
- private wsConnection: InstanceType<typeof WebSocketImpl> | null = null;
129
+ private wsConnection: WebSocket | null = null;
120
130
  private wsUrl: string | null = null;
121
131
  private pendingRequests: Map<number, {
122
132
  callbacks: StreamCallbacks;
@@ -152,7 +162,7 @@ class TTSResource {
152
162
  * Check if WebSocket connection is established and open.
153
163
  */
154
164
  isConnected(): boolean {
155
- return this.wsConnection !== null && this.wsConnection.readyState === WebSocketImpl.OPEN;
165
+ return this.wsConnection !== null && this.wsConnection.readyState === WS_OPEN;
156
166
  }
157
167
 
158
168
  /**
@@ -219,14 +229,14 @@ class TTSResource {
219
229
  * Get or create a WebSocket connection for connection pooling.
220
230
  * This avoids the ~220ms connect overhead on each request.
221
231
  */
222
- private async getConnection(): Promise<InstanceType<typeof WebSocketImpl>> {
232
+ private async getConnection(): Promise<WebSocket> {
223
233
  const url = this.buildWsUrl();
224
234
 
225
235
  // Return existing connection if valid
226
236
  if (
227
237
  this.wsConnection &&
228
238
  this.wsUrl === url &&
229
- this.wsConnection.readyState === WebSocketImpl.OPEN
239
+ this.wsConnection.readyState === WS_OPEN
230
240
  ) {
231
241
  return this.wsConnection;
232
242
  }
@@ -243,7 +253,7 @@ class TTSResource {
243
253
 
244
254
  // Create new connection
245
255
  return new Promise((resolve, reject) => {
246
- const ws = new WebSocketImpl(url);
256
+ const ws = createWs(url);
247
257
 
248
258
  ws.onopen = () => {
249
259
  this.wsConnection = ws;
@@ -261,7 +271,7 @@ class TTSResource {
261
271
  /**
262
272
  * Setup message handler for pooled connection.
263
273
  */
264
- private setupMessageHandler(ws: InstanceType<typeof WebSocketImpl>): void {
274
+ private setupMessageHandler(ws: WebSocket): void {
265
275
  ws.onmessage = (event: { data: unknown }) => {
266
276
  try {
267
277
  // Handle both browser (string) and Node.js (Buffer) message formats
@@ -400,7 +410,7 @@ class TTSResource {
400
410
  ): Promise<void> {
401
411
  return new Promise((resolve, reject) => {
402
412
  const url = this.buildWsUrl();
403
- const ws = new WebSocketImpl(url);
413
+ const ws = createWs(url);
404
414
 
405
415
  ws.onopen = () => {
406
416
  callbacks.onOpen?.();
@@ -556,7 +566,7 @@ class TTSResource {
556
566
  * Multi-context WebSocket session for concurrent TTS streams.
557
567
  */
558
568
  class MultiContextSession {
559
- private ws: InstanceType<typeof WebSocketImpl> | null = null;
569
+ private ws: WebSocket | null = null;
560
570
  private config: import('./types').MultiContextConfig;
561
571
  private callbacks: import('./types').MultiContextCallbacks = {};
562
572
  private contexts: Set<string> = new Set();
@@ -597,7 +607,7 @@ class MultiContextSession {
597
607
  }
598
608
 
599
609
  const url = `${wsUrl}/ws/tts/multi?${authParam}=${this.client.apiKey}`;
600
- this.ws = new WebSocketImpl(url);
610
+ this.ws = createWs(url);
601
611
 
602
612
  this.ws.onopen = () => {
603
613
  // Connection established, ready to create contexts
@@ -692,7 +702,7 @@ class MultiContextSession {
692
702
  voiceSettings?: import('./types').ContextVoiceSettings;
693
703
  }
694
704
  ): void {
695
- if (!this.ws || this.ws.readyState !== WebSocketImpl.OPEN) {
705
+ if (!this.ws || this.ws.readyState !== WS_OPEN) {
696
706
  throw new KugelAudioError('WebSocket not connected');
697
707
  }
698
708
 
@@ -731,7 +741,7 @@ class MultiContextSession {
731
741
  * Send text to a specific context.
732
742
  */
733
743
  send(contextId: string, text: string, flush = false): void {
734
- if (!this.ws || this.ws.readyState !== WebSocketImpl.OPEN) {
744
+ if (!this.ws || this.ws.readyState !== WS_OPEN) {
735
745
  throw new KugelAudioError('WebSocket not connected');
736
746
  }
737
747
 
@@ -751,7 +761,7 @@ class MultiContextSession {
751
761
  * Flush a context's buffer.
752
762
  */
753
763
  flush(contextId: string): void {
754
- if (!this.ws || this.ws.readyState !== WebSocketImpl.OPEN) return;
764
+ if (!this.ws || this.ws.readyState !== WS_OPEN) return;
755
765
 
756
766
  this.ws.send(JSON.stringify({
757
767
  flush: true,
@@ -763,7 +773,7 @@ class MultiContextSession {
763
773
  * Close a specific context.
764
774
  */
765
775
  closeContext(contextId: string): void {
766
- if (!this.ws || this.ws.readyState !== WebSocketImpl.OPEN) return;
776
+ if (!this.ws || this.ws.readyState !== WS_OPEN) return;
767
777
 
768
778
  this.ws.send(JSON.stringify({
769
779
  close_context: true,
@@ -775,7 +785,7 @@ class MultiContextSession {
775
785
  * Send keep-alive to reset a context's inactivity timeout.
776
786
  */
777
787
  keepAlive(contextId: string): void {
778
- if (!this.ws || this.ws.readyState !== WebSocketImpl.OPEN) return;
788
+ if (!this.ws || this.ws.readyState !== WS_OPEN) return;
779
789
 
780
790
  this.ws.send(JSON.stringify({
781
791
  text: '',
@@ -787,7 +797,7 @@ class MultiContextSession {
787
797
  * Close the session and all contexts.
788
798
  */
789
799
  close(): void {
790
- if (this.ws && this.ws.readyState === WebSocketImpl.OPEN) {
800
+ if (this.ws && this.ws.readyState === WS_OPEN) {
791
801
  this.ws.send(JSON.stringify({ close_socket: true }));
792
802
  this.ws.close();
793
803
  }
@@ -807,7 +817,7 @@ class MultiContextSession {
807
817
  * Check if connected.
808
818
  */
809
819
  get isConnected(): boolean {
810
- return this.ws !== null && this.ws.readyState === WebSocketImpl.OPEN;
820
+ return this.ws !== null && this.ws.readyState === WS_OPEN;
811
821
  }
812
822
  }
813
823
 
package/src/websocket.ts CHANGED
@@ -1,33 +1,44 @@
1
1
  /**
2
2
  * WebSocket compatibility layer for browser and Node.js environments.
3
+ *
4
+ * IMPORTANT: WebSocket resolution is lazy to avoid top-level side-effects
5
+ * that break server-side bundlers (Turbopack / Webpack) when this module
6
+ * is imported in a Node.js (API route) context.
3
7
  */
4
8
 
5
- // Detect environment
6
- const isBrowser = typeof window !== 'undefined' && typeof window.WebSocket !== 'undefined';
9
+ let _cachedWs: typeof WebSocket | null = null;
7
10
 
8
11
  /**
9
12
  * Get the WebSocket constructor for the current environment.
10
13
  * Uses native WebSocket in browsers, ws package in Node.js.
14
+ * Result is cached after first call.
11
15
  */
12
16
  export function getWebSocket(): typeof WebSocket {
13
- if (isBrowser) {
14
- return window.WebSocket;
17
+ if (_cachedWs) return _cachedWs;
18
+
19
+ // Browser environment
20
+ if (typeof globalThis !== 'undefined' && typeof (globalThis as any).WebSocket !== 'undefined') {
21
+ _cachedWs = (globalThis as any).WebSocket;
22
+ return _cachedWs!;
15
23
  }
16
-
17
- // Node.js environment - use ws package
24
+
25
+ // Node.js environment - use ws package via dynamic require
18
26
  try {
19
- // Dynamic require to avoid bundler issues
20
- // eslint-disable-next-line @typescript-eslint/no-var-requires
21
- const ws = require('ws');
22
- return ws;
27
+ // Use Function constructor to hide require from static analysis by bundlers
28
+ // eslint-disable-next-line no-new-func
29
+ const _require = typeof require !== 'undefined'
30
+ ? require
31
+ : Function('return typeof require !== "undefined" ? require : undefined')();
32
+ if (_require) {
33
+ const ws = _require('ws');
34
+ _cachedWs = ws.default || ws;
35
+ return _cachedWs!;
36
+ }
23
37
  } catch {
24
- throw new Error(
25
- 'WebSocket not available. In Node.js, install the "ws" package: npm install ws'
26
- );
38
+ // Fall through to error
27
39
  }
28
- }
29
40
 
30
- /**
31
- * WebSocket constructor that works in both environments.
32
- */
33
- export const WebSocketCompat = getWebSocket();
41
+ throw new Error(
42
+ 'WebSocket not available. In Node.js, install the "ws" package: npm install ws'
43
+ );
44
+ }