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 +31 -22
- package/dist/index.mjs +31 -22
- package/package.json +1 -1
- package/src/client.ts +28 -18
- package/src/websocket.ts +29 -18
package/dist/index.js
CHANGED
|
@@ -136,25 +136,34 @@ function createWavBlob(audio, sampleRate) {
|
|
|
136
136
|
}
|
|
137
137
|
|
|
138
138
|
// src/websocket.ts
|
|
139
|
-
var
|
|
139
|
+
var _cachedWs = null;
|
|
140
140
|
function getWebSocket() {
|
|
141
|
-
if (
|
|
142
|
-
|
|
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
|
|
146
|
-
|
|
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
|
-
|
|
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 ===
|
|
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 ===
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 !==
|
|
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 !==
|
|
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 !==
|
|
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 !==
|
|
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 !==
|
|
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 ===
|
|
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 ===
|
|
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
|
|
110
|
+
var _cachedWs = null;
|
|
111
111
|
function getWebSocket() {
|
|
112
|
-
if (
|
|
113
|
-
|
|
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
|
|
117
|
-
|
|
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
|
-
|
|
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 ===
|
|
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 ===
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 !==
|
|
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 !==
|
|
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 !==
|
|
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 !==
|
|
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 !==
|
|
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 ===
|
|
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 ===
|
|
762
|
+
return this.ws !== null && this.ws.readyState === WS_OPEN;
|
|
754
763
|
}
|
|
755
764
|
};
|
|
756
765
|
var KugelAudio = class _KugelAudio {
|
package/package.json
CHANGED
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
|
-
|
|
27
|
-
|
|
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:
|
|
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 ===
|
|
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<
|
|
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 ===
|
|
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 =
|
|
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:
|
|
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 =
|
|
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:
|
|
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 =
|
|
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 !==
|
|
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 !==
|
|
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 !==
|
|
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 !==
|
|
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 !==
|
|
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 ===
|
|
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 ===
|
|
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
|
-
|
|
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 (
|
|
14
|
-
|
|
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
|
-
//
|
|
20
|
-
// eslint-disable-next-line
|
|
21
|
-
const
|
|
22
|
-
|
|
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
|
-
|
|
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
|
-
|
|
32
|
-
|
|
33
|
-
|
|
41
|
+
throw new Error(
|
|
42
|
+
'WebSocket not available. In Node.js, install the "ws" package: npm install ws'
|
|
43
|
+
);
|
|
44
|
+
}
|