@reactor-team/js-sdk 1.0.9 → 1.0.11
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.d.mts +12 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +264 -21
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +270 -23
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -33,6 +33,7 @@ declare const OptionsSchema: z.ZodObject<{
|
|
|
33
33
|
jwtToken: z.ZodOptional<z.ZodString>;
|
|
34
34
|
coordinatorUrl: z.ZodDefault<z.ZodString>;
|
|
35
35
|
modelName: z.ZodString;
|
|
36
|
+
queueing: z.ZodDefault<z.ZodBoolean>;
|
|
36
37
|
}, z.core.$strip>;
|
|
37
38
|
type Options = z.input<typeof OptionsSchema>;
|
|
38
39
|
type EventHandler = (...args: any[]) => void;
|
|
@@ -48,6 +49,7 @@ declare class Reactor {
|
|
|
48
49
|
private directConnection?;
|
|
49
50
|
private modelName;
|
|
50
51
|
private modelVersion;
|
|
52
|
+
private queueing;
|
|
51
53
|
constructor(options: Options);
|
|
52
54
|
private eventListeners;
|
|
53
55
|
on(event: ReactorEvent, handler: EventHandler): void;
|
|
@@ -60,6 +62,16 @@ declare class Reactor {
|
|
|
60
62
|
* @throws Error if not in ready state
|
|
61
63
|
*/
|
|
62
64
|
sendMessage(message: any): Promise<void>;
|
|
65
|
+
/**
|
|
66
|
+
* Public method to publish a video stream to the machine.
|
|
67
|
+
* @param videoStream The video stream to send to the machine.
|
|
68
|
+
*/
|
|
69
|
+
publishVideoStream(videoStream: MediaStream): Promise<void>;
|
|
70
|
+
/**
|
|
71
|
+
* Public method to unpublish video stream to the machine.
|
|
72
|
+
* This unpublishes the video track that was previously sent.
|
|
73
|
+
*/
|
|
74
|
+
unpublishVideoStream(): Promise<void>;
|
|
63
75
|
/**
|
|
64
76
|
* Connects to the machine via LiveKit and waits for the gpu machine to be ready.
|
|
65
77
|
* Once the machine is ready, the Reactor will establish the LiveKit connection.
|
package/dist/index.d.ts
CHANGED
|
@@ -33,6 +33,7 @@ declare const OptionsSchema: z.ZodObject<{
|
|
|
33
33
|
jwtToken: z.ZodOptional<z.ZodString>;
|
|
34
34
|
coordinatorUrl: z.ZodDefault<z.ZodString>;
|
|
35
35
|
modelName: z.ZodString;
|
|
36
|
+
queueing: z.ZodDefault<z.ZodBoolean>;
|
|
36
37
|
}, z.core.$strip>;
|
|
37
38
|
type Options = z.input<typeof OptionsSchema>;
|
|
38
39
|
type EventHandler = (...args: any[]) => void;
|
|
@@ -48,6 +49,7 @@ declare class Reactor {
|
|
|
48
49
|
private directConnection?;
|
|
49
50
|
private modelName;
|
|
50
51
|
private modelVersion;
|
|
52
|
+
private queueing;
|
|
51
53
|
constructor(options: Options);
|
|
52
54
|
private eventListeners;
|
|
53
55
|
on(event: ReactorEvent, handler: EventHandler): void;
|
|
@@ -60,6 +62,16 @@ declare class Reactor {
|
|
|
60
62
|
* @throws Error if not in ready state
|
|
61
63
|
*/
|
|
62
64
|
sendMessage(message: any): Promise<void>;
|
|
65
|
+
/**
|
|
66
|
+
* Public method to publish a video stream to the machine.
|
|
67
|
+
* @param videoStream The video stream to send to the machine.
|
|
68
|
+
*/
|
|
69
|
+
publishVideoStream(videoStream: MediaStream): Promise<void>;
|
|
70
|
+
/**
|
|
71
|
+
* Public method to unpublish video stream to the machine.
|
|
72
|
+
* This unpublishes the video track that was previously sent.
|
|
73
|
+
*/
|
|
74
|
+
unpublishVideoStream(): Promise<void>;
|
|
63
75
|
/**
|
|
64
76
|
* Connects to the machine via LiveKit and waits for the gpu machine to be ready.
|
|
65
77
|
* Once the machine is ready, the Reactor will establish the LiveKit connection.
|
package/dist/index.js
CHANGED
|
@@ -142,7 +142,8 @@ var OptionsSchema = import_zod2.z.object({
|
|
|
142
142
|
jwtToken: import_zod2.z.string().optional(),
|
|
143
143
|
insecureApiKey: import_zod2.z.string().optional(),
|
|
144
144
|
modelName: import_zod2.z.string(),
|
|
145
|
-
modelVersion: import_zod2.z.string().default("latest")
|
|
145
|
+
modelVersion: import_zod2.z.string().default("latest"),
|
|
146
|
+
queueing: import_zod2.z.boolean().default(false)
|
|
146
147
|
}).refine((data) => data.jwtToken || data.insecureApiKey, {
|
|
147
148
|
message: "At least one of jwtToken or insecureApiKey must be provided."
|
|
148
149
|
});
|
|
@@ -155,6 +156,7 @@ var CoordinatorClient = class {
|
|
|
155
156
|
this.insecureApiKey = validatedOptions.insecureApiKey;
|
|
156
157
|
this.modelName = validatedOptions.modelName;
|
|
157
158
|
this.modelVersion = validatedOptions.modelVersion;
|
|
159
|
+
this.queueing = validatedOptions.queueing;
|
|
158
160
|
}
|
|
159
161
|
// Event Emitter API
|
|
160
162
|
on(event, handler) {
|
|
@@ -189,6 +191,9 @@ var CoordinatorClient = class {
|
|
|
189
191
|
} else if (this.insecureApiKey) {
|
|
190
192
|
url.searchParams.set("api_key", this.insecureApiKey);
|
|
191
193
|
}
|
|
194
|
+
if (this.queueing) {
|
|
195
|
+
url.searchParams.set("queueing", "true");
|
|
196
|
+
}
|
|
192
197
|
console.debug("[CoordinatorClient] Connecting to", url.toString());
|
|
193
198
|
this.websocket = new WebSocket(url.toString());
|
|
194
199
|
this.websocket.onopen = () => {
|
|
@@ -382,6 +387,12 @@ var GPUMachineClient = class {
|
|
|
382
387
|
*/
|
|
383
388
|
disconnect() {
|
|
384
389
|
return __async(this, null, function* () {
|
|
390
|
+
if (this.publishedVideoTrack) {
|
|
391
|
+
yield this.unpublishVideoTrack();
|
|
392
|
+
}
|
|
393
|
+
if (this.publishedAudioTrack) {
|
|
394
|
+
yield this.unpublishAudioTrack();
|
|
395
|
+
}
|
|
385
396
|
if (this.roomInstance) {
|
|
386
397
|
console.debug("[GPUMachineClient] Closing LiveKit connection");
|
|
387
398
|
yield this.roomInstance.disconnect();
|
|
@@ -404,6 +415,126 @@ var GPUMachineClient = class {
|
|
|
404
415
|
getVideoStream() {
|
|
405
416
|
return this.videoStream;
|
|
406
417
|
}
|
|
418
|
+
/**
|
|
419
|
+
* Publishes a video track from the provided MediaStream to the LiveKit room.
|
|
420
|
+
* Only one video track can be published at a time. If a video track is already
|
|
421
|
+
* published, it will be unpublished first.
|
|
422
|
+
*
|
|
423
|
+
* @param mediaStream The MediaStream containing the video track to publish
|
|
424
|
+
* @throws Error if no video track is found in the MediaStream or room is not connected
|
|
425
|
+
*/
|
|
426
|
+
publishVideoTrack(mediaStream) {
|
|
427
|
+
return __async(this, null, function* () {
|
|
428
|
+
if (!this.roomInstance) {
|
|
429
|
+
throw new Error(
|
|
430
|
+
"[GPUMachineClient] Cannot publish track - not connected to room"
|
|
431
|
+
);
|
|
432
|
+
}
|
|
433
|
+
const videoTracks = mediaStream.getVideoTracks();
|
|
434
|
+
if (videoTracks.length === 0) {
|
|
435
|
+
throw new Error("[GPUMachineClient] No video track found in MediaStream");
|
|
436
|
+
}
|
|
437
|
+
if (this.publishedVideoTrack) {
|
|
438
|
+
yield this.unpublishVideoTrack();
|
|
439
|
+
}
|
|
440
|
+
try {
|
|
441
|
+
const videoTrack = videoTracks[0];
|
|
442
|
+
const localVideoTrack = yield this.roomInstance.localParticipant.publishTrack(videoTrack, {
|
|
443
|
+
name: "client-video",
|
|
444
|
+
source: import_livekit_client.Track.Source.Camera
|
|
445
|
+
});
|
|
446
|
+
this.publishedVideoTrack = localVideoTrack.track;
|
|
447
|
+
console.debug("[GPUMachineClient] Video track published successfully");
|
|
448
|
+
} catch (error) {
|
|
449
|
+
console.error("[GPUMachineClient] Failed to publish video track:", error);
|
|
450
|
+
throw error;
|
|
451
|
+
}
|
|
452
|
+
});
|
|
453
|
+
}
|
|
454
|
+
/**
|
|
455
|
+
* Unpublishes the currently published video track.
|
|
456
|
+
*/
|
|
457
|
+
unpublishVideoTrack() {
|
|
458
|
+
return __async(this, null, function* () {
|
|
459
|
+
if (!this.roomInstance || !this.publishedVideoTrack) {
|
|
460
|
+
return;
|
|
461
|
+
}
|
|
462
|
+
try {
|
|
463
|
+
yield this.roomInstance.localParticipant.unpublishTrack(
|
|
464
|
+
this.publishedVideoTrack
|
|
465
|
+
);
|
|
466
|
+
this.publishedVideoTrack.stop();
|
|
467
|
+
this.publishedVideoTrack = void 0;
|
|
468
|
+
console.debug("[GPUMachineClient] Video track unpublished successfully");
|
|
469
|
+
} catch (error) {
|
|
470
|
+
console.error(
|
|
471
|
+
"[GPUMachineClient] Failed to unpublish video track:",
|
|
472
|
+
error
|
|
473
|
+
);
|
|
474
|
+
throw error;
|
|
475
|
+
}
|
|
476
|
+
});
|
|
477
|
+
}
|
|
478
|
+
/**
|
|
479
|
+
* Publishes an audio track from the provided MediaStream to the LiveKit room.
|
|
480
|
+
* This is an internal method. Only one audio track can be published at a time.
|
|
481
|
+
*
|
|
482
|
+
* @param mediaStream The MediaStream containing the audio track to publish
|
|
483
|
+
* @private
|
|
484
|
+
*/
|
|
485
|
+
publishAudioTrack(mediaStream) {
|
|
486
|
+
return __async(this, null, function* () {
|
|
487
|
+
if (!this.roomInstance) {
|
|
488
|
+
throw new Error(
|
|
489
|
+
"[GPUMachineClient] Cannot publish track - not connected to room"
|
|
490
|
+
);
|
|
491
|
+
}
|
|
492
|
+
const audioTracks = mediaStream.getAudioTracks();
|
|
493
|
+
if (audioTracks.length === 0) {
|
|
494
|
+
throw new Error("[GPUMachineClient] No audio track found in MediaStream");
|
|
495
|
+
}
|
|
496
|
+
if (this.publishedAudioTrack) {
|
|
497
|
+
yield this.unpublishAudioTrack();
|
|
498
|
+
}
|
|
499
|
+
try {
|
|
500
|
+
const audioTrack = audioTracks[0];
|
|
501
|
+
const localAudioTrack = yield this.roomInstance.localParticipant.publishTrack(audioTrack, {
|
|
502
|
+
name: "client-audio",
|
|
503
|
+
source: import_livekit_client.Track.Source.Microphone
|
|
504
|
+
});
|
|
505
|
+
this.publishedAudioTrack = localAudioTrack.track;
|
|
506
|
+
console.debug("[GPUMachineClient] Audio track published successfully");
|
|
507
|
+
} catch (error) {
|
|
508
|
+
console.error("[GPUMachineClient] Failed to publish audio track:", error);
|
|
509
|
+
throw error;
|
|
510
|
+
}
|
|
511
|
+
});
|
|
512
|
+
}
|
|
513
|
+
/**
|
|
514
|
+
* Unpublishes the currently published audio track.
|
|
515
|
+
* @private
|
|
516
|
+
*/
|
|
517
|
+
unpublishAudioTrack() {
|
|
518
|
+
return __async(this, null, function* () {
|
|
519
|
+
if (!this.roomInstance || !this.publishedAudioTrack) {
|
|
520
|
+
return;
|
|
521
|
+
}
|
|
522
|
+
try {
|
|
523
|
+
yield this.roomInstance.localParticipant.unpublishTrack(
|
|
524
|
+
this.publishedAudioTrack
|
|
525
|
+
);
|
|
526
|
+
this.publishedAudioTrack.stop();
|
|
527
|
+
this.publishedAudioTrack = void 0;
|
|
528
|
+
console.debug("[GPUMachineClient] Audio track unpublished successfully");
|
|
529
|
+
} catch (error) {
|
|
530
|
+
console.error(
|
|
531
|
+
"[GPUMachineClient] Failed to unpublish audio track:",
|
|
532
|
+
error
|
|
533
|
+
);
|
|
534
|
+
throw error;
|
|
535
|
+
}
|
|
536
|
+
});
|
|
537
|
+
}
|
|
407
538
|
};
|
|
408
539
|
|
|
409
540
|
// src/core/Reactor.ts
|
|
@@ -416,7 +547,8 @@ var OptionsSchema2 = import_zod3.z.object({
|
|
|
416
547
|
insecureApiKey: import_zod3.z.string().optional(),
|
|
417
548
|
jwtToken: import_zod3.z.string().optional(),
|
|
418
549
|
coordinatorUrl: import_zod3.z.string().default("wss://api.reactor.inc/ws"),
|
|
419
|
-
modelName: import_zod3.z.string()
|
|
550
|
+
modelName: import_zod3.z.string(),
|
|
551
|
+
queueing: import_zod3.z.boolean().default(false)
|
|
420
552
|
}).refine(
|
|
421
553
|
(data) => data.directConnection || data.insecureApiKey || data.jwtToken,
|
|
422
554
|
{
|
|
@@ -435,6 +567,7 @@ var Reactor = class {
|
|
|
435
567
|
this.insecureApiKey = validatedOptions.insecureApiKey;
|
|
436
568
|
this.directConnection = validatedOptions.directConnection;
|
|
437
569
|
this.modelName = validatedOptions.modelName;
|
|
570
|
+
this.queueing = validatedOptions.queueing;
|
|
438
571
|
this.modelVersion = "1.0.0";
|
|
439
572
|
}
|
|
440
573
|
// Event Emitter API
|
|
@@ -483,6 +616,51 @@ var Reactor = class {
|
|
|
483
616
|
}
|
|
484
617
|
});
|
|
485
618
|
}
|
|
619
|
+
/**
|
|
620
|
+
* Public method to publish a video stream to the machine.
|
|
621
|
+
* @param videoStream The video stream to send to the machine.
|
|
622
|
+
*/
|
|
623
|
+
publishVideoStream(videoStream) {
|
|
624
|
+
return __async(this, null, function* () {
|
|
625
|
+
var _a;
|
|
626
|
+
if (process.env.NODE_ENV !== "development" && this.status !== "ready") {
|
|
627
|
+
const errorMessage = `Cannot publish video stream, status is ${this.status}`;
|
|
628
|
+
console.error("[Reactor] Not ready, cannot publish video stream");
|
|
629
|
+
throw new Error(errorMessage);
|
|
630
|
+
}
|
|
631
|
+
try {
|
|
632
|
+
yield (_a = this.machineClient) == null ? void 0 : _a.publishVideoTrack(videoStream);
|
|
633
|
+
} catch (error) {
|
|
634
|
+
console.error("[Reactor] Failed to publish video:", error);
|
|
635
|
+
this.createError(
|
|
636
|
+
"VIDEO_PUBLISH_FAILED",
|
|
637
|
+
`Failed to publish video: ${error}`,
|
|
638
|
+
"gpu",
|
|
639
|
+
true
|
|
640
|
+
);
|
|
641
|
+
}
|
|
642
|
+
});
|
|
643
|
+
}
|
|
644
|
+
/**
|
|
645
|
+
* Public method to unpublish video stream to the machine.
|
|
646
|
+
* This unpublishes the video track that was previously sent.
|
|
647
|
+
*/
|
|
648
|
+
unpublishVideoStream() {
|
|
649
|
+
return __async(this, null, function* () {
|
|
650
|
+
var _a;
|
|
651
|
+
try {
|
|
652
|
+
yield (_a = this.machineClient) == null ? void 0 : _a.unpublishVideoTrack();
|
|
653
|
+
} catch (error) {
|
|
654
|
+
console.error("[Reactor] Failed to unpublish video:", error);
|
|
655
|
+
this.createError(
|
|
656
|
+
"VIDEO_UNPUBLISH_FAILED",
|
|
657
|
+
`Failed to unpublish video: ${error}`,
|
|
658
|
+
"gpu",
|
|
659
|
+
true
|
|
660
|
+
);
|
|
661
|
+
}
|
|
662
|
+
});
|
|
663
|
+
}
|
|
486
664
|
/**
|
|
487
665
|
* Connects to the machine via LiveKit and waits for the gpu machine to be ready.
|
|
488
666
|
* Once the machine is ready, the Reactor will establish the LiveKit connection.
|
|
@@ -557,7 +735,8 @@ var Reactor = class {
|
|
|
557
735
|
jwtToken: this.jwtToken,
|
|
558
736
|
insecureApiKey: this.insecureApiKey,
|
|
559
737
|
modelName: this.modelName,
|
|
560
|
-
modelVersion: this.modelVersion
|
|
738
|
+
modelVersion: this.modelVersion,
|
|
739
|
+
queueing: this.queueing
|
|
561
740
|
});
|
|
562
741
|
this.coordinatorClient.on(
|
|
563
742
|
"gpu-machine-assigned",
|
|
@@ -835,34 +1014,98 @@ function ReactorProvider(_a) {
|
|
|
835
1014
|
]);
|
|
836
1015
|
const storeRef = (0, import_react3.useRef)(void 0);
|
|
837
1016
|
const firstRender = (0, import_react3.useRef)(true);
|
|
838
|
-
|
|
839
|
-
var _a2, _b2;
|
|
840
|
-
const status = (_a2 = storeRef.current) == null ? void 0 : _a2.getState().status;
|
|
841
|
-
if (autoConnect && status === "disconnected") {
|
|
842
|
-
console.debug("[ReactorProvider] Starting autoconnect...");
|
|
843
|
-
(_b2 = storeRef.current) == null ? void 0 : _b2.getState().connect().then(() => {
|
|
844
|
-
console.debug("[ReactorProvider] Autoconnect successful");
|
|
845
|
-
}).catch((error) => {
|
|
846
|
-
console.error("[ReactorProvider] Failed to autoconnect:", error);
|
|
847
|
-
});
|
|
848
|
-
}
|
|
849
|
-
}
|
|
1017
|
+
const [_storeVersion, setStoreVersion] = (0, import_react3.useState)(0);
|
|
850
1018
|
if (storeRef.current === void 0) {
|
|
851
1019
|
console.debug("[ReactorProvider] Creating new reactor store");
|
|
852
1020
|
storeRef.current = createReactorStore(initReactorStore(props));
|
|
853
1021
|
console.debug("[ReactorProvider] Reactor store created successfully");
|
|
854
|
-
attemptAutoConnect();
|
|
855
1022
|
}
|
|
1023
|
+
const {
|
|
1024
|
+
coordinatorUrl,
|
|
1025
|
+
modelName,
|
|
1026
|
+
jwtToken,
|
|
1027
|
+
insecureApiKey,
|
|
1028
|
+
directConnection,
|
|
1029
|
+
queueing
|
|
1030
|
+
} = props;
|
|
856
1031
|
(0, import_react3.useEffect)(() => {
|
|
857
1032
|
if (firstRender.current) {
|
|
858
1033
|
firstRender.current = false;
|
|
859
|
-
|
|
1034
|
+
const current2 = storeRef.current;
|
|
1035
|
+
if (autoConnect && current2.getState().status === "disconnected") {
|
|
1036
|
+
console.debug(
|
|
1037
|
+
"[ReactorProvider] Starting autoconnect in first render..."
|
|
1038
|
+
);
|
|
1039
|
+
current2.getState().connect().then(() => {
|
|
1040
|
+
console.debug(
|
|
1041
|
+
"[ReactorProvider] Autoconnect successful in first render"
|
|
1042
|
+
);
|
|
1043
|
+
}).catch((error) => {
|
|
1044
|
+
console.error(
|
|
1045
|
+
"[ReactorProvider] Failed to autoconnect in first render:",
|
|
1046
|
+
error
|
|
1047
|
+
);
|
|
1048
|
+
});
|
|
1049
|
+
}
|
|
1050
|
+
return () => {
|
|
1051
|
+
console.debug(
|
|
1052
|
+
"[ReactorProvider] Disconnecting in cleanup for first render"
|
|
1053
|
+
);
|
|
1054
|
+
current2.getState().disconnect().then(() => {
|
|
1055
|
+
console.debug(
|
|
1056
|
+
"[ReactorProvider] Disconnect completed successfully in cleanup for first render"
|
|
1057
|
+
);
|
|
1058
|
+
}).catch((error) => {
|
|
1059
|
+
console.error(
|
|
1060
|
+
"[ReactorProvider] Failed to disconnect in cleanup for first render:",
|
|
1061
|
+
error
|
|
1062
|
+
);
|
|
1063
|
+
});
|
|
1064
|
+
};
|
|
860
1065
|
}
|
|
861
1066
|
console.debug("[ReactorProvider] Updating reactor store");
|
|
862
|
-
storeRef.current = createReactorStore(
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
1067
|
+
storeRef.current = createReactorStore(
|
|
1068
|
+
initReactorStore({
|
|
1069
|
+
coordinatorUrl,
|
|
1070
|
+
modelName,
|
|
1071
|
+
jwtToken,
|
|
1072
|
+
insecureApiKey,
|
|
1073
|
+
directConnection,
|
|
1074
|
+
queueing
|
|
1075
|
+
})
|
|
1076
|
+
);
|
|
1077
|
+
const current = storeRef.current;
|
|
1078
|
+
setStoreVersion((v) => v + 1);
|
|
1079
|
+
console.debug(
|
|
1080
|
+
"[ReactorProvider] Reactor store updated successfully, and increased version"
|
|
1081
|
+
);
|
|
1082
|
+
if (autoConnect && current.getState().status === "disconnected") {
|
|
1083
|
+
console.debug("[ReactorProvider] Starting autoconnect...");
|
|
1084
|
+
current.getState().connect().then(() => {
|
|
1085
|
+
console.debug("[ReactorProvider] Autoconnect successful");
|
|
1086
|
+
}).catch((error) => {
|
|
1087
|
+
console.error("[ReactorProvider] Failed to autoconnect:", error);
|
|
1088
|
+
});
|
|
1089
|
+
}
|
|
1090
|
+
return () => {
|
|
1091
|
+
console.debug("[ReactorProvider] Disconnecting in cleanup");
|
|
1092
|
+
current.getState().disconnect().then(() => {
|
|
1093
|
+
console.debug(
|
|
1094
|
+
"[ReactorProvider] Disconnect completed successfully in cleanup"
|
|
1095
|
+
);
|
|
1096
|
+
}).catch((error) => {
|
|
1097
|
+
console.error("[ReactorProvider] Failed to disconnect:", error);
|
|
1098
|
+
});
|
|
1099
|
+
};
|
|
1100
|
+
}, [
|
|
1101
|
+
coordinatorUrl,
|
|
1102
|
+
modelName,
|
|
1103
|
+
jwtToken,
|
|
1104
|
+
insecureApiKey,
|
|
1105
|
+
directConnection,
|
|
1106
|
+
queueing,
|
|
1107
|
+
autoConnect
|
|
1108
|
+
]);
|
|
866
1109
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ReactorContext.Provider, { value: storeRef.current, children });
|
|
867
1110
|
}
|
|
868
1111
|
function useReactorStore(selector) {
|