@reactor-team/js-sdk 2.2.1 → 2.3.1
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 +20 -7
- package/dist/index.d.ts +20 -7
- package/dist/index.js +76 -25
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +76 -25
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -3,6 +3,12 @@ import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
|
3
3
|
import React, { ReactNode } from 'react';
|
|
4
4
|
|
|
5
5
|
type ReactorStatus = "disconnected" | "connecting" | "waiting" | "ready";
|
|
6
|
+
/**
|
|
7
|
+
* The message scope identifies the envelope layer a data channel message belongs to.
|
|
8
|
+
* - "application": model-defined commands (client->runtime) and model-emitted payloads (runtime->client).
|
|
9
|
+
* - "runtime": platform-level control messages (e.g., capabilities exchange).
|
|
10
|
+
*/
|
|
11
|
+
type MessageScope = "application" | "runtime";
|
|
6
12
|
interface ReactorError {
|
|
7
13
|
code: string;
|
|
8
14
|
message: string;
|
|
@@ -45,11 +51,14 @@ declare class Reactor {
|
|
|
45
51
|
emit(event: ReactorEvent, ...args: any[]): void;
|
|
46
52
|
/**
|
|
47
53
|
* Public method to send a message to the machine.
|
|
48
|
-
*
|
|
49
|
-
* @param
|
|
54
|
+
* Wraps the message in the specified channel envelope (defaults to "application").
|
|
55
|
+
* @param command The command name to send.
|
|
56
|
+
* @param data The command payload.
|
|
57
|
+
* @param scope The envelope scope – "application" (default) for model commands,
|
|
58
|
+
* "runtime" for platform-level messages (e.g. requestCapabilities).
|
|
50
59
|
* @throws Error if not in ready state
|
|
51
60
|
*/
|
|
52
|
-
sendCommand(command: string, data: any): Promise<void>;
|
|
61
|
+
sendCommand(command: string, data: any, scope?: MessageScope): Promise<void>;
|
|
53
62
|
/**
|
|
54
63
|
* Public method to publish a track to the machine.
|
|
55
64
|
* @param track The track to send to the machine.
|
|
@@ -111,7 +120,7 @@ interface ReactorState {
|
|
|
111
120
|
jwtToken?: string;
|
|
112
121
|
}
|
|
113
122
|
interface ReactorActions {
|
|
114
|
-
sendCommand(command: string, data: any): Promise<void>;
|
|
123
|
+
sendCommand(command: string, data: any, scope?: MessageScope): Promise<void>;
|
|
115
124
|
connect(jwtToken?: string): Promise<void>;
|
|
116
125
|
disconnect(recoverable?: boolean): Promise<void>;
|
|
117
126
|
publishVideoStream(stream: MediaStream): Promise<void>;
|
|
@@ -170,9 +179,13 @@ declare function useReactor<T>(selector: (state: ReactorStore) => T): T;
|
|
|
170
179
|
/**
|
|
171
180
|
* Hook for handling message subscriptions with proper React lifecycle management.
|
|
172
181
|
*
|
|
173
|
-
*
|
|
182
|
+
* The handler receives the message payload and the scope it arrived on:
|
|
183
|
+
* - "application" for model-defined messages (via get_ctx().send())
|
|
184
|
+
* - "runtime" for platform-level messages (e.g., capabilities response)
|
|
185
|
+
*
|
|
186
|
+
* @param handler - The message handler function (message, scope)
|
|
174
187
|
*/
|
|
175
|
-
declare function useReactorMessage(handler: (message: any) => void): void;
|
|
188
|
+
declare function useReactorMessage(handler: (message: any, scope: MessageScope) => void): void;
|
|
176
189
|
|
|
177
190
|
/**
|
|
178
191
|
* ⚠️ INSECURE: Fetches a JWT token directly from the client.
|
|
@@ -187,4 +200,4 @@ declare function useReactorMessage(handler: (message: any) => void): void;
|
|
|
187
200
|
*/
|
|
188
201
|
declare function fetchInsecureJwtToken(apiKey: string, coordinatorUrl?: string): Promise<string>;
|
|
189
202
|
|
|
190
|
-
export { ConflictError, type Options, PROD_COORDINATOR_URL, Reactor, ReactorController, type ReactorControllerProps, type ReactorError, type ReactorEvent, ReactorProvider, type ReactorState$1 as ReactorState, type ReactorStatus, ReactorView, type ReactorViewProps, WebcamStream, fetchInsecureJwtToken, useReactor, useReactorMessage, useReactorStore };
|
|
203
|
+
export { ConflictError, type MessageScope, type Options, PROD_COORDINATOR_URL, Reactor, ReactorController, type ReactorControllerProps, type ReactorError, type ReactorEvent, ReactorProvider, type ReactorState$1 as ReactorState, type ReactorStatus, ReactorView, type ReactorViewProps, WebcamStream, fetchInsecureJwtToken, useReactor, useReactorMessage, useReactorStore };
|
package/dist/index.d.ts
CHANGED
|
@@ -3,6 +3,12 @@ import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
|
3
3
|
import React, { ReactNode } from 'react';
|
|
4
4
|
|
|
5
5
|
type ReactorStatus = "disconnected" | "connecting" | "waiting" | "ready";
|
|
6
|
+
/**
|
|
7
|
+
* The message scope identifies the envelope layer a data channel message belongs to.
|
|
8
|
+
* - "application": model-defined commands (client->runtime) and model-emitted payloads (runtime->client).
|
|
9
|
+
* - "runtime": platform-level control messages (e.g., capabilities exchange).
|
|
10
|
+
*/
|
|
11
|
+
type MessageScope = "application" | "runtime";
|
|
6
12
|
interface ReactorError {
|
|
7
13
|
code: string;
|
|
8
14
|
message: string;
|
|
@@ -45,11 +51,14 @@ declare class Reactor {
|
|
|
45
51
|
emit(event: ReactorEvent, ...args: any[]): void;
|
|
46
52
|
/**
|
|
47
53
|
* Public method to send a message to the machine.
|
|
48
|
-
*
|
|
49
|
-
* @param
|
|
54
|
+
* Wraps the message in the specified channel envelope (defaults to "application").
|
|
55
|
+
* @param command The command name to send.
|
|
56
|
+
* @param data The command payload.
|
|
57
|
+
* @param scope The envelope scope – "application" (default) for model commands,
|
|
58
|
+
* "runtime" for platform-level messages (e.g. requestCapabilities).
|
|
50
59
|
* @throws Error if not in ready state
|
|
51
60
|
*/
|
|
52
|
-
sendCommand(command: string, data: any): Promise<void>;
|
|
61
|
+
sendCommand(command: string, data: any, scope?: MessageScope): Promise<void>;
|
|
53
62
|
/**
|
|
54
63
|
* Public method to publish a track to the machine.
|
|
55
64
|
* @param track The track to send to the machine.
|
|
@@ -111,7 +120,7 @@ interface ReactorState {
|
|
|
111
120
|
jwtToken?: string;
|
|
112
121
|
}
|
|
113
122
|
interface ReactorActions {
|
|
114
|
-
sendCommand(command: string, data: any): Promise<void>;
|
|
123
|
+
sendCommand(command: string, data: any, scope?: MessageScope): Promise<void>;
|
|
115
124
|
connect(jwtToken?: string): Promise<void>;
|
|
116
125
|
disconnect(recoverable?: boolean): Promise<void>;
|
|
117
126
|
publishVideoStream(stream: MediaStream): Promise<void>;
|
|
@@ -170,9 +179,13 @@ declare function useReactor<T>(selector: (state: ReactorStore) => T): T;
|
|
|
170
179
|
/**
|
|
171
180
|
* Hook for handling message subscriptions with proper React lifecycle management.
|
|
172
181
|
*
|
|
173
|
-
*
|
|
182
|
+
* The handler receives the message payload and the scope it arrived on:
|
|
183
|
+
* - "application" for model-defined messages (via get_ctx().send())
|
|
184
|
+
* - "runtime" for platform-level messages (e.g., capabilities response)
|
|
185
|
+
*
|
|
186
|
+
* @param handler - The message handler function (message, scope)
|
|
174
187
|
*/
|
|
175
|
-
declare function useReactorMessage(handler: (message: any) => void): void;
|
|
188
|
+
declare function useReactorMessage(handler: (message: any, scope: MessageScope) => void): void;
|
|
176
189
|
|
|
177
190
|
/**
|
|
178
191
|
* ⚠️ INSECURE: Fetches a JWT token directly from the client.
|
|
@@ -187,4 +200,4 @@ declare function useReactorMessage(handler: (message: any) => void): void;
|
|
|
187
200
|
*/
|
|
188
201
|
declare function fetchInsecureJwtToken(apiKey: string, coordinatorUrl?: string): Promise<string>;
|
|
189
202
|
|
|
190
|
-
export { ConflictError, type Options, PROD_COORDINATOR_URL, Reactor, ReactorController, type ReactorControllerProps, type ReactorError, type ReactorEvent, ReactorProvider, type ReactorState$1 as ReactorState, type ReactorStatus, ReactorView, type ReactorViewProps, WebcamStream, fetchInsecureJwtToken, useReactor, useReactorMessage, useReactorStore };
|
|
203
|
+
export { ConflictError, type MessageScope, type Options, PROD_COORDINATOR_URL, Reactor, ReactorController, type ReactorControllerProps, type ReactorError, type ReactorEvent, ReactorProvider, type ReactorState$1 as ReactorState, type ReactorStatus, ReactorView, type ReactorViewProps, WebcamStream, fetchInsecureJwtToken, useReactor, useReactorMessage, useReactorStore };
|
package/dist/index.js
CHANGED
|
@@ -227,12 +227,13 @@ function waitForIceGathering(pc, timeoutMs = 5e3) {
|
|
|
227
227
|
}, timeoutMs);
|
|
228
228
|
});
|
|
229
229
|
}
|
|
230
|
-
function sendMessage(channel, command, data) {
|
|
230
|
+
function sendMessage(channel, command, data, scope = "application") {
|
|
231
231
|
if (channel.readyState !== "open") {
|
|
232
232
|
throw new Error(`Data channel not open: ${channel.readyState}`);
|
|
233
233
|
}
|
|
234
234
|
const jsonData = typeof data === "string" ? JSON.parse(data) : data;
|
|
235
|
-
const
|
|
235
|
+
const inner = { type: command, data: jsonData };
|
|
236
|
+
const payload = { scope, data: inner };
|
|
236
237
|
channel.send(JSON.stringify(payload));
|
|
237
238
|
}
|
|
238
239
|
function parseMessage(data) {
|
|
@@ -614,6 +615,7 @@ var LocalCoordinatorClient = class extends CoordinatorClient {
|
|
|
614
615
|
};
|
|
615
616
|
|
|
616
617
|
// src/core/GPUMachineClient.ts
|
|
618
|
+
var PING_INTERVAL_MS = 5e3;
|
|
617
619
|
var GPUMachineClient = class {
|
|
618
620
|
constructor(config) {
|
|
619
621
|
this.eventListeners = /* @__PURE__ */ new Map();
|
|
@@ -696,6 +698,7 @@ var GPUMachineClient = class {
|
|
|
696
698
|
*/
|
|
697
699
|
disconnect() {
|
|
698
700
|
return __async(this, null, function* () {
|
|
701
|
+
this.stopPing();
|
|
699
702
|
if (this.publishedTrack) {
|
|
700
703
|
yield this.unpublishTrack();
|
|
701
704
|
}
|
|
@@ -736,13 +739,14 @@ var GPUMachineClient = class {
|
|
|
736
739
|
* Sends a command to the GPU machine via the data channel.
|
|
737
740
|
* @param command The command to send
|
|
738
741
|
* @param data The data to send with the command. These are the parameters for the command, matching the scheme in the capabilities dictionary.
|
|
742
|
+
* @param scope The message scope – "application" (default) for model commands, "runtime" for platform-level messages.
|
|
739
743
|
*/
|
|
740
|
-
sendCommand(command, data) {
|
|
744
|
+
sendCommand(command, data, scope = "application") {
|
|
741
745
|
if (!this.dataChannel) {
|
|
742
746
|
throw new Error("[GPUMachineClient] Data channel not available");
|
|
743
747
|
}
|
|
744
748
|
try {
|
|
745
|
-
sendMessage(this.dataChannel, command, data);
|
|
749
|
+
sendMessage(this.dataChannel, command, data, scope);
|
|
746
750
|
} catch (error) {
|
|
747
751
|
console.warn("[GPUMachineClient] Failed to send message:", error);
|
|
748
752
|
}
|
|
@@ -823,6 +827,34 @@ var GPUMachineClient = class {
|
|
|
823
827
|
return new MediaStream(tracks);
|
|
824
828
|
}
|
|
825
829
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
830
|
+
// Ping (Client Liveness)
|
|
831
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
832
|
+
/**
|
|
833
|
+
* Starts sending periodic "ping" messages on the runtime channel so the
|
|
834
|
+
* server can detect stale connections quickly.
|
|
835
|
+
*/
|
|
836
|
+
startPing() {
|
|
837
|
+
this.stopPing();
|
|
838
|
+
this.pingInterval = setInterval(() => {
|
|
839
|
+
var _a;
|
|
840
|
+
if (((_a = this.dataChannel) == null ? void 0 : _a.readyState) === "open") {
|
|
841
|
+
try {
|
|
842
|
+
sendMessage(this.dataChannel, "ping", {}, "runtime");
|
|
843
|
+
} catch (e) {
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
}, PING_INTERVAL_MS);
|
|
847
|
+
}
|
|
848
|
+
/**
|
|
849
|
+
* Stops the periodic ping.
|
|
850
|
+
*/
|
|
851
|
+
stopPing() {
|
|
852
|
+
if (this.pingInterval !== void 0) {
|
|
853
|
+
clearInterval(this.pingInterval);
|
|
854
|
+
this.pingInterval = void 0;
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
826
858
|
// Private Helpers
|
|
827
859
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
828
860
|
setStatus(newStatus) {
|
|
@@ -876,18 +908,29 @@ var GPUMachineClient = class {
|
|
|
876
908
|
if (!this.dataChannel) return;
|
|
877
909
|
this.dataChannel.onopen = () => {
|
|
878
910
|
console.debug("[GPUMachineClient] Data channel open");
|
|
911
|
+
this.startPing();
|
|
879
912
|
};
|
|
880
913
|
this.dataChannel.onclose = () => {
|
|
881
914
|
console.debug("[GPUMachineClient] Data channel closed");
|
|
915
|
+
this.stopPing();
|
|
882
916
|
};
|
|
883
917
|
this.dataChannel.onerror = (error) => {
|
|
884
918
|
console.error("[GPUMachineClient] Data channel error:", error);
|
|
885
919
|
};
|
|
886
920
|
this.dataChannel.onmessage = (event) => {
|
|
887
|
-
const
|
|
888
|
-
console.debug("[GPUMachineClient] Received message:",
|
|
921
|
+
const rawData = parseMessage(event.data);
|
|
922
|
+
console.debug("[GPUMachineClient] Received message:", rawData);
|
|
889
923
|
try {
|
|
890
|
-
|
|
924
|
+
if ((rawData == null ? void 0 : rawData.scope) === "application" && (rawData == null ? void 0 : rawData.data) !== void 0) {
|
|
925
|
+
this.emit("message", rawData.data, "application");
|
|
926
|
+
} else if ((rawData == null ? void 0 : rawData.scope) === "runtime" && (rawData == null ? void 0 : rawData.data) !== void 0) {
|
|
927
|
+
this.emit("message", rawData.data, "runtime");
|
|
928
|
+
} else {
|
|
929
|
+
console.warn(
|
|
930
|
+
"[GPUMachineClient] Received message without envelope, treating as application"
|
|
931
|
+
);
|
|
932
|
+
this.emit("message", rawData, "application");
|
|
933
|
+
}
|
|
891
934
|
} catch (error) {
|
|
892
935
|
console.error(
|
|
893
936
|
"[GPUMachineClient] Failed to parse/validate message:",
|
|
@@ -937,11 +980,14 @@ var Reactor = class {
|
|
|
937
980
|
}
|
|
938
981
|
/**
|
|
939
982
|
* Public method to send a message to the machine.
|
|
940
|
-
*
|
|
941
|
-
* @param
|
|
983
|
+
* Wraps the message in the specified channel envelope (defaults to "application").
|
|
984
|
+
* @param command The command name to send.
|
|
985
|
+
* @param data The command payload.
|
|
986
|
+
* @param scope The envelope scope – "application" (default) for model commands,
|
|
987
|
+
* "runtime" for platform-level messages (e.g. requestCapabilities).
|
|
942
988
|
* @throws Error if not in ready state
|
|
943
989
|
*/
|
|
944
|
-
sendCommand(command, data) {
|
|
990
|
+
sendCommand(command, data, scope = "application") {
|
|
945
991
|
return __async(this, null, function* () {
|
|
946
992
|
var _a;
|
|
947
993
|
if (process.env.NODE_ENV !== "development" && this.status !== "ready") {
|
|
@@ -950,7 +996,7 @@ var Reactor = class {
|
|
|
950
996
|
return;
|
|
951
997
|
}
|
|
952
998
|
try {
|
|
953
|
-
(_a = this.machineClient) == null ? void 0 : _a.sendCommand(command, data);
|
|
999
|
+
(_a = this.machineClient) == null ? void 0 : _a.sendCommand(command, data, scope);
|
|
954
1000
|
} catch (error) {
|
|
955
1001
|
console.error("[Reactor] Failed to send message:", error);
|
|
956
1002
|
this.createError(
|
|
@@ -1100,10 +1146,8 @@ var Reactor = class {
|
|
|
1100
1146
|
*/
|
|
1101
1147
|
setupMachineClientHandlers() {
|
|
1102
1148
|
if (!this.machineClient) return;
|
|
1103
|
-
this.machineClient.on("
|
|
1104
|
-
|
|
1105
|
-
this.emit("newMessage", message.data);
|
|
1106
|
-
}
|
|
1149
|
+
this.machineClient.on("message", (message, scope) => {
|
|
1150
|
+
this.emit("newMessage", message, scope);
|
|
1107
1151
|
});
|
|
1108
1152
|
this.machineClient.on("statusChanged", (status) => {
|
|
1109
1153
|
switch (status) {
|
|
@@ -1310,10 +1354,14 @@ var createReactorStore = (initProps, publicState = defaultInitState) => {
|
|
|
1310
1354
|
get().internal.reactor.off("newMessage", handler);
|
|
1311
1355
|
};
|
|
1312
1356
|
},
|
|
1313
|
-
sendCommand: (command, data) => __async(null, null, function* () {
|
|
1314
|
-
console.debug("[ReactorStore] Sending command", {
|
|
1357
|
+
sendCommand: (command, data, scope) => __async(null, null, function* () {
|
|
1358
|
+
console.debug("[ReactorStore] Sending command", {
|
|
1359
|
+
command,
|
|
1360
|
+
data,
|
|
1361
|
+
scope
|
|
1362
|
+
});
|
|
1315
1363
|
try {
|
|
1316
|
-
yield get().internal.reactor.sendCommand(command, data);
|
|
1364
|
+
yield get().internal.reactor.sendCommand(command, data, scope);
|
|
1317
1365
|
console.debug("[ReactorStore] Command sent successfully");
|
|
1318
1366
|
} catch (error) {
|
|
1319
1367
|
console.error("[ReactorStore] Failed to send command:", error);
|
|
@@ -1516,9 +1564,12 @@ function useReactorMessage(handler) {
|
|
|
1516
1564
|
}, [handler]);
|
|
1517
1565
|
(0, import_react4.useEffect)(() => {
|
|
1518
1566
|
console.debug("[useReactorMessage] Setting up message subscription");
|
|
1519
|
-
const stableHandler = (message) => {
|
|
1520
|
-
console.debug("[useReactorMessage] Message received", {
|
|
1521
|
-
|
|
1567
|
+
const stableHandler = (message, scope) => {
|
|
1568
|
+
console.debug("[useReactorMessage] Message received", {
|
|
1569
|
+
message,
|
|
1570
|
+
scope
|
|
1571
|
+
});
|
|
1572
|
+
handlerRef.current(message, scope);
|
|
1522
1573
|
};
|
|
1523
1574
|
reactor.on("newMessage", stableHandler);
|
|
1524
1575
|
console.debug("[useReactorMessage] Message handler registered");
|
|
@@ -1647,7 +1698,7 @@ function ReactorController({
|
|
|
1647
1698
|
}, [status]);
|
|
1648
1699
|
const requestCapabilities = (0, import_react6.useCallback)(() => {
|
|
1649
1700
|
if (status === "ready") {
|
|
1650
|
-
sendCommand("requestCapabilities", {});
|
|
1701
|
+
sendCommand("requestCapabilities", {}, "runtime");
|
|
1651
1702
|
}
|
|
1652
1703
|
}, [status, sendCommand]);
|
|
1653
1704
|
import_react6.default.useEffect(() => {
|
|
@@ -1664,9 +1715,9 @@ function ReactorController({
|
|
|
1664
1715
|
}, 5e3);
|
|
1665
1716
|
return () => clearInterval(interval);
|
|
1666
1717
|
}, [status, commands, requestCapabilities]);
|
|
1667
|
-
useReactorMessage((message) => {
|
|
1668
|
-
if (message && typeof message === "object" && "commands" in message) {
|
|
1669
|
-
const commandsMessage = message;
|
|
1718
|
+
useReactorMessage((message, scope) => {
|
|
1719
|
+
if (scope === "runtime" && message && typeof message === "object" && message.type === "modelCapabilities" && message.data && "commands" in message.data) {
|
|
1720
|
+
const commandsMessage = message.data;
|
|
1670
1721
|
setCommands(commandsMessage.commands);
|
|
1671
1722
|
const initialValues = {};
|
|
1672
1723
|
const initialExpanded = {};
|