@reactor-team/js-sdk 1.0.15 → 1.0.16

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 CHANGED
@@ -1,13 +1,25 @@
1
- import { z } from 'zod';
1
+ import z$1, { z } from 'zod';
2
2
  import * as react_jsx_runtime from 'react/jsx-runtime';
3
3
  import React, { ReactNode } from 'react';
4
4
  import { RemoteVideoTrack } from 'livekit-client';
5
5
 
6
+ /**
7
+ * Internal types for the Reactor SDK.
8
+ */
9
+
10
+ declare const WaitingInfoDataSchema: z.ZodObject<{
11
+ position: z.ZodOptional<z.ZodNumber>;
12
+ estimatedWaitTime: z.ZodOptional<z.ZodNumber>;
13
+ averageWaitTime: z.ZodOptional<z.ZodNumber>;
14
+ }, z.core.$strip>;
15
+ declare const SessionExpirationDataSchema: z.ZodObject<{
16
+ expire: z.ZodNumber;
17
+ }, z.core.$strip>;
18
+
6
19
  type ReactorStatus = "disconnected" | "connecting" | "waiting" | "ready";
7
- interface ReactorWaitingInfo {
8
- position?: number;
9
- estimatedWaitTime?: number;
10
- averageWaitTime?: number;
20
+ interface ReactorWaitingInfo extends z$1.infer<typeof WaitingInfoDataSchema> {
21
+ }
22
+ interface ReactorSessionExpiration extends z$1.infer<typeof SessionExpirationDataSchema> {
11
23
  }
12
24
  interface ReactorError {
13
25
  code: string;
@@ -22,7 +34,7 @@ interface ReactorState$1 {
22
34
  waitingInfo?: ReactorWaitingInfo;
23
35
  lastError?: ReactorError;
24
36
  }
25
- type ReactorEvent = "statusChanged" | "waitingInfoChanged" | "newMessage" | "fps" | "streamChanged" | "error";
37
+ type ReactorEvent = "statusChanged" | "waitingInfoChanged" | "newMessage" | "fps" | "streamChanged" | "error" | "sessionExpirationChanged";
26
38
 
27
39
  declare const OptionsSchema: z.ZodObject<{
28
40
  directConnection: z.ZodOptional<z.ZodObject<{
@@ -51,6 +63,7 @@ declare class Reactor {
51
63
  private modelName;
52
64
  private modelVersion;
53
65
  private queueing;
66
+ private sessionExpiration?;
54
67
  constructor(options: Options);
55
68
  private eventListeners;
56
69
  on(event: ReactorEvent, handler: EventHandler): void;
@@ -92,6 +105,11 @@ declare class Reactor {
92
105
  disconnect(): Promise<void>;
93
106
  private setStatus;
94
107
  private setWaitingInfo;
108
+ /**
109
+ * Set the session expiration time.
110
+ * @param newSessionExpiration The new session expiration time in seconds.
111
+ */
112
+ private setSessionExpiration;
95
113
  getStatus(): ReactorStatus;
96
114
  /**
97
115
  * Get the current state including status, error, and waiting info
@@ -117,6 +135,7 @@ interface ReactorState {
117
135
  fps?: number;
118
136
  waitingInfo?: ReactorWaitingInfo;
119
137
  lastError?: ReactorError;
138
+ sessionExpiration?: number;
120
139
  }
121
140
  interface ReactorActions {
122
141
  sendMessage(message: any): Promise<void>;
@@ -173,4 +192,4 @@ declare function useReactor<T>(selector: (state: ReactorStore) => T): T;
173
192
  */
174
193
  declare function useReactorMessage(handler: (message: any) => void): void;
175
194
 
176
- export { type Options, Reactor, type ReactorError, type ReactorEvent, ReactorProvider, type ReactorState$1 as ReactorState, type ReactorStatus, ReactorView, type ReactorViewProps, type ReactorWaitingInfo, WebcamStream, useReactor, useReactorMessage, useReactorStore };
195
+ export { type Options, Reactor, type ReactorError, type ReactorEvent, ReactorProvider, type ReactorSessionExpiration, type ReactorState$1 as ReactorState, type ReactorStatus, ReactorView, type ReactorViewProps, type ReactorWaitingInfo, WebcamStream, useReactor, useReactorMessage, useReactorStore };
package/dist/index.d.ts CHANGED
@@ -1,13 +1,25 @@
1
- import { z } from 'zod';
1
+ import z$1, { z } from 'zod';
2
2
  import * as react_jsx_runtime from 'react/jsx-runtime';
3
3
  import React, { ReactNode } from 'react';
4
4
  import { RemoteVideoTrack } from 'livekit-client';
5
5
 
6
+ /**
7
+ * Internal types for the Reactor SDK.
8
+ */
9
+
10
+ declare const WaitingInfoDataSchema: z.ZodObject<{
11
+ position: z.ZodOptional<z.ZodNumber>;
12
+ estimatedWaitTime: z.ZodOptional<z.ZodNumber>;
13
+ averageWaitTime: z.ZodOptional<z.ZodNumber>;
14
+ }, z.core.$strip>;
15
+ declare const SessionExpirationDataSchema: z.ZodObject<{
16
+ expire: z.ZodNumber;
17
+ }, z.core.$strip>;
18
+
6
19
  type ReactorStatus = "disconnected" | "connecting" | "waiting" | "ready";
7
- interface ReactorWaitingInfo {
8
- position?: number;
9
- estimatedWaitTime?: number;
10
- averageWaitTime?: number;
20
+ interface ReactorWaitingInfo extends z$1.infer<typeof WaitingInfoDataSchema> {
21
+ }
22
+ interface ReactorSessionExpiration extends z$1.infer<typeof SessionExpirationDataSchema> {
11
23
  }
12
24
  interface ReactorError {
13
25
  code: string;
@@ -22,7 +34,7 @@ interface ReactorState$1 {
22
34
  waitingInfo?: ReactorWaitingInfo;
23
35
  lastError?: ReactorError;
24
36
  }
25
- type ReactorEvent = "statusChanged" | "waitingInfoChanged" | "newMessage" | "fps" | "streamChanged" | "error";
37
+ type ReactorEvent = "statusChanged" | "waitingInfoChanged" | "newMessage" | "fps" | "streamChanged" | "error" | "sessionExpirationChanged";
26
38
 
27
39
  declare const OptionsSchema: z.ZodObject<{
28
40
  directConnection: z.ZodOptional<z.ZodObject<{
@@ -51,6 +63,7 @@ declare class Reactor {
51
63
  private modelName;
52
64
  private modelVersion;
53
65
  private queueing;
66
+ private sessionExpiration?;
54
67
  constructor(options: Options);
55
68
  private eventListeners;
56
69
  on(event: ReactorEvent, handler: EventHandler): void;
@@ -92,6 +105,11 @@ declare class Reactor {
92
105
  disconnect(): Promise<void>;
93
106
  private setStatus;
94
107
  private setWaitingInfo;
108
+ /**
109
+ * Set the session expiration time.
110
+ * @param newSessionExpiration The new session expiration time in seconds.
111
+ */
112
+ private setSessionExpiration;
95
113
  getStatus(): ReactorStatus;
96
114
  /**
97
115
  * Get the current state including status, error, and waiting info
@@ -117,6 +135,7 @@ interface ReactorState {
117
135
  fps?: number;
118
136
  waitingInfo?: ReactorWaitingInfo;
119
137
  lastError?: ReactorError;
138
+ sessionExpiration?: number;
120
139
  }
121
140
  interface ReactorActions {
122
141
  sendMessage(message: any): Promise<void>;
@@ -173,4 +192,4 @@ declare function useReactor<T>(selector: (state: ReactorStore) => T): T;
173
192
  */
174
193
  declare function useReactorMessage(handler: (message: any) => void): void;
175
194
 
176
- export { type Options, Reactor, type ReactorError, type ReactorEvent, ReactorProvider, type ReactorState$1 as ReactorState, type ReactorStatus, ReactorView, type ReactorViewProps, type ReactorWaitingInfo, WebcamStream, useReactor, useReactorMessage, useReactorStore };
195
+ export { type Options, Reactor, type ReactorError, type ReactorEvent, ReactorProvider, type ReactorSessionExpiration, type ReactorState$1 as ReactorState, type ReactorStatus, ReactorView, type ReactorViewProps, type ReactorWaitingInfo, WebcamStream, useReactor, useReactorMessage, useReactorStore };
package/dist/index.js CHANGED
@@ -119,11 +119,19 @@ var WaitingInfoMessageSchema = import_zod.z.object({
119
119
  type: import_zod.z.literal("waiting-info"),
120
120
  data: WaitingInfoDataSchema
121
121
  });
122
+ var SessionExpirationDataSchema = import_zod.z.object({
123
+ expire: import_zod.z.number()
124
+ });
125
+ var SessionExpirationMessageSchema = import_zod.z.object({
126
+ type: import_zod.z.literal("session-expiration"),
127
+ data: SessionExpirationDataSchema
128
+ });
122
129
  var CoordinatorMessageSchema = import_zod.z.discriminatedUnion("type", [
123
130
  WelcomeMessageSchema,
124
131
  GPUMachineAssignmentMessageSchema,
125
132
  EchoMessageSchema,
126
- WaitingInfoMessageSchema
133
+ WaitingInfoMessageSchema,
134
+ SessionExpirationMessageSchema
127
135
  ]);
128
136
  var GPUMachineSendMessageSchema = import_zod.z.discriminatedUnion("type", [
129
137
  ApplicationMessageSchema
@@ -786,6 +794,12 @@ var Reactor = class {
786
794
  this.setWaitingInfo(__spreadValues(__spreadValues({}, this.waitingInfo), waitingData));
787
795
  }
788
796
  );
797
+ this.coordinatorClient.on(
798
+ "session-expiration",
799
+ (sessionExpirationData) => {
800
+ this.setSessionExpiration(sessionExpirationData.expire);
801
+ }
802
+ );
789
803
  this.coordinatorClient.on(
790
804
  "statusChanged",
791
805
  (newStatus) => {
@@ -851,7 +865,8 @@ var Reactor = class {
851
865
  this.machineClient = void 0;
852
866
  }
853
867
  this.setStatus("disconnected");
854
- this.waitingInfo = void 0;
868
+ this.setSessionExpiration(void 0);
869
+ this.setWaitingInfo(void 0);
855
870
  });
856
871
  }
857
872
  setStatus(newStatus) {
@@ -873,6 +888,20 @@ var Reactor = class {
873
888
  this.emit("waitingInfoChanged", newWaitingInfo);
874
889
  }
875
890
  }
891
+ /**
892
+ * Set the session expiration time.
893
+ * @param newSessionExpiration The new session expiration time in seconds.
894
+ */
895
+ setSessionExpiration(newSessionExpiration) {
896
+ console.debug(
897
+ "[Reactor] Setting session expiration:",
898
+ newSessionExpiration
899
+ );
900
+ if (this.sessionExpiration !== newSessionExpiration) {
901
+ this.sessionExpiration = newSessionExpiration;
902
+ this.emit("sessionExpirationChanged", newSessionExpiration);
903
+ }
904
+ }
876
905
  getStatus() {
877
906
  return this.status;
878
907
  }
@@ -928,7 +957,8 @@ var defaultInitState = {
928
957
  videoTrack: null,
929
958
  fps: void 0,
930
959
  waitingInfo: void 0,
931
- lastError: void 0
960
+ lastError: void 0,
961
+ sessionExpiration: void 0
932
962
  };
933
963
  var initReactorStore = (props) => {
934
964
  return __spreadValues(__spreadValues({}, defaultInitState), props);
@@ -955,6 +985,13 @@ var createReactorStore = (initProps, publicState = defaultInitState) => {
955
985
  });
956
986
  set({ waitingInfo: newWaitingInfo });
957
987
  });
988
+ reactor.on("sessionExpirationChanged", (newSessionExpiration) => {
989
+ console.debug("[ReactorStore] Session expiration changed", {
990
+ oldSessionExpiration: get().sessionExpiration,
991
+ newSessionExpiration
992
+ });
993
+ set({ sessionExpiration: newSessionExpiration });
994
+ });
958
995
  reactor.on("streamChanged", (videoTrack) => {
959
996
  console.debug("[ReactorStore] Stream changed", {
960
997
  hasVideoTrack: !!videoTrack,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/core/types.ts","../src/core/CoordinatorClient.ts","../src/core/GPUMachineClient.ts","../src/core/Reactor.ts","../src/react/ReactorProvider.tsx","../src/core/store.ts","../src/react/hooks.ts","../src/react/ReactorView.tsx","../src/react/WebcamStream.tsx"],"sourcesContent":["export * from \"./core/Reactor\";\nexport * from \"./react/ReactorProvider\";\nexport * from \"./react/ReactorView\";\nexport * from \"./react/WebcamStream\";\nexport * from \"./react/hooks\";\nexport * from \"./types\";\n","/**\n * Internal types for the Reactor SDK.\n */\n\nimport { z } from \"zod\";\n\n// Base message schemas corresponding to Python Pydantic models\n\nexport const ApplicationMessageSchema = z.object({\n type: z.literal(\"application\"),\n data: z.any(), // Can be any JSON-serializable data\n});\n\n// Internal message that notifies the client of the current push rate of the machine\nexport const FPSMessageSchema = z.object({\n type: z.literal(\"fps\"),\n data: z.number(),\n});\n\nexport const GPUMachineReceiveMessageSchema = z.discriminatedUnion(\"type\", [\n ApplicationMessageSchema,\n FPSMessageSchema,\n]);\n\nexport const WelcomeMessageSchema = z.object({\n type: z.literal(\"welcome\"),\n data: z.record(z.string(), z.any()),\n});\n\nexport const GPUMachineAssignmentDataSchema = z.object({\n livekitWsUrl: z.string(),\n livekitJwtToken: z.string(),\n});\n\nexport const GPUMachineAssignmentMessageSchema = z.object({\n type: z.literal(\"gpu-machine-assigned\"),\n data: GPUMachineAssignmentDataSchema,\n});\n\nexport const EchoMessageSchema = z.object({\n type: z.literal(\"echo\"),\n data: z.record(z.string(), z.any()),\n});\n\nexport const WaitingInfoDataSchema = z.object({\n position: z.number().optional(),\n estimatedWaitTime: z.number().optional(),\n averageWaitTime: z.number().optional(),\n});\n\nexport const WaitingInfoMessageSchema = z.object({\n type: z.literal(\"waiting-info\"),\n data: WaitingInfoDataSchema,\n});\n\nexport const CoordinatorMessageSchema = z.discriminatedUnion(\"type\", [\n WelcomeMessageSchema,\n GPUMachineAssignmentMessageSchema,\n EchoMessageSchema,\n WaitingInfoMessageSchema,\n]);\n\nexport const GPUMachineSendMessageSchema = z.discriminatedUnion(\"type\", [\n ApplicationMessageSchema,\n]);\n\nexport const SessionSetupMessageSchema = z.object({\n type: z.literal(\"sessionSetup\"),\n data: z.object({\n modelName: z.string(),\n modelVersion: z.string().default(\"latest\"),\n }),\n});\n\n// TypeScript types derived from schemas\nexport type ApplicationMessage = z.infer<typeof ApplicationMessageSchema>;\nexport type GPUMachineReceiveMessageSchema = z.infer<\n typeof GPUMachineReceiveMessageSchema\n>;\nexport type WelcomeMessage = z.infer<typeof WelcomeMessageSchema>;\nexport type GPUMachineAssignmentData = z.infer<\n typeof GPUMachineAssignmentDataSchema\n>;\nexport type GPUMachineAssignmentMessage = z.infer<\n typeof GPUMachineAssignmentMessageSchema\n>;\nexport type EchoMessage = z.infer<typeof EchoMessageSchema>;\nexport type WaitingInfoData = z.infer<typeof WaitingInfoDataSchema>;\nexport type WaitingInfoMessage = z.infer<typeof WaitingInfoMessageSchema>;\nexport type CoordinatorMessage = z.infer<typeof CoordinatorMessageSchema>;\nexport type GPUMachineSendMessage = z.infer<typeof GPUMachineSendMessageSchema>;\nexport type SessionSetupMessage = z.infer<typeof SessionSetupMessageSchema>;\n\n// Internal connection status for individual components\nexport type InternalConnectionStatus =\n | \"disconnected\"\n | \"connecting\"\n | \"connected\"\n | \"error\";\n","/**\n * The CoordinatorClient is responsible for handling the connection to the coordinator.\n */\n\nimport {\n type CoordinatorMessage,\n CoordinatorMessageSchema,\n type SessionSetupMessage,\n} from \"./types\";\nimport { z } from \"zod\";\n\ntype EventHandler = (...args: any[]) => void;\n\nconst OptionsSchema = z\n .object({\n wsUrl: z.string().nonempty(),\n jwtToken: z.string().optional(),\n insecureApiKey: z.string().optional(),\n modelName: z.string(),\n modelVersion: z.string().default(\"latest\"),\n queueing: z.boolean().default(false),\n })\n .refine((data) => data.jwtToken || data.insecureApiKey, {\n message: \"At least one of jwtToken or insecureApiKey must be provided.\",\n });\n\ntype Options = z.input<typeof OptionsSchema>;\n\n// Infer message types from the schema - single source of truth\nexport type CoordinatorEvent = \"statusChanged\" | CoordinatorMessage[\"type\"];\n\nexport class CoordinatorClient {\n private websocket?: WebSocket;\n private wsUrl: string;\n private jwtToken?: string;\n private insecureApiKey?: string;\n private eventListeners: Map<CoordinatorEvent, Set<EventHandler>> = new Map();\n private modelName: string;\n private modelVersion: string;\n private queueing: boolean;\n\n constructor(options: Options) {\n const validatedOptions = OptionsSchema.parse(options);\n this.wsUrl = validatedOptions.wsUrl;\n this.jwtToken = validatedOptions.jwtToken;\n this.insecureApiKey = validatedOptions.insecureApiKey;\n this.modelName = validatedOptions.modelName;\n this.modelVersion = validatedOptions.modelVersion;\n this.queueing = validatedOptions.queueing;\n }\n\n // Event Emitter API\n on(event: CoordinatorEvent, handler: EventHandler) {\n if (!this.eventListeners.has(event)) {\n this.eventListeners.set(event, new Set());\n }\n this.eventListeners.get(event)!.add(handler);\n }\n\n off(event: CoordinatorEvent, handler: EventHandler) {\n this.eventListeners.get(event)?.delete(handler);\n }\n\n emit(event: CoordinatorEvent, ...args: any[]) {\n this.eventListeners.get(event)?.forEach((handler) => handler(...args));\n }\n\n sendMessage(message: any) {\n try {\n const messageStr =\n typeof message === \"string\" ? message : JSON.stringify(message);\n this.websocket?.send(messageStr);\n } catch (error) {\n console.error(\"[CoordinatorClient] Failed to send message:\", error);\n this.emit(\"statusChanged\", \"error\");\n }\n }\n\n async connect(): Promise<void> {\n // Build WebSocket URL with authentication query parameters\n const url = new URL(this.wsUrl);\n if (this.jwtToken) {\n url.searchParams.set(\"jwt_token\", this.jwtToken);\n } else if (this.insecureApiKey) {\n url.searchParams.set(\"api_key\", this.insecureApiKey);\n }\n\n // Add queued parameter only if queueing is true\n if (this.queueing) {\n url.searchParams.set(\"queueing\", \"true\");\n }\n\n console.debug(\"[CoordinatorClient] Connecting to\", url.toString());\n this.websocket = new WebSocket(url.toString());\n\n this.websocket.onopen = () => {\n console.debug(\"[CoordinatorClient] WebSocket opened\");\n this.emit(\"statusChanged\", \"connected\");\n };\n\n this.websocket.onmessage = (event) => {\n try {\n let parsedData: string | object;\n if (typeof event.data === \"string\") {\n parsedData = JSON.parse(event.data);\n } else {\n parsedData = event.data;\n }\n console.debug(\n \"[CoordinatorClient] Received message from coordinator:\",\n parsedData\n );\n const validatedData = CoordinatorMessageSchema.parse(parsedData);\n this.emit(validatedData.type, validatedData.data);\n } catch (error) {\n console.error(\n \"[CoordinatorClient] Failed to parse WebSocket message from coordinator:\",\n error,\n \"message\",\n event.data\n );\n this.emit(\"statusChanged\", \"error\");\n }\n };\n\n this.websocket.onclose = (event) => {\n console.debug(\"[CoordinatorClient] WebSocket closed\", event);\n this.websocket = undefined;\n this.emit(\"statusChanged\", \"disconnected\");\n };\n\n this.websocket.onerror = (error) => {\n console.error(\"[CoordinatorClient] WebSocket error:\", error);\n this.websocket = undefined;\n this.emit(\"statusChanged\", \"error\");\n };\n\n await new Promise<void>((resolve, reject) => {\n const onOpen = () => {\n this.websocket?.removeEventListener(\"error\", onError);\n resolve();\n };\n const onError = (error: Event) => {\n this.websocket?.removeEventListener(\"open\", onOpen);\n reject(error);\n };\n this.websocket?.addEventListener(\"open\", onOpen);\n this.websocket?.addEventListener(\"error\", onError);\n });\n\n console.log(\"[CoordinatorClient] WebSocket connected\");\n\n this.sendMessage({\n type: \"sessionSetup\",\n data: {\n modelName: this.modelName,\n modelVersion: this.modelVersion,\n },\n } satisfies SessionSetupMessage);\n\n console.debug(\"[CoordinatorClient] Setup session message sent\");\n }\n\n /**\n * Closes the WebSocket connection if it exists.\n * This will trigger the onclose event handler.\n */\n disconnect() {\n if (this.websocket) {\n console.debug(\"[CoordinatorClient] Closing WebSocket connection\");\n this.websocket.close();\n this.websocket = undefined;\n }\n }\n}\n","/**\n * The GPUMachineClient is responsible for handling the direct connection to the machine instance\n * after the coordinator has assigned a machine.\n */\n\nimport {\n type GPUMachineSendMessage,\n GPUMachineReceiveMessageSchema,\n} from \"./types\";\nimport {\n Room,\n RoomEvent,\n Track,\n RemoteVideoTrack,\n LocalVideoTrack,\n LocalAudioTrack,\n} from \"livekit-client\";\n\ntype EventHandler = (...args: any[]) => void;\nexport type GPUMachineEvent =\n | GPUMachineReceiveMessageSchema[\"type\"]\n | \"statusChanged\"\n | \"streamChanged\";\n\nexport class GPUMachineClient {\n private eventListeners: Map<GPUMachineEvent, Set<EventHandler>> = new Map();\n private roomInstance: Room | undefined;\n private machineFPS: number | undefined;\n private token: string;\n private videoStream: MediaStream | undefined;\n private liveKitUrl: string;\n private publishedVideoTrack: LocalVideoTrack | undefined;\n private publishedAudioTrack: LocalAudioTrack | undefined;\n\n constructor(token: string, liveKitUrl: string) {\n this.token = token;\n this.liveKitUrl = liveKitUrl;\n }\n\n // Event Emitter API\n on(event: GPUMachineEvent, handler: EventHandler) {\n if (!this.eventListeners.has(event)) {\n this.eventListeners.set(event, new Set());\n }\n this.eventListeners.get(event)!.add(handler);\n }\n\n off(event: GPUMachineEvent, handler: EventHandler) {\n this.eventListeners.get(event)?.delete(handler);\n }\n\n emit(event: GPUMachineEvent, ...args: any[]) {\n this.eventListeners.get(event)?.forEach((handler) => handler(...args));\n }\n\n async sendMessage(message: GPUMachineSendMessage): Promise<void> {\n try {\n if (this.roomInstance) {\n const messageStr = JSON.stringify(message);\n // Send message via LiveKit text channel\n await this.roomInstance.localParticipant.sendText(messageStr, {\n topic: \"application\",\n });\n } else {\n console.warn(\n \"[GPUMachineClient] Cannot send message - not connected to room\"\n );\n }\n } catch (error) {\n console.error(\"[GPUMachineClient] Failed to send message:\", error);\n this.emit(\"statusChanged\", \"error\");\n }\n }\n\n async connect(): Promise<void> {\n this.roomInstance = new Room({\n adaptiveStream: true,\n dynacast: true,\n });\n\n this.roomInstance.on(RoomEvent.Connected, () => {\n console.debug(\"[GPUMachineClient] Connected to room\");\n this.emit(\"statusChanged\", \"connected\");\n });\n\n this.roomInstance.on(RoomEvent.Disconnected, () => {\n console.debug(\"[GPUMachineClient] Disconnected from room\");\n this.emit(\"statusChanged\", \"disconnected\");\n });\n\n // Handle video track subscriptions from GPU machine\n this.roomInstance.on(\n RoomEvent.TrackSubscribed,\n (track, _publication, participant) => {\n console.debug(\n \"[GPUMachineClient] Track subscribed:\",\n track.kind,\n participant.identity\n );\n\n if (track.kind === Track.Kind.Video) {\n const videoTrack = track as RemoteVideoTrack;\n this.emit(\"streamChanged\", videoTrack);\n }\n }\n );\n\n this.roomInstance.on(\n RoomEvent.TrackUnsubscribed,\n (track, _publication, participant) => {\n console.debug(\n \"[GPUMachineClient] Track unsubscribed:\",\n track.kind,\n participant.identity\n );\n\n if (track.kind === Track.Kind.Video) {\n this.emit(\"streamChanged\", null);\n }\n }\n );\n\n this.roomInstance.registerTextStreamHandler(\n \"application\",\n async (reader, participant) => {\n const text = await reader.readAll();\n console.log(\"[GPUMachineClient] Received message:\", text);\n try {\n const parsedData = JSON.parse(text);\n\n const validatedMessage =\n GPUMachineReceiveMessageSchema.parse(parsedData);\n if (validatedMessage.type === \"fps\") {\n this.machineFPS = validatedMessage.data;\n }\n\n this.emit(validatedMessage.type, validatedMessage.data);\n } catch (error) {\n console.error(\n \"[GPUMachineClient] Failed to parse/validate message:\",\n error\n );\n this.emit(\"statusChanged\", \"error\");\n }\n }\n );\n\n await this.roomInstance.connect(this.liveKitUrl, this.token);\n\n console.log(\"[GPUMachineClient] Room connected\");\n }\n\n /**\n * Closes the LiveKit connection if it exists.\n * This will trigger the onclose event handler.\n */\n async disconnect() {\n // Unpublish any published tracks before disconnecting\n if (this.publishedVideoTrack) {\n await this.unpublishVideoTrack();\n }\n if (this.publishedAudioTrack) {\n await this.unpublishAudioTrack();\n }\n\n if (this.roomInstance) {\n console.debug(\"[GPUMachineClient] Closing LiveKit connection\");\n await this.roomInstance.disconnect();\n this.roomInstance = undefined;\n }\n this.machineFPS = undefined;\n }\n\n /**\n * Returns the current fps rate of the machine.\n * @returns The current fps rate of the machine.\n */\n getFPS(): number | undefined {\n return this.machineFPS;\n }\n\n /**\n * Returns the current video stream from the GPU machine.\n * @returns The current video stream or undefined if not available.\n */\n getVideoStream(): MediaStream | undefined {\n return this.videoStream;\n }\n\n /**\n * Publishes a video track from the provided MediaStream to the LiveKit room.\n * Only one video track can be published at a time. If a video track is already\n * published, it will be unpublished first.\n *\n * @param mediaStream The MediaStream containing the video track to publish\n * @throws Error if no video track is found in the MediaStream or room is not connected\n */\n async publishVideoTrack(mediaStream: MediaStream): Promise<void> {\n if (!this.roomInstance) {\n throw new Error(\n \"[GPUMachineClient] Cannot publish track - not connected to room\"\n );\n }\n\n const videoTracks = mediaStream.getVideoTracks();\n if (videoTracks.length === 0) {\n throw new Error(\"[GPUMachineClient] No video track found in MediaStream\");\n }\n\n // Unpublish existing video track if any\n if (this.publishedVideoTrack) {\n await this.unpublishVideoTrack();\n }\n\n try {\n const videoTrack = videoTracks[0];\n const localVideoTrack =\n await this.roomInstance.localParticipant.publishTrack(videoTrack, {\n name: \"client-video\",\n source: Track.Source.Camera,\n });\n\n this.publishedVideoTrack = localVideoTrack.track as LocalVideoTrack;\n console.debug(\"[GPUMachineClient] Video track published successfully\");\n } catch (error) {\n console.error(\"[GPUMachineClient] Failed to publish video track:\", error);\n throw error;\n }\n }\n\n /**\n * Unpublishes the currently published video track.\n * Note: We pass false to unpublishTrack to prevent LiveKit from stopping\n * the source MediaStreamTrack, as it's owned by the component that created it.\n */\n async unpublishVideoTrack(): Promise<void> {\n if (!this.roomInstance || !this.publishedVideoTrack) {\n return;\n }\n\n const publishedVideoTrack = this.publishedVideoTrack;\n this.publishedVideoTrack = undefined;\n\n try {\n await this.roomInstance.localParticipant.unpublishTrack(\n publishedVideoTrack,\n false // Don't stop the source track - it's managed externally\n );\n console.debug(\"[GPUMachineClient] Video track unpublished successfully\");\n } catch (error) {\n console.error(\n \"[GPUMachineClient] Failed to unpublish video track:\",\n error\n );\n throw error;\n }\n }\n\n /**\n * Publishes an audio track from the provided MediaStream to the LiveKit room.\n * This is an internal method. Only one audio track can be published at a time.\n *\n * @param mediaStream The MediaStream containing the audio track to publish\n * @private\n */\n private async publishAudioTrack(mediaStream: MediaStream): Promise<void> {\n if (!this.roomInstance) {\n throw new Error(\n \"[GPUMachineClient] Cannot publish track - not connected to room\"\n );\n }\n\n const audioTracks = mediaStream.getAudioTracks();\n if (audioTracks.length === 0) {\n throw new Error(\"[GPUMachineClient] No audio track found in MediaStream\");\n }\n\n // Unpublish existing audio track if any\n if (this.publishedAudioTrack) {\n await this.unpublishAudioTrack();\n }\n\n try {\n const audioTrack = audioTracks[0];\n const localAudioTrack =\n await this.roomInstance.localParticipant.publishTrack(audioTrack, {\n name: \"client-audio\",\n source: Track.Source.Microphone,\n });\n\n this.publishedAudioTrack = localAudioTrack.track as LocalAudioTrack;\n console.debug(\"[GPUMachineClient] Audio track published successfully\");\n } catch (error) {\n console.error(\"[GPUMachineClient] Failed to publish audio track:\", error);\n throw error;\n }\n }\n\n /**\n * Unpublishes the currently published audio track.\n * Note: We pass false to unpublishTrack to prevent LiveKit from stopping\n * the source MediaStreamTrack, as it's owned by the component that created it.\n * @private\n */\n private async unpublishAudioTrack(): Promise<void> {\n if (!this.roomInstance || !this.publishedAudioTrack) {\n return;\n }\n\n const publishedAudioTrack = this.publishedAudioTrack;\n this.publishedAudioTrack = undefined;\n\n try {\n await this.roomInstance.localParticipant.unpublishTrack(\n publishedAudioTrack,\n false // Don't stop the source track - it's managed externally\n );\n console.debug(\"[GPUMachineClient] Audio track unpublished successfully\");\n } catch (error) {\n console.error(\n \"[GPUMachineClient] Failed to unpublish audio track:\",\n error\n );\n throw error;\n }\n }\n}\n","import type {\n ApplicationMessage,\n InternalConnectionStatus,\n GPUMachineAssignmentData,\n} from \"./types\";\nimport type {\n ReactorEvent,\n ReactorStatus,\n ReactorState,\n ReactorError,\n ReactorWaitingInfo,\n} from \"../types\";\nimport { CoordinatorClient } from \"./CoordinatorClient\";\nimport { GPUMachineClient } from \"./GPUMachineClient\";\nimport { z } from \"zod\";\n\nconst LOCAL_COORDINATOR_URL = \"ws://localhost:8080/ws\";\nconst LOCAL_INSECURE_API_KEY = \"1234\";\nconst PROD_COORDINATOR_URL = \"wss://api.reactor.inc/ws\";\n\nconst OptionsSchema = z\n .object({\n directConnection: z\n .object({\n livekitJwtToken: z.string(),\n livekitWsUrl: z.string(),\n })\n .optional(),\n insecureApiKey: z.string().optional(),\n jwtToken: z.string().optional(),\n coordinatorUrl: z.string().default(PROD_COORDINATOR_URL),\n modelName: z.string(),\n queueing: z.boolean().default(false),\n local: z.boolean().default(false),\n })\n .refine(\n (data) =>\n data.directConnection ||\n data.insecureApiKey ||\n data.jwtToken ||\n data.local,\n {\n message:\n \"At least one of directConnection, insecureApiKey, or jwtToken or local must be provided.\",\n }\n );\nexport type Options = z.input<typeof OptionsSchema>;\n\ntype EventHandler = (...args: any[]) => void;\n\nexport class Reactor {\n private coordinatorClient: CoordinatorClient | undefined; //client for the coordinator\n private machineClient: GPUMachineClient | undefined; //client for the machine instance\n private status: ReactorStatus = \"disconnected\";\n private coordinatorUrl: string;\n private lastError?: ReactorError;\n private waitingInfo?: ReactorWaitingInfo;\n private jwtToken?: string;\n private insecureApiKey?: string;\n private directConnection?: {\n livekitJwtToken: string;\n livekitWsUrl: string;\n };\n private modelName: string;\n private modelVersion: string;\n private queueing: boolean;\n\n constructor(options: Options) {\n const validatedOptions = OptionsSchema.parse(options);\n this.coordinatorUrl = validatedOptions.coordinatorUrl;\n this.jwtToken = validatedOptions.jwtToken;\n this.insecureApiKey = validatedOptions.insecureApiKey;\n this.directConnection = validatedOptions.directConnection;\n this.modelName = validatedOptions.modelName;\n this.queueing = validatedOptions.queueing;\n // TODO: Use the model version from the options once we have a way to handle multiple versions\n this.modelVersion = \"1.0.0\";\n if (validatedOptions.local) {\n this.coordinatorUrl = LOCAL_COORDINATOR_URL;\n this.insecureApiKey = LOCAL_INSECURE_API_KEY;\n }\n }\n\n // Generic event map\n private eventListeners: Map<ReactorEvent, Set<EventHandler>> = new Map();\n\n // Event Emitter API\n on(event: ReactorEvent, handler: EventHandler) {\n if (!this.eventListeners.has(event)) {\n this.eventListeners.set(event, new Set());\n }\n this.eventListeners.get(event)!.add(handler);\n }\n\n off(event: ReactorEvent, handler: EventHandler) {\n this.eventListeners.get(event)?.delete(handler);\n }\n\n emit(event: ReactorEvent, ...args: any[]) {\n this.eventListeners.get(event)?.forEach((handler) => handler(...args));\n }\n\n /**\n * Public method to send a message to the machine.\n * Automatically wraps the message in an application message.\n * @param message The message to send to the machine.\n * @throws Error if not in ready state\n */\n async sendMessage(message: any): Promise<void> {\n // Synchronous validation - throw immediately\n if (process.env.NODE_ENV !== \"development\" && this.status !== \"ready\") {\n const errorMessage = `Cannot send message, status is ${this.status}`;\n console.error(\"[Reactor] Not ready, cannot send message\");\n throw new Error(errorMessage);\n }\n\n try {\n // Automatically wrap the user-message in an application message.\n const applicationMessage: ApplicationMessage = {\n type: \"application\",\n data: message,\n };\n await this.machineClient?.sendMessage(applicationMessage);\n } catch (error) {\n // Async operational error - emit event only\n console.error(\"[Reactor] Failed to send message:\", error);\n this.createError(\n \"MESSAGE_SEND_FAILED\",\n `Failed to send message: ${error}`,\n \"gpu\",\n true\n );\n // Don't re-throw - let the error event handle it\n }\n }\n\n /**\n * Public method to publish a video stream to the machine.\n * @param videoStream The video stream to send to the machine.\n */\n async publishVideoStream(videoStream: MediaStream): Promise<void> {\n // Synchronous validation - throw immediately\n if (process.env.NODE_ENV !== \"development\" && this.status !== \"ready\") {\n const errorMessage = `Cannot publish video stream, status is ${this.status}`;\n console.error(\"[Reactor] Not ready, cannot publish video stream\");\n throw new Error(errorMessage);\n }\n\n try {\n await this.machineClient?.publishVideoTrack(videoStream);\n } catch (error) {\n console.error(\"[Reactor] Failed to publish video:\", error);\n this.createError(\n \"VIDEO_PUBLISH_FAILED\",\n `Failed to publish video: ${error}`,\n \"gpu\",\n true\n );\n }\n }\n\n /**\n * Public method to unpublish video stream to the machine.\n * This unpublishes the video track that was previously sent.\n */\n async unpublishVideoStream(): Promise<void> {\n try {\n await this.machineClient?.unpublishVideoTrack();\n } catch (error) {\n console.error(\"[Reactor] Failed to unpublish video:\", error);\n this.createError(\n \"VIDEO_UNPUBLISH_FAILED\",\n `Failed to unpublish video: ${error}`,\n \"gpu\",\n true\n );\n }\n }\n\n /**\n * Connects to the machine via LiveKit and waits for the gpu machine to be ready.\n * Once the machine is ready, the Reactor will establish the LiveKit connection.\n * @param livekitJwtToken The JWT token for LiveKit authentication\n * @param livekitWsUrl The WebSocket URL for LiveKit connection\n */\n private async connectToGPUMachine(\n livekitJwtToken: string,\n livekitWsUrl: string\n ) {\n console.debug(\"[Reactor] Connecting to machine room...\");\n\n try {\n this.machineClient = new GPUMachineClient(livekitJwtToken, livekitWsUrl);\n\n this.machineClient.on(\"application\", (message: any) => {\n // escalate the message event through the instance, so that the user can listen to it.\n this.emit(\"newMessage\", message);\n });\n\n this.machineClient.on(\n \"statusChanged\",\n (status: InternalConnectionStatus) => {\n switch (status) {\n case \"connected\":\n this.setStatus(\"ready\");\n break;\n case \"disconnected\":\n // gpu machine has disconnected. Close any other connection to any other entity\n // such as the coordinator or the LiveKit connection.\n this.disconnect();\n break;\n case \"error\":\n // gpu machine has errored. Close any other connection to any other entity\n // such as the coordinator or the LiveKit connection.\n this.createError(\n \"GPU_CONNECTION_ERROR\",\n \"GPU machine connection failed\",\n \"gpu\",\n true\n );\n this.disconnect();\n break;\n }\n }\n );\n\n this.machineClient.on(\"fps\", (fps: number) => {\n this.emit(\"fps\", fps);\n });\n\n this.machineClient.on(\"streamChanged\", (videoTrack) => {\n this.emit(\"streamChanged\", videoTrack);\n });\n\n console.debug(\"[Reactor] About to connect to machine\");\n await this.machineClient.connect();\n } catch (error) {\n // For private methods, we can still throw since the caller will handle it appropriately\n throw error;\n }\n }\n\n /**\n * Connects to the coordinator and waits for a GPU to be assigned.\n * Once a GPU is assigned, the Reactor will connect to the gpu machine via LiveKit.\n */\n async connect(): Promise<void> {\n console.debug(\"[Reactor] Connecting, status:\", this.status);\n\n // Synchronous validation - throw immediately\n if (this.status !== \"disconnected\")\n throw new Error(\"Already connected or connecting\");\n\n if (this.directConnection) {\n return this.connectToGPUMachine(\n this.directConnection.livekitJwtToken,\n this.directConnection.livekitWsUrl\n );\n }\n\n this.setStatus(\"connecting\");\n\n try {\n console.debug(\n \"[Reactor] Connecting to coordinator with authenticated URL\"\n );\n\n this.coordinatorClient = new CoordinatorClient({\n wsUrl: this.coordinatorUrl,\n jwtToken: this.jwtToken,\n insecureApiKey: this.insecureApiKey,\n modelName: this.modelName,\n modelVersion: this.modelVersion,\n queueing: this.queueing,\n });\n\n this.coordinatorClient.on(\n \"gpu-machine-assigned\",\n async (assignmentData: GPUMachineAssignmentData) => {\n console.debug(\n \"[Reactor] GPU machine assigned by coordinator:\",\n assignmentData\n );\n try {\n await this.connectToGPUMachine(\n assignmentData.livekitJwtToken,\n assignmentData.livekitWsUrl\n );\n } catch (error) {\n console.error(\"[Reactor] Failed to connect to GPU machine:\", error);\n // Emit error event for async GPU connection failure\n this.createError(\n \"GPU_CONNECTION_FAILED\",\n `Failed to connect to GPU machine: ${error}`,\n \"gpu\",\n true\n );\n this.disconnect();\n }\n }\n );\n\n this.coordinatorClient.on(\n \"waiting-info\",\n (waitingData: ReactorWaitingInfo) => {\n console.debug(\"[Reactor] Waiting info update received:\", waitingData);\n // Update waiting info\n this.setWaitingInfo({\n ...this.waitingInfo,\n ...waitingData,\n });\n }\n );\n\n this.coordinatorClient.on(\n \"statusChanged\",\n (newStatus: InternalConnectionStatus) => {\n switch (newStatus) {\n case \"connected\":\n this.setStatus(\"waiting\");\n // Initialize waiting info when entering waiting state\n this.setWaitingInfo({\n position: undefined,\n estimatedWaitTime: undefined,\n averageWaitTime: undefined,\n });\n break;\n case \"disconnected\":\n this.disconnect();\n break;\n case \"error\":\n this.createError(\n \"COORDINATOR_CONNECTION_ERROR\",\n \"Coordinator connection failed\",\n \"coordinator\",\n true\n );\n this.disconnect();\n break;\n }\n }\n );\n\n await this.coordinatorClient.connect();\n } catch (error) {\n console.error(\"[Reactor] Authentication failed:\", error);\n this.createError(\n \"AUTHENTICATION_FAILED\",\n `Authentication failed: ${error}`,\n \"coordinator\",\n true\n );\n this.setStatus(\"disconnected\");\n // Keep throwing for authentication failures as these are immediate/sync failures\n throw error;\n }\n }\n\n /**\n * Disconnects from the coordinator and the gpu machine.\n * Ensures cleanup completes even if individual disconnections fail.\n */\n async disconnect() {\n if (this.status === \"disconnected\") return;\n\n // Disconnect coordinator client with error handling\n if (this.coordinatorClient) {\n try {\n this.coordinatorClient.disconnect();\n } catch (error) {\n console.error(\"[Reactor] Error disconnecting from coordinator:\", error);\n // Continue with cleanup even if coordinator disconnect fails\n }\n this.coordinatorClient = undefined;\n }\n\n // Disconnect machine client with error handling\n if (this.machineClient) {\n try {\n await this.machineClient.disconnect();\n } catch (error) {\n console.error(\"[Reactor] Error disconnecting from GPU machine:\", error);\n // Continue with cleanup even if machine disconnect fails\n }\n this.machineClient = undefined;\n }\n\n this.setStatus(\"disconnected\");\n\n // Clear waiting info when disconnecting\n this.waitingInfo = undefined;\n }\n\n private setStatus(newStatus: ReactorStatus) {\n console.debug(\"[Reactor] Setting status:\", newStatus, \"from\", this.status);\n if (this.status !== newStatus) {\n this.status = newStatus;\n this.emit(\"statusChanged\", newStatus);\n }\n }\n\n private setWaitingInfo(newWaitingInfo: ReactorWaitingInfo) {\n console.debug(\n \"[Reactor] Setting waiting info:\",\n newWaitingInfo,\n \"from\",\n this.waitingInfo\n );\n if (this.waitingInfo !== newWaitingInfo) {\n this.waitingInfo = newWaitingInfo;\n this.emit(\"waitingInfoChanged\", newWaitingInfo);\n }\n }\n\n getStatus(): ReactorStatus {\n return this.status;\n }\n\n /**\n * Get the current state including status, error, and waiting info\n */\n getState(): ReactorState {\n return {\n status: this.status,\n waitingInfo: this.waitingInfo,\n lastError: this.lastError,\n };\n }\n\n /**\n * Get waiting information when status is 'waiting'\n */\n getWaitingInfo(): ReactorWaitingInfo | undefined {\n return this.waitingInfo;\n }\n\n /**\n * Get the last error that occurred\n */\n getLastError(): ReactorError | undefined {\n return this.lastError;\n }\n\n /**\n * Create and store an error\n */\n private createError(\n code: string,\n message: string,\n component: \"coordinator\" | \"gpu\" | \"livekit\",\n recoverable: boolean,\n retryAfter?: number\n ) {\n this.lastError = {\n code,\n message,\n timestamp: Date.now(),\n recoverable,\n component,\n retryAfter,\n };\n\n // Emit error event\n this.emit(\"error\", this.lastError);\n }\n}\n","\"use client\";\n\nimport { ReactNode, useContext, useEffect, useRef, useState } from \"react\";\nimport {\n createReactorStore,\n initReactorStore,\n ReactorContext,\n ReactorStore,\n ReactorStoreApi,\n type ReactorInitializationProps,\n} from \"../core/store\";\nimport { useStore } from \"zustand\";\n\n// Provider props\ninterface ReactorProviderProps extends ReactorInitializationProps {\n autoConnect?: boolean;\n children: ReactNode;\n}\n\n// tsx component\nexport function ReactorProvider({\n children,\n autoConnect = true,\n ...props\n}: ReactorProviderProps) {\n // Stable Reactor instance\n const storeRef = useRef<ReactorStoreApi | undefined>(undefined);\n const firstRender = useRef(true);\n // State to trigger re-renders when store changes\n const [_storeVersion, setStoreVersion] = useState(0);\n\n if (storeRef.current === undefined) {\n console.debug(\"[ReactorProvider] Creating new reactor store\");\n // We create the store without autoconnecting, to avoid duplicate connections.\n // We actually connect when the component is mounted, to be on sync with the react component lifecycle.\n storeRef.current = createReactorStore(initReactorStore(props));\n console.debug(\"[ReactorProvider] Reactor store created successfully\");\n }\n\n // Fan out props to individual variables so that the\n // useEffect hook can be optimized by only re-running when the\n // props that actually change.\n const {\n coordinatorUrl,\n modelName,\n jwtToken,\n insecureApiKey,\n directConnection,\n queueing,\n local,\n } = props;\n\n useEffect(() => {\n if (firstRender.current) {\n firstRender.current = false;\n\n // We know as a fact that the store is not undefined at this point\n const current = storeRef.current!;\n if (autoConnect && current.getState().status === \"disconnected\") {\n console.debug(\n \"[ReactorProvider] Starting autoconnect in first render...\"\n );\n current\n .getState()\n .connect()\n .then(() => {\n console.debug(\n \"[ReactorProvider] Autoconnect successful in first render\"\n );\n })\n .catch((error) => {\n console.error(\n \"[ReactorProvider] Failed to autoconnect in first render:\",\n error\n );\n });\n }\n return () => {\n console.debug(\n \"[ReactorProvider] Disconnecting in cleanup for first render\"\n );\n current\n .getState()\n .disconnect()\n .then(() => {\n console.debug(\n \"[ReactorProvider] Disconnect completed successfully in cleanup for first render\"\n );\n })\n .catch((error) => {\n console.error(\n \"[ReactorProvider] Failed to disconnect in cleanup for first render:\",\n error\n );\n });\n };\n }\n\n console.debug(\"[ReactorProvider] Updating reactor store\");\n storeRef.current = createReactorStore(\n initReactorStore({\n coordinatorUrl,\n modelName,\n jwtToken,\n insecureApiKey,\n directConnection,\n queueing,\n local,\n } satisfies ReactorInitializationProps)\n );\n\n // Store current reference to the store in the return\n const current = storeRef.current!;\n\n // Increment version to trigger re-render and propagate new store to Provider\n setStoreVersion((v) => v + 1);\n console.debug(\n \"[ReactorProvider] Reactor store updated successfully, and increased version\"\n );\n\n if (autoConnect && current.getState().status === \"disconnected\") {\n console.debug(\"[ReactorProvider] Starting autoconnect...\");\n current\n .getState()\n .connect()\n .then(() => {\n console.debug(\"[ReactorProvider] Autoconnect successful\");\n })\n .catch((error) => {\n console.error(\"[ReactorProvider] Failed to autoconnect:\", error);\n });\n }\n\n return () => {\n console.debug(\"[ReactorProvider] Disconnecting in cleanup\");\n current\n .getState()\n .disconnect()\n .then(() => {\n console.debug(\n \"[ReactorProvider] Disconnect completed successfully in cleanup\"\n );\n })\n .catch((error) => {\n console.error(\"[ReactorProvider] Failed to disconnect:\", error);\n });\n };\n }, [\n coordinatorUrl,\n modelName,\n jwtToken,\n insecureApiKey,\n directConnection,\n queueing,\n autoConnect,\n local,\n ]);\n\n return (\n <ReactorContext.Provider value={storeRef.current}>\n {children}\n </ReactorContext.Provider>\n );\n}\n\nexport function useReactorStore<T = ReactorStore>(\n selector: (state: ReactorStore) => T\n): T {\n const ctx = useContext(ReactorContext);\n if (!ctx) {\n throw new Error(\"useReactor must be used within a ReactorProvider\");\n }\n\n return useStore(ctx, selector);\n}\n","import { StoreApi } from \"zustand\";\nimport type { ReactorStatus, ReactorWaitingInfo, ReactorError } from \"../types\";\nimport { Reactor, type Options as ReactorOptions } from \"./Reactor\";\nimport { create } from \"zustand/react\";\nimport { createContext } from \"react\";\nimport type { RemoteVideoTrack } from \"livekit-client\";\n\nexport type ReactorStoreApi = ReturnType<typeof createReactorStore>;\n\nexport interface ReactorState {\n status: ReactorStatus;\n videoTrack: RemoteVideoTrack | null;\n //These are the machine FPS. The machine internally reports to the client the rate at which the frames are\n //being generated. This can be useful for the client to calcolate at which rate to run commands.\n fps?: number;\n waitingInfo?: ReactorWaitingInfo;\n lastError?: ReactorError;\n}\n\nexport interface ReactorActions {\n sendMessage(message: any): Promise<void>;\n connect(): Promise<void>;\n disconnect(): Promise<void>;\n publishVideoStream(stream: MediaStream): Promise<void>;\n unpublishVideoStream(): Promise<void>;\n}\n\n// Internal state not exposed to components\ninterface ReactorInternalState {\n reactor: Reactor;\n}\n\nexport const ReactorContext = createContext<ReactorStoreApi | undefined>(\n undefined\n);\n\nexport type ReactorStore = ReactorState &\n ReactorActions & {\n internal: ReactorInternalState;\n };\n\nexport const defaultInitState: ReactorState = {\n status: \"disconnected\",\n videoTrack: null,\n fps: undefined,\n waitingInfo: undefined,\n lastError: undefined,\n};\n\nexport interface ReactorInitializationProps extends ReactorOptions {}\n\nexport const initReactorStore = (\n props: ReactorInitializationProps\n): ReactorState & ReactorInitializationProps => {\n return {\n ...defaultInitState,\n // These are only used for dev initialization, not exposed in the store\n ...props,\n };\n};\n\nexport const createReactorStore = (\n initProps: ReactorInitializationProps,\n publicState: ReactorState = defaultInitState\n): StoreApi<ReactorStore> => {\n console.debug(\"[ReactorStore] Creating store\", {\n coordinatorUrl: initProps.coordinatorUrl,\n initialState: publicState,\n });\n\n return create<ReactorStore>()((set, get) => {\n const reactor = new Reactor(initProps);\n\n console.debug(\"[ReactorStore] Setting up event listeners\");\n\n reactor.on(\"statusChanged\", (newStatus: ReactorStatus) => {\n console.debug(\"[ReactorStore] Status changed\", {\n oldStatus: get().status,\n newStatus,\n });\n set({ status: newStatus });\n });\n\n reactor.on(\"waitingInfoChanged\", (newWaitingInfo: ReactorWaitingInfo) => {\n console.debug(\"[ReactorStore] Waiting info changed\", {\n oldWaitingInfo: get().waitingInfo,\n newWaitingInfo,\n });\n set({ waitingInfo: newWaitingInfo });\n });\n\n reactor.on(\"streamChanged\", (videoTrack: RemoteVideoTrack | null) => {\n console.debug(\"[ReactorStore] Stream changed\", {\n hasVideoTrack: !!videoTrack,\n videoTrackKind: videoTrack?.kind,\n videoTrackSid: videoTrack?.sid,\n });\n set({ videoTrack: videoTrack });\n });\n\n reactor.on(\"fps\", (fps: number) => {\n console.debug(\"[ReactorStore] FPS updated\", { fps });\n set({ fps: fps });\n });\n\n reactor.on(\"error\", (error: ReactorError) => {\n console.debug(\"[ReactorStore] Error occurred\", error);\n set({ lastError: error });\n });\n\n return {\n ...publicState,\n internal: { reactor },\n\n // actions\n onMessage: (handler: (message: any) => void) => {\n console.debug(\"[ReactorStore] Registering message handler\");\n\n // Simply register the handler\n get().internal.reactor.on(\"newMessage\", handler);\n\n // Return a cleanup function that can be called to unregister\n return () => {\n console.debug(\"[ReactorStore] Cleaning up message handler\");\n get().internal.reactor.off(\"newMessage\", handler);\n };\n },\n sendMessage: async (mess: any) => {\n console.debug(\"[ReactorStore] Sending message\", { message: mess });\n\n try {\n await get().internal.reactor.sendMessage(mess);\n console.debug(\"[ReactorStore] Message sent successfully\");\n } catch (error) {\n console.error(\"[ReactorStore] Failed to send message:\", error);\n throw error;\n }\n },\n connect: async () => {\n console.debug(\"[ReactorStore] Connect called\");\n\n try {\n await get().internal.reactor.connect();\n console.debug(\"[ReactorStore] Connect completed successfully\");\n } catch (error) {\n console.error(\"[ReactorStore] Connect failed:\", error);\n throw error;\n }\n },\n disconnect: async () => {\n console.debug(\"[ReactorStore] Disconnect called\", {\n currentStatus: get().status,\n });\n\n try {\n await get().internal.reactor.disconnect();\n console.debug(\"[ReactorStore] Disconnect completed successfully\");\n } catch (error) {\n console.error(\"[ReactorStore] Disconnect failed:\", error);\n throw error;\n }\n },\n publishVideoStream: async (stream: MediaStream) => {\n console.debug(\"[ReactorStore] Publishing video stream\");\n\n try {\n await get().internal.reactor.publishVideoStream(stream);\n console.debug(\"[ReactorStore] Video stream published successfully\");\n } catch (error) {\n console.error(\n \"[ReactorStore] Failed to publish video stream:\",\n error\n );\n throw error;\n }\n },\n unpublishVideoStream: async () => {\n console.debug(\"[ReactorStore] Unpublishing video stream\");\n\n try {\n await get().internal.reactor.unpublishVideoStream();\n console.debug(\"[ReactorStore] Video stream unpublished successfully\");\n } catch (error) {\n console.error(\n \"[ReactorStore] Failed to unpublish video stream:\",\n error\n );\n throw error;\n }\n },\n };\n });\n};\n","import { useReactorStore } from \"./ReactorProvider\";\nimport type { ReactorStore } from \"../core/store\";\nimport { useShallow } from \"zustand/shallow\";\nimport { useEffect, useRef } from \"react\";\n\n/**\n * Generic hook for accessing selected parts of the Reactor store.\n *\n * @param selector - A function that selects part of the store state.\n * @returns The selected slice from the store.\n */\nexport function useReactor<T>(selector: (state: ReactorStore) => T): T {\n return useReactorStore(useShallow(selector));\n}\n\n/**\n * Hook for handling message subscriptions with proper React lifecycle management.\n *\n * @param handler - The message handler function\n */\nexport function useReactorMessage(handler: (message: any) => void): void {\n const reactor = useReactor((state) => state.internal.reactor);\n const handlerRef = useRef(handler);\n\n // Update the ref when handler changes\n useEffect(() => {\n handlerRef.current = handler;\n }, [handler]);\n\n useEffect(() => {\n console.debug(\"[useReactorMessage] Setting up message subscription\");\n\n // Create a stable handler that calls the current ref\n const stableHandler = (message: any) => {\n console.debug(\"[useReactorMessage] Message received\", { message });\n handlerRef.current(message);\n };\n\n // Register the handler and get the cleanup function\n reactor.on(\"newMessage\", stableHandler);\n\n console.debug(\"[useReactorMessage] Message handler registered\");\n\n // Return the cleanup function\n return () => {\n console.debug(\"[useReactorMessage] Cleaning up message subscription\");\n reactor.off(\"newMessage\", stableHandler);\n };\n }, [reactor]);\n}\n","\"use client\";\n\nimport { useReactor } from \"./hooks\";\nimport { useEffect, useRef } from \"react\";\nimport React from \"react\";\n\nexport interface ReactorViewProps {\n width?: number;\n height?: number;\n className?: string;\n style?: React.CSSProperties;\n videoObjectFit?: NonNullable<\n React.VideoHTMLAttributes<HTMLVideoElement>[\"style\"]\n >[\"objectFit\"];\n}\n\nexport function ReactorView({\n width,\n height,\n className,\n style,\n videoObjectFit = \"contain\",\n}: ReactorViewProps) {\n const { videoTrack, status } = useReactor((state) => ({\n videoTrack: state.videoTrack,\n status: state.status,\n }));\n\n const videoRef = useRef<HTMLVideoElement>(null);\n\n useEffect(() => {\n console.debug(\"[ReactorView] Video track effect triggered\", {\n hasVideoElement: !!videoRef.current,\n hasVideoTrack: !!videoTrack,\n videoTrackKind: videoTrack?.kind,\n });\n\n if (videoRef.current && videoTrack) {\n console.debug(\"[ReactorView] Attaching video track to element\");\n try {\n // Attach the LiveKit track to the video element\n videoTrack.attach(videoRef.current);\n console.debug(\"[ReactorView] Video track attached successfully\");\n } catch (error) {\n console.error(\"[ReactorView] Failed to attach video track:\", error);\n }\n\n // Cleanup: detach when track changes or component unmounts\n return () => {\n console.debug(\"[ReactorView] Detaching video track from element\");\n if (videoRef.current) {\n try {\n videoTrack.detach(videoRef.current);\n console.debug(\"[ReactorView] Video track detached successfully\");\n } catch (error) {\n console.error(\"[ReactorView] Failed to detach video track:\", error);\n }\n }\n };\n } else {\n console.debug(\"[ReactorView] No video track or element to attach\");\n }\n }, [videoTrack]);\n\n const showPlaceholder = !videoTrack;\n\n return (\n <div\n style={{\n position: \"relative\",\n background: \"#000\",\n ...(width && { width }),\n ...(height && { height }),\n ...style,\n }}\n className={className}\n >\n <video\n ref={videoRef}\n style={{\n width: \"100%\",\n height: \"100%\",\n objectFit: videoObjectFit,\n display: showPlaceholder ? \"none\" : \"block\",\n }}\n muted\n playsInline\n />\n {showPlaceholder && (\n <div\n style={{\n position: \"absolute\",\n top: 0,\n left: 0,\n width: \"100%\",\n height: \"100%\",\n color: \"#fff\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n fontSize: \"16px\",\n fontFamily: \"monospace\",\n textAlign: \"center\",\n padding: \"20px\",\n boxSizing: \"border-box\",\n }}\n >\n {status}\n </div>\n )}\n </div>\n );\n}\n","\"use client\";\n\nimport { useReactor } from \"./hooks\";\nimport { useEffect, useRef, useState } from \"react\";\nimport React from \"react\";\n\ninterface Props {\n className?: string;\n style?: React.CSSProperties;\n videoConstraints?: MediaTrackConstraints;\n showWebcam?: boolean;\n videoObjectFit?: NonNullable<\n React.VideoHTMLAttributes<HTMLVideoElement>[\"style\"]\n >[\"objectFit\"];\n}\n\nexport function WebcamStream({\n className,\n style,\n videoConstraints = {\n width: { ideal: 1280 },\n height: { ideal: 720 },\n },\n showWebcam = true,\n videoObjectFit = \"contain\",\n}: Props) {\n const [stream, setStream] = useState<MediaStream | null>(null);\n const [isPublishing, setIsPublishing] = useState(false);\n const [permissionDenied, setPermissionDenied] = useState(false);\n\n const { status, publishVideoStream, unpublishVideoStream, reactor } =\n useReactor((state) => ({\n status: state.status,\n publishVideoStream: state.publishVideoStream,\n unpublishVideoStream: state.unpublishVideoStream,\n reactor: state.internal.reactor,\n }));\n\n const videoRef = useRef<HTMLVideoElement>(null);\n\n // Start webcam\n const startWebcam = async () => {\n console.debug(\"[WebcamPublisher] Starting webcam\");\n\n try {\n const mediaStream = await navigator.mediaDevices.getUserMedia({\n video: videoConstraints,\n audio: false,\n });\n\n console.debug(\"[WebcamPublisher] Webcam started successfully\");\n setStream(mediaStream);\n setPermissionDenied(false);\n } catch (err) {\n console.error(\"[WebcamPublisher] Failed to start webcam:\", err);\n\n // Check if the error is a permission denial\n if (\n err instanceof DOMException &&\n (err.name === \"NotAllowedError\" || err.name === \"PermissionDeniedError\")\n ) {\n console.debug(\"[WebcamPublisher] Camera permission denied\");\n setPermissionDenied(true);\n }\n }\n };\n\n // Stop webcam\n const stopWebcam = async () => {\n console.debug(\"[WebcamPublisher] Stopping webcam\");\n\n // Unpublish if currently publishing\n try {\n await unpublishVideoStream();\n console.debug(\"[WebcamPublisher] Unpublished before stopping\");\n } catch (err) {\n console.error(\"[WebcamPublisher] Error unpublishing before stop:\", err);\n }\n\n setIsPublishing(false);\n\n // Stop all tracks\n stream?.getTracks().forEach((track) => {\n track.stop();\n console.debug(\"[WebcamPublisher] Stopped track:\", track.kind);\n });\n setStream(null);\n\n console.debug(\"[WebcamPublisher] Webcam stopped\");\n };\n\n // Attach stream to video element\n useEffect(() => {\n console.debug(\"[WebcamPublisher] Stream effect triggered\", {\n hasVideoElement: !!videoRef.current,\n hasStream: !!stream,\n });\n\n if (!videoRef.current) {\n return;\n }\n\n if (stream) {\n console.debug(\"[WebcamPublisher] Attaching stream to video element\");\n videoRef.current.srcObject = stream;\n console.debug(\"[WebcamPublisher] Stream attached successfully\");\n } else {\n console.debug(\"[WebcamPublisher] Clearing video element\");\n videoRef.current.srcObject = null;\n }\n }, [stream]);\n\n // Auto-publish when reactor is ready and webcam is active\n useEffect(() => {\n if (!stream) {\n return;\n }\n\n if (status === \"ready\" && !isPublishing) {\n console.debug(\n \"[WebcamPublisher] Reactor ready, auto-publishing webcam stream\"\n );\n publishVideoStream(stream)\n .then(() => {\n console.debug(\"[WebcamPublisher] Auto-publish successful\");\n setIsPublishing(true);\n })\n .catch((err) => {\n console.error(\"[WebcamPublisher] Auto-publish failed:\", err);\n });\n } else if (status !== \"ready\" && isPublishing) {\n console.debug(\"[WebcamPublisher] Reactor not ready, auto-unpublishing\");\n unpublishVideoStream()\n .then(() => {\n console.debug(\"[WebcamPublisher] Auto-unpublish successful\");\n setIsPublishing(false);\n })\n .catch((err) => {\n console.error(\"[WebcamPublisher] Auto-unpublish failed:\", err);\n });\n }\n }, [status, stream, isPublishing, publishVideoStream, unpublishVideoStream]);\n\n // Listen for error events from Reactor\n useEffect(() => {\n const handleError = (error: any) => {\n console.debug(\"[WebcamPublisher] Received error event:\", error);\n\n // Handle video publish failures by resetting state\n if (error.code === \"VIDEO_PUBLISH_FAILED\") {\n console.debug(\n \"[WebcamPublisher] Video publish failed, resetting isPublishing state\"\n );\n setIsPublishing(false);\n }\n };\n\n reactor.on(\"error\", handleError);\n\n return () => {\n reactor.off(\"error\", handleError);\n };\n }, [reactor]);\n\n // Reset publishing state when status changes away from ready\n useEffect(() => {\n if (status !== \"ready\") {\n console.debug(\n \"[WebcamPublisher] Status changed to\",\n status,\n \"- resetting isPublishing state\"\n );\n setIsPublishing(false);\n }\n }, [status, isPublishing]);\n\n // Auto-start webcam on mount and cleanup on unmount\n useEffect(() => {\n console.debug(\"[WebcamPublisher] Auto-starting webcam\");\n startWebcam();\n\n return () => {\n console.debug(\"[WebcamPublisher] Cleanup on unmount\");\n stopWebcam();\n };\n }, []); // eslint-disable-line react-hooks/exhaustive-deps\n\n const showPlaceholder = !stream;\n\n return (\n <div\n style={{\n display: showWebcam ? \"block\" : \"none\",\n position: \"relative\",\n background: \"#000\",\n ...style,\n }}\n className={className}\n >\n <video\n ref={videoRef}\n style={{\n width: \"100%\",\n height: \"100%\",\n objectFit: videoObjectFit,\n display: showPlaceholder ? \"none\" : \"block\",\n }}\n muted\n playsInline\n autoPlay\n />\n {showPlaceholder && (\n <div\n style={{\n position: \"absolute\",\n top: 0,\n left: 0,\n width: \"100%\",\n height: \"100%\",\n color: \"#fff\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n fontSize: \"16px\",\n fontFamily: \"monospace\",\n textAlign: \"center\",\n padding: \"20px\",\n boxSizing: \"border-box\",\n flexDirection: \"column\",\n gap: \"12px\",\n }}\n >\n {permissionDenied ? (\n <div style={{ fontSize: \"12px\", fontFamily: \"monospace\" }}>\n Camera access denied.\n <br />\n Please allow access in your browser settings.\n </div>\n ) : (\n <div style={{ fontSize: \"12px\", fontFamily: \"monospace\" }}>\n Starting camera...\n </div>\n )}\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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","names":["import_zod","_a","import_zod","OptionsSchema","import_react","import_react","current","import_react","import_react","import_jsx_runtime","import_react","import_jsx_runtime"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/core/types.ts","../src/core/CoordinatorClient.ts","../src/core/GPUMachineClient.ts","../src/core/Reactor.ts","../src/react/ReactorProvider.tsx","../src/core/store.ts","../src/react/hooks.ts","../src/react/ReactorView.tsx","../src/react/WebcamStream.tsx"],"sourcesContent":["export * from \"./core/Reactor\";\nexport * from \"./react/ReactorProvider\";\nexport * from \"./react/ReactorView\";\nexport * from \"./react/WebcamStream\";\nexport * from \"./react/hooks\";\nexport * from \"./types\";\n","/**\n * Internal types for the Reactor SDK.\n */\n\nimport { z } from \"zod\";\n\n// Base message schemas corresponding to Python Pydantic models\n\nexport const ApplicationMessageSchema = z.object({\n type: z.literal(\"application\"),\n data: z.any(), // Can be any JSON-serializable data\n});\n\n// Internal message that notifies the client of the current push rate of the machine\nexport const FPSMessageSchema = z.object({\n type: z.literal(\"fps\"),\n data: z.number(),\n});\n\nexport const GPUMachineReceiveMessageSchema = z.discriminatedUnion(\"type\", [\n ApplicationMessageSchema,\n FPSMessageSchema,\n]);\n\nexport const WelcomeMessageSchema = z.object({\n type: z.literal(\"welcome\"),\n data: z.record(z.string(), z.any()),\n});\n\nexport const GPUMachineAssignmentDataSchema = z.object({\n livekitWsUrl: z.string(),\n livekitJwtToken: z.string(),\n});\n\nexport const GPUMachineAssignmentMessageSchema = z.object({\n type: z.literal(\"gpu-machine-assigned\"),\n data: GPUMachineAssignmentDataSchema,\n});\n\nexport const EchoMessageSchema = z.object({\n type: z.literal(\"echo\"),\n data: z.record(z.string(), z.any()),\n});\n\nexport const WaitingInfoDataSchema = z.object({\n position: z.number().optional(),\n estimatedWaitTime: z.number().optional(),\n averageWaitTime: z.number().optional(),\n});\n\nexport const WaitingInfoMessageSchema = z.object({\n type: z.literal(\"waiting-info\"),\n data: WaitingInfoDataSchema,\n});\n\nexport const SessionExpirationDataSchema = z.object({\n expire: z.number(),\n});\n\nexport const SessionExpirationMessageSchema = z.object({\n type: z.literal(\"session-expiration\"),\n data: SessionExpirationDataSchema,\n});\n\nexport const CoordinatorMessageSchema = z.discriminatedUnion(\"type\", [\n WelcomeMessageSchema,\n GPUMachineAssignmentMessageSchema,\n EchoMessageSchema,\n WaitingInfoMessageSchema,\n SessionExpirationMessageSchema,\n]);\n\nexport const GPUMachineSendMessageSchema = z.discriminatedUnion(\"type\", [\n ApplicationMessageSchema,\n]);\n\nexport const SessionSetupMessageSchema = z.object({\n type: z.literal(\"sessionSetup\"),\n data: z.object({\n modelName: z.string(),\n modelVersion: z.string().default(\"latest\"),\n }),\n});\n\n// TypeScript types derived from schemas\nexport type ApplicationMessage = z.infer<typeof ApplicationMessageSchema>;\nexport type GPUMachineReceiveMessageSchema = z.infer<\n typeof GPUMachineReceiveMessageSchema\n>;\nexport type WelcomeMessage = z.infer<typeof WelcomeMessageSchema>;\nexport type GPUMachineAssignmentData = z.infer<\n typeof GPUMachineAssignmentDataSchema\n>;\nexport type GPUMachineAssignmentMessage = z.infer<\n typeof GPUMachineAssignmentMessageSchema\n>;\nexport type EchoMessage = z.infer<typeof EchoMessageSchema>;\nexport type WaitingInfoData = z.infer<typeof WaitingInfoDataSchema>;\nexport type WaitingInfoMessage = z.infer<typeof WaitingInfoMessageSchema>;\nexport type CoordinatorMessage = z.infer<typeof CoordinatorMessageSchema>;\nexport type GPUMachineSendMessage = z.infer<typeof GPUMachineSendMessageSchema>;\nexport type SessionSetupMessage = z.infer<typeof SessionSetupMessageSchema>;\n\n// Internal connection status for individual components\nexport type InternalConnectionStatus =\n | \"disconnected\"\n | \"connecting\"\n | \"connected\"\n | \"error\";\n","/**\n * The CoordinatorClient is responsible for handling the connection to the coordinator.\n */\n\nimport {\n type CoordinatorMessage,\n CoordinatorMessageSchema,\n type SessionSetupMessage,\n} from \"./types\";\nimport { z } from \"zod\";\n\ntype EventHandler = (...args: any[]) => void;\n\nconst OptionsSchema = z\n .object({\n wsUrl: z.string().nonempty(),\n jwtToken: z.string().optional(),\n insecureApiKey: z.string().optional(),\n modelName: z.string(),\n modelVersion: z.string().default(\"latest\"),\n queueing: z.boolean().default(false),\n })\n .refine((data) => data.jwtToken || data.insecureApiKey, {\n message: \"At least one of jwtToken or insecureApiKey must be provided.\",\n });\n\ntype Options = z.input<typeof OptionsSchema>;\n\n// Infer message types from the schema - single source of truth\nexport type CoordinatorEvent = \"statusChanged\" | CoordinatorMessage[\"type\"];\n\nexport class CoordinatorClient {\n private websocket?: WebSocket;\n private wsUrl: string;\n private jwtToken?: string;\n private insecureApiKey?: string;\n private eventListeners: Map<CoordinatorEvent, Set<EventHandler>> = new Map();\n private modelName: string;\n private modelVersion: string;\n private queueing: boolean;\n\n constructor(options: Options) {\n const validatedOptions = OptionsSchema.parse(options);\n this.wsUrl = validatedOptions.wsUrl;\n this.jwtToken = validatedOptions.jwtToken;\n this.insecureApiKey = validatedOptions.insecureApiKey;\n this.modelName = validatedOptions.modelName;\n this.modelVersion = validatedOptions.modelVersion;\n this.queueing = validatedOptions.queueing;\n }\n\n // Event Emitter API\n on(event: CoordinatorEvent, handler: EventHandler) {\n if (!this.eventListeners.has(event)) {\n this.eventListeners.set(event, new Set());\n }\n this.eventListeners.get(event)!.add(handler);\n }\n\n off(event: CoordinatorEvent, handler: EventHandler) {\n this.eventListeners.get(event)?.delete(handler);\n }\n\n emit(event: CoordinatorEvent, ...args: any[]) {\n this.eventListeners.get(event)?.forEach((handler) => handler(...args));\n }\n\n sendMessage(message: any) {\n try {\n const messageStr =\n typeof message === \"string\" ? message : JSON.stringify(message);\n this.websocket?.send(messageStr);\n } catch (error) {\n console.error(\"[CoordinatorClient] Failed to send message:\", error);\n this.emit(\"statusChanged\", \"error\");\n }\n }\n\n async connect(): Promise<void> {\n // Build WebSocket URL with authentication query parameters\n const url = new URL(this.wsUrl);\n if (this.jwtToken) {\n url.searchParams.set(\"jwt_token\", this.jwtToken);\n } else if (this.insecureApiKey) {\n url.searchParams.set(\"api_key\", this.insecureApiKey);\n }\n\n // Add queued parameter only if queueing is true\n if (this.queueing) {\n url.searchParams.set(\"queueing\", \"true\");\n }\n\n console.debug(\"[CoordinatorClient] Connecting to\", url.toString());\n this.websocket = new WebSocket(url.toString());\n\n this.websocket.onopen = () => {\n console.debug(\"[CoordinatorClient] WebSocket opened\");\n this.emit(\"statusChanged\", \"connected\");\n };\n\n this.websocket.onmessage = (event) => {\n try {\n let parsedData: string | object;\n if (typeof event.data === \"string\") {\n parsedData = JSON.parse(event.data);\n } else {\n parsedData = event.data;\n }\n console.debug(\n \"[CoordinatorClient] Received message from coordinator:\",\n parsedData\n );\n const validatedData = CoordinatorMessageSchema.parse(parsedData);\n this.emit(validatedData.type, validatedData.data);\n } catch (error) {\n console.error(\n \"[CoordinatorClient] Failed to parse WebSocket message from coordinator:\",\n error,\n \"message\",\n event.data\n );\n this.emit(\"statusChanged\", \"error\");\n }\n };\n\n this.websocket.onclose = (event) => {\n console.debug(\"[CoordinatorClient] WebSocket closed\", event);\n this.websocket = undefined;\n this.emit(\"statusChanged\", \"disconnected\");\n };\n\n this.websocket.onerror = (error) => {\n console.error(\"[CoordinatorClient] WebSocket error:\", error);\n this.websocket = undefined;\n this.emit(\"statusChanged\", \"error\");\n };\n\n await new Promise<void>((resolve, reject) => {\n const onOpen = () => {\n this.websocket?.removeEventListener(\"error\", onError);\n resolve();\n };\n const onError = (error: Event) => {\n this.websocket?.removeEventListener(\"open\", onOpen);\n reject(error);\n };\n this.websocket?.addEventListener(\"open\", onOpen);\n this.websocket?.addEventListener(\"error\", onError);\n });\n\n console.log(\"[CoordinatorClient] WebSocket connected\");\n\n this.sendMessage({\n type: \"sessionSetup\",\n data: {\n modelName: this.modelName,\n modelVersion: this.modelVersion,\n },\n } satisfies SessionSetupMessage);\n\n console.debug(\"[CoordinatorClient] Setup session message sent\");\n }\n\n /**\n * Closes the WebSocket connection if it exists.\n * This will trigger the onclose event handler.\n */\n disconnect() {\n if (this.websocket) {\n console.debug(\"[CoordinatorClient] Closing WebSocket connection\");\n this.websocket.close();\n this.websocket = undefined;\n }\n }\n}\n","/**\n * The GPUMachineClient is responsible for handling the direct connection to the machine instance\n * after the coordinator has assigned a machine.\n */\n\nimport {\n type GPUMachineSendMessage,\n GPUMachineReceiveMessageSchema,\n} from \"./types\";\nimport {\n Room,\n RoomEvent,\n Track,\n RemoteVideoTrack,\n LocalVideoTrack,\n LocalAudioTrack,\n} from \"livekit-client\";\n\ntype EventHandler = (...args: any[]) => void;\nexport type GPUMachineEvent =\n | GPUMachineReceiveMessageSchema[\"type\"]\n | \"statusChanged\"\n | \"streamChanged\";\n\nexport class GPUMachineClient {\n private eventListeners: Map<GPUMachineEvent, Set<EventHandler>> = new Map();\n private roomInstance: Room | undefined;\n private machineFPS: number | undefined;\n private token: string;\n private videoStream: MediaStream | undefined;\n private liveKitUrl: string;\n private publishedVideoTrack: LocalVideoTrack | undefined;\n private publishedAudioTrack: LocalAudioTrack | undefined;\n\n constructor(token: string, liveKitUrl: string) {\n this.token = token;\n this.liveKitUrl = liveKitUrl;\n }\n\n // Event Emitter API\n on(event: GPUMachineEvent, handler: EventHandler) {\n if (!this.eventListeners.has(event)) {\n this.eventListeners.set(event, new Set());\n }\n this.eventListeners.get(event)!.add(handler);\n }\n\n off(event: GPUMachineEvent, handler: EventHandler) {\n this.eventListeners.get(event)?.delete(handler);\n }\n\n emit(event: GPUMachineEvent, ...args: any[]) {\n this.eventListeners.get(event)?.forEach((handler) => handler(...args));\n }\n\n async sendMessage(message: GPUMachineSendMessage): Promise<void> {\n try {\n if (this.roomInstance) {\n const messageStr = JSON.stringify(message);\n // Send message via LiveKit text channel\n await this.roomInstance.localParticipant.sendText(messageStr, {\n topic: \"application\",\n });\n } else {\n console.warn(\n \"[GPUMachineClient] Cannot send message - not connected to room\"\n );\n }\n } catch (error) {\n console.error(\"[GPUMachineClient] Failed to send message:\", error);\n this.emit(\"statusChanged\", \"error\");\n }\n }\n\n async connect(): Promise<void> {\n this.roomInstance = new Room({\n adaptiveStream: true,\n dynacast: true,\n });\n\n this.roomInstance.on(RoomEvent.Connected, () => {\n console.debug(\"[GPUMachineClient] Connected to room\");\n this.emit(\"statusChanged\", \"connected\");\n });\n\n this.roomInstance.on(RoomEvent.Disconnected, () => {\n console.debug(\"[GPUMachineClient] Disconnected from room\");\n this.emit(\"statusChanged\", \"disconnected\");\n });\n\n // Handle video track subscriptions from GPU machine\n this.roomInstance.on(\n RoomEvent.TrackSubscribed,\n (track, _publication, participant) => {\n console.debug(\n \"[GPUMachineClient] Track subscribed:\",\n track.kind,\n participant.identity\n );\n\n if (track.kind === Track.Kind.Video) {\n const videoTrack = track as RemoteVideoTrack;\n this.emit(\"streamChanged\", videoTrack);\n }\n }\n );\n\n this.roomInstance.on(\n RoomEvent.TrackUnsubscribed,\n (track, _publication, participant) => {\n console.debug(\n \"[GPUMachineClient] Track unsubscribed:\",\n track.kind,\n participant.identity\n );\n\n if (track.kind === Track.Kind.Video) {\n this.emit(\"streamChanged\", null);\n }\n }\n );\n\n this.roomInstance.registerTextStreamHandler(\n \"application\",\n async (reader, participant) => {\n const text = await reader.readAll();\n console.log(\"[GPUMachineClient] Received message:\", text);\n try {\n const parsedData = JSON.parse(text);\n\n const validatedMessage =\n GPUMachineReceiveMessageSchema.parse(parsedData);\n if (validatedMessage.type === \"fps\") {\n this.machineFPS = validatedMessage.data;\n }\n\n this.emit(validatedMessage.type, validatedMessage.data);\n } catch (error) {\n console.error(\n \"[GPUMachineClient] Failed to parse/validate message:\",\n error\n );\n this.emit(\"statusChanged\", \"error\");\n }\n }\n );\n\n await this.roomInstance.connect(this.liveKitUrl, this.token);\n\n console.log(\"[GPUMachineClient] Room connected\");\n }\n\n /**\n * Closes the LiveKit connection if it exists.\n * This will trigger the onclose event handler.\n */\n async disconnect() {\n // Unpublish any published tracks before disconnecting\n if (this.publishedVideoTrack) {\n await this.unpublishVideoTrack();\n }\n if (this.publishedAudioTrack) {\n await this.unpublishAudioTrack();\n }\n\n if (this.roomInstance) {\n console.debug(\"[GPUMachineClient] Closing LiveKit connection\");\n await this.roomInstance.disconnect();\n this.roomInstance = undefined;\n }\n this.machineFPS = undefined;\n }\n\n /**\n * Returns the current fps rate of the machine.\n * @returns The current fps rate of the machine.\n */\n getFPS(): number | undefined {\n return this.machineFPS;\n }\n\n /**\n * Returns the current video stream from the GPU machine.\n * @returns The current video stream or undefined if not available.\n */\n getVideoStream(): MediaStream | undefined {\n return this.videoStream;\n }\n\n /**\n * Publishes a video track from the provided MediaStream to the LiveKit room.\n * Only one video track can be published at a time. If a video track is already\n * published, it will be unpublished first.\n *\n * @param mediaStream The MediaStream containing the video track to publish\n * @throws Error if no video track is found in the MediaStream or room is not connected\n */\n async publishVideoTrack(mediaStream: MediaStream): Promise<void> {\n if (!this.roomInstance) {\n throw new Error(\n \"[GPUMachineClient] Cannot publish track - not connected to room\"\n );\n }\n\n const videoTracks = mediaStream.getVideoTracks();\n if (videoTracks.length === 0) {\n throw new Error(\"[GPUMachineClient] No video track found in MediaStream\");\n }\n\n // Unpublish existing video track if any\n if (this.publishedVideoTrack) {\n await this.unpublishVideoTrack();\n }\n\n try {\n const videoTrack = videoTracks[0];\n const localVideoTrack =\n await this.roomInstance.localParticipant.publishTrack(videoTrack, {\n name: \"client-video\",\n source: Track.Source.Camera,\n });\n\n this.publishedVideoTrack = localVideoTrack.track as LocalVideoTrack;\n console.debug(\"[GPUMachineClient] Video track published successfully\");\n } catch (error) {\n console.error(\"[GPUMachineClient] Failed to publish video track:\", error);\n throw error;\n }\n }\n\n /**\n * Unpublishes the currently published video track.\n * Note: We pass false to unpublishTrack to prevent LiveKit from stopping\n * the source MediaStreamTrack, as it's owned by the component that created it.\n */\n async unpublishVideoTrack(): Promise<void> {\n if (!this.roomInstance || !this.publishedVideoTrack) {\n return;\n }\n\n const publishedVideoTrack = this.publishedVideoTrack;\n this.publishedVideoTrack = undefined;\n\n try {\n await this.roomInstance.localParticipant.unpublishTrack(\n publishedVideoTrack,\n false // Don't stop the source track - it's managed externally\n );\n console.debug(\"[GPUMachineClient] Video track unpublished successfully\");\n } catch (error) {\n console.error(\n \"[GPUMachineClient] Failed to unpublish video track:\",\n error\n );\n throw error;\n }\n }\n\n /**\n * Publishes an audio track from the provided MediaStream to the LiveKit room.\n * This is an internal method. Only one audio track can be published at a time.\n *\n * @param mediaStream The MediaStream containing the audio track to publish\n * @private\n */\n private async publishAudioTrack(mediaStream: MediaStream): Promise<void> {\n if (!this.roomInstance) {\n throw new Error(\n \"[GPUMachineClient] Cannot publish track - not connected to room\"\n );\n }\n\n const audioTracks = mediaStream.getAudioTracks();\n if (audioTracks.length === 0) {\n throw new Error(\"[GPUMachineClient] No audio track found in MediaStream\");\n }\n\n // Unpublish existing audio track if any\n if (this.publishedAudioTrack) {\n await this.unpublishAudioTrack();\n }\n\n try {\n const audioTrack = audioTracks[0];\n const localAudioTrack =\n await this.roomInstance.localParticipant.publishTrack(audioTrack, {\n name: \"client-audio\",\n source: Track.Source.Microphone,\n });\n\n this.publishedAudioTrack = localAudioTrack.track as LocalAudioTrack;\n console.debug(\"[GPUMachineClient] Audio track published successfully\");\n } catch (error) {\n console.error(\"[GPUMachineClient] Failed to publish audio track:\", error);\n throw error;\n }\n }\n\n /**\n * Unpublishes the currently published audio track.\n * Note: We pass false to unpublishTrack to prevent LiveKit from stopping\n * the source MediaStreamTrack, as it's owned by the component that created it.\n * @private\n */\n private async unpublishAudioTrack(): Promise<void> {\n if (!this.roomInstance || !this.publishedAudioTrack) {\n return;\n }\n\n const publishedAudioTrack = this.publishedAudioTrack;\n this.publishedAudioTrack = undefined;\n\n try {\n await this.roomInstance.localParticipant.unpublishTrack(\n publishedAudioTrack,\n false // Don't stop the source track - it's managed externally\n );\n console.debug(\"[GPUMachineClient] Audio track unpublished successfully\");\n } catch (error) {\n console.error(\n \"[GPUMachineClient] Failed to unpublish audio track:\",\n error\n );\n throw error;\n }\n }\n}\n","import type {\n ApplicationMessage,\n InternalConnectionStatus,\n GPUMachineAssignmentData,\n} from \"./types\";\nimport type {\n ReactorEvent,\n ReactorStatus,\n ReactorState,\n ReactorError,\n ReactorWaitingInfo,\n ReactorSessionExpiration,\n} from \"../types\";\nimport { CoordinatorClient } from \"./CoordinatorClient\";\nimport { GPUMachineClient } from \"./GPUMachineClient\";\nimport { z } from \"zod\";\n\nconst LOCAL_COORDINATOR_URL = \"ws://localhost:8080/ws\";\nconst LOCAL_INSECURE_API_KEY = \"1234\";\nconst PROD_COORDINATOR_URL = \"wss://api.reactor.inc/ws\";\n\nconst OptionsSchema = z\n .object({\n directConnection: z\n .object({\n livekitJwtToken: z.string(),\n livekitWsUrl: z.string(),\n })\n .optional(),\n insecureApiKey: z.string().optional(),\n jwtToken: z.string().optional(),\n coordinatorUrl: z.string().default(PROD_COORDINATOR_URL),\n modelName: z.string(),\n queueing: z.boolean().default(false),\n local: z.boolean().default(false),\n })\n .refine(\n (data) =>\n data.directConnection ||\n data.insecureApiKey ||\n data.jwtToken ||\n data.local,\n {\n message:\n \"At least one of directConnection, insecureApiKey, or jwtToken or local must be provided.\",\n }\n );\nexport type Options = z.input<typeof OptionsSchema>;\n\ntype EventHandler = (...args: any[]) => void;\n\nexport class Reactor {\n private coordinatorClient: CoordinatorClient | undefined; //client for the coordinator\n private machineClient: GPUMachineClient | undefined; //client for the machine instance\n private status: ReactorStatus = \"disconnected\";\n private coordinatorUrl: string;\n private lastError?: ReactorError;\n private waitingInfo?: ReactorWaitingInfo;\n private jwtToken?: string;\n private insecureApiKey?: string;\n private directConnection?: {\n livekitJwtToken: string;\n livekitWsUrl: string;\n };\n private modelName: string;\n private modelVersion: string;\n private queueing: boolean;\n private sessionExpiration?: number;\n\n constructor(options: Options) {\n const validatedOptions = OptionsSchema.parse(options);\n this.coordinatorUrl = validatedOptions.coordinatorUrl;\n this.jwtToken = validatedOptions.jwtToken;\n this.insecureApiKey = validatedOptions.insecureApiKey;\n this.directConnection = validatedOptions.directConnection;\n this.modelName = validatedOptions.modelName;\n this.queueing = validatedOptions.queueing;\n // TODO: Use the model version from the options once we have a way to handle multiple versions\n this.modelVersion = \"1.0.0\";\n if (validatedOptions.local) {\n this.coordinatorUrl = LOCAL_COORDINATOR_URL;\n this.insecureApiKey = LOCAL_INSECURE_API_KEY;\n }\n }\n\n // Generic event map\n private eventListeners: Map<ReactorEvent, Set<EventHandler>> = new Map();\n\n // Event Emitter API\n on(event: ReactorEvent, handler: EventHandler) {\n if (!this.eventListeners.has(event)) {\n this.eventListeners.set(event, new Set());\n }\n this.eventListeners.get(event)!.add(handler);\n }\n\n off(event: ReactorEvent, handler: EventHandler) {\n this.eventListeners.get(event)?.delete(handler);\n }\n\n emit(event: ReactorEvent, ...args: any[]) {\n this.eventListeners.get(event)?.forEach((handler) => handler(...args));\n }\n\n /**\n * Public method to send a message to the machine.\n * Automatically wraps the message in an application message.\n * @param message The message to send to the machine.\n * @throws Error if not in ready state\n */\n async sendMessage(message: any): Promise<void> {\n // Synchronous validation - throw immediately\n if (process.env.NODE_ENV !== \"development\" && this.status !== \"ready\") {\n const errorMessage = `Cannot send message, status is ${this.status}`;\n console.error(\"[Reactor] Not ready, cannot send message\");\n throw new Error(errorMessage);\n }\n\n try {\n // Automatically wrap the user-message in an application message.\n const applicationMessage: ApplicationMessage = {\n type: \"application\",\n data: message,\n };\n await this.machineClient?.sendMessage(applicationMessage);\n } catch (error) {\n // Async operational error - emit event only\n console.error(\"[Reactor] Failed to send message:\", error);\n this.createError(\n \"MESSAGE_SEND_FAILED\",\n `Failed to send message: ${error}`,\n \"gpu\",\n true\n );\n // Don't re-throw - let the error event handle it\n }\n }\n\n /**\n * Public method to publish a video stream to the machine.\n * @param videoStream The video stream to send to the machine.\n */\n async publishVideoStream(videoStream: MediaStream): Promise<void> {\n // Synchronous validation - throw immediately\n if (process.env.NODE_ENV !== \"development\" && this.status !== \"ready\") {\n const errorMessage = `Cannot publish video stream, status is ${this.status}`;\n console.error(\"[Reactor] Not ready, cannot publish video stream\");\n throw new Error(errorMessage);\n }\n\n try {\n await this.machineClient?.publishVideoTrack(videoStream);\n } catch (error) {\n console.error(\"[Reactor] Failed to publish video:\", error);\n this.createError(\n \"VIDEO_PUBLISH_FAILED\",\n `Failed to publish video: ${error}`,\n \"gpu\",\n true\n );\n }\n }\n\n /**\n * Public method to unpublish video stream to the machine.\n * This unpublishes the video track that was previously sent.\n */\n async unpublishVideoStream(): Promise<void> {\n try {\n await this.machineClient?.unpublishVideoTrack();\n } catch (error) {\n console.error(\"[Reactor] Failed to unpublish video:\", error);\n this.createError(\n \"VIDEO_UNPUBLISH_FAILED\",\n `Failed to unpublish video: ${error}`,\n \"gpu\",\n true\n );\n }\n }\n\n /**\n * Connects to the machine via LiveKit and waits for the gpu machine to be ready.\n * Once the machine is ready, the Reactor will establish the LiveKit connection.\n * @param livekitJwtToken The JWT token for LiveKit authentication\n * @param livekitWsUrl The WebSocket URL for LiveKit connection\n */\n private async connectToGPUMachine(\n livekitJwtToken: string,\n livekitWsUrl: string\n ) {\n console.debug(\"[Reactor] Connecting to machine room...\");\n\n try {\n this.machineClient = new GPUMachineClient(livekitJwtToken, livekitWsUrl);\n\n this.machineClient.on(\"application\", (message: any) => {\n // escalate the message event through the instance, so that the user can listen to it.\n this.emit(\"newMessage\", message);\n });\n\n this.machineClient.on(\n \"statusChanged\",\n (status: InternalConnectionStatus) => {\n switch (status) {\n case \"connected\":\n this.setStatus(\"ready\");\n break;\n case \"disconnected\":\n // gpu machine has disconnected. Close any other connection to any other entity\n // such as the coordinator or the LiveKit connection.\n this.disconnect();\n break;\n case \"error\":\n // gpu machine has errored. Close any other connection to any other entity\n // such as the coordinator or the LiveKit connection.\n this.createError(\n \"GPU_CONNECTION_ERROR\",\n \"GPU machine connection failed\",\n \"gpu\",\n true\n );\n this.disconnect();\n break;\n }\n }\n );\n\n this.machineClient.on(\"fps\", (fps: number) => {\n this.emit(\"fps\", fps);\n });\n\n this.machineClient.on(\"streamChanged\", (videoTrack) => {\n this.emit(\"streamChanged\", videoTrack);\n });\n\n console.debug(\"[Reactor] About to connect to machine\");\n await this.machineClient.connect();\n } catch (error) {\n // For private methods, we can still throw since the caller will handle it appropriately\n throw error;\n }\n }\n\n /**\n * Connects to the coordinator and waits for a GPU to be assigned.\n * Once a GPU is assigned, the Reactor will connect to the gpu machine via LiveKit.\n */\n async connect(): Promise<void> {\n console.debug(\"[Reactor] Connecting, status:\", this.status);\n\n // Synchronous validation - throw immediately\n if (this.status !== \"disconnected\")\n throw new Error(\"Already connected or connecting\");\n\n if (this.directConnection) {\n return this.connectToGPUMachine(\n this.directConnection.livekitJwtToken,\n this.directConnection.livekitWsUrl\n );\n }\n\n this.setStatus(\"connecting\");\n\n try {\n console.debug(\n \"[Reactor] Connecting to coordinator with authenticated URL\"\n );\n\n this.coordinatorClient = new CoordinatorClient({\n wsUrl: this.coordinatorUrl,\n jwtToken: this.jwtToken,\n insecureApiKey: this.insecureApiKey,\n modelName: this.modelName,\n modelVersion: this.modelVersion,\n queueing: this.queueing,\n });\n\n this.coordinatorClient.on(\n \"gpu-machine-assigned\",\n async (assignmentData: GPUMachineAssignmentData) => {\n console.debug(\n \"[Reactor] GPU machine assigned by coordinator:\",\n assignmentData\n );\n try {\n await this.connectToGPUMachine(\n assignmentData.livekitJwtToken,\n assignmentData.livekitWsUrl\n );\n } catch (error) {\n console.error(\"[Reactor] Failed to connect to GPU machine:\", error);\n // Emit error event for async GPU connection failure\n this.createError(\n \"GPU_CONNECTION_FAILED\",\n `Failed to connect to GPU machine: ${error}`,\n \"gpu\",\n true\n );\n this.disconnect();\n }\n }\n );\n\n this.coordinatorClient.on(\n \"waiting-info\",\n (waitingData: ReactorWaitingInfo) => {\n console.debug(\"[Reactor] Waiting info update received:\", waitingData);\n // Update waiting info\n this.setWaitingInfo({\n ...this.waitingInfo,\n ...waitingData,\n });\n }\n );\n\n this.coordinatorClient.on(\n \"session-expiration\",\n (sessionExpirationData: ReactorSessionExpiration) => {\n this.setSessionExpiration(sessionExpirationData.expire);\n }\n );\n\n this.coordinatorClient.on(\n \"statusChanged\",\n (newStatus: InternalConnectionStatus) => {\n switch (newStatus) {\n case \"connected\":\n this.setStatus(\"waiting\");\n // Initialize waiting info when entering waiting state\n this.setWaitingInfo({\n position: undefined,\n estimatedWaitTime: undefined,\n averageWaitTime: undefined,\n });\n break;\n case \"disconnected\":\n this.disconnect();\n break;\n case \"error\":\n this.createError(\n \"COORDINATOR_CONNECTION_ERROR\",\n \"Coordinator connection failed\",\n \"coordinator\",\n true\n );\n this.disconnect();\n break;\n }\n }\n );\n\n await this.coordinatorClient.connect();\n } catch (error) {\n console.error(\"[Reactor] Authentication failed:\", error);\n this.createError(\n \"AUTHENTICATION_FAILED\",\n `Authentication failed: ${error}`,\n \"coordinator\",\n true\n );\n this.setStatus(\"disconnected\");\n // Keep throwing for authentication failures as these are immediate/sync failures\n throw error;\n }\n }\n\n /**\n * Disconnects from the coordinator and the gpu machine.\n * Ensures cleanup completes even if individual disconnections fail.\n */\n async disconnect() {\n if (this.status === \"disconnected\") return;\n\n // Disconnect coordinator client with error handling\n if (this.coordinatorClient) {\n try {\n this.coordinatorClient.disconnect();\n } catch (error) {\n console.error(\"[Reactor] Error disconnecting from coordinator:\", error);\n // Continue with cleanup even if coordinator disconnect fails\n }\n this.coordinatorClient = undefined;\n }\n\n // Disconnect machine client with error handling\n if (this.machineClient) {\n try {\n await this.machineClient.disconnect();\n } catch (error) {\n console.error(\"[Reactor] Error disconnecting from GPU machine:\", error);\n // Continue with cleanup even if machine disconnect fails\n }\n this.machineClient = undefined;\n }\n\n this.setStatus(\"disconnected\");\n this.setSessionExpiration(undefined);\n\n // Clear waiting info when disconnecting\n this.setWaitingInfo(undefined);\n }\n\n private setStatus(newStatus: ReactorStatus) {\n console.debug(\"[Reactor] Setting status:\", newStatus, \"from\", this.status);\n if (this.status !== newStatus) {\n this.status = newStatus;\n this.emit(\"statusChanged\", newStatus);\n }\n }\n\n private setWaitingInfo(newWaitingInfo: ReactorWaitingInfo | undefined) {\n console.debug(\n \"[Reactor] Setting waiting info:\",\n newWaitingInfo,\n \"from\",\n this.waitingInfo\n );\n if (this.waitingInfo !== newWaitingInfo) {\n this.waitingInfo = newWaitingInfo;\n this.emit(\"waitingInfoChanged\", newWaitingInfo);\n }\n }\n /**\n * Set the session expiration time.\n * @param newSessionExpiration The new session expiration time in seconds.\n */\n private setSessionExpiration(newSessionExpiration: number | undefined) {\n console.debug(\n \"[Reactor] Setting session expiration:\",\n newSessionExpiration\n );\n if (this.sessionExpiration !== newSessionExpiration) {\n this.sessionExpiration = newSessionExpiration;\n this.emit(\"sessionExpirationChanged\", newSessionExpiration);\n }\n }\n\n getStatus(): ReactorStatus {\n return this.status;\n }\n\n /**\n * Get the current state including status, error, and waiting info\n */\n getState(): ReactorState {\n return {\n status: this.status,\n waitingInfo: this.waitingInfo,\n lastError: this.lastError,\n };\n }\n\n /**\n * Get waiting information when status is 'waiting'\n */\n getWaitingInfo(): ReactorWaitingInfo | undefined {\n return this.waitingInfo;\n }\n\n /**\n * Get the last error that occurred\n */\n getLastError(): ReactorError | undefined {\n return this.lastError;\n }\n\n /**\n * Create and store an error\n */\n private createError(\n code: string,\n message: string,\n component: \"coordinator\" | \"gpu\" | \"livekit\",\n recoverable: boolean,\n retryAfter?: number\n ) {\n this.lastError = {\n code,\n message,\n timestamp: Date.now(),\n recoverable,\n component,\n retryAfter,\n };\n\n // Emit error event\n this.emit(\"error\", this.lastError);\n }\n}\n","\"use client\";\n\nimport { ReactNode, useContext, useEffect, useRef, useState } from \"react\";\nimport {\n createReactorStore,\n initReactorStore,\n ReactorContext,\n ReactorStore,\n ReactorStoreApi,\n type ReactorInitializationProps,\n} from \"../core/store\";\nimport { useStore } from \"zustand\";\n\n// Provider props\ninterface ReactorProviderProps extends ReactorInitializationProps {\n autoConnect?: boolean;\n children: ReactNode;\n}\n\n// tsx component\nexport function ReactorProvider({\n children,\n autoConnect = true,\n ...props\n}: ReactorProviderProps) {\n // Stable Reactor instance\n const storeRef = useRef<ReactorStoreApi | undefined>(undefined);\n const firstRender = useRef(true);\n // State to trigger re-renders when store changes\n const [_storeVersion, setStoreVersion] = useState(0);\n\n if (storeRef.current === undefined) {\n console.debug(\"[ReactorProvider] Creating new reactor store\");\n // We create the store without autoconnecting, to avoid duplicate connections.\n // We actually connect when the component is mounted, to be on sync with the react component lifecycle.\n storeRef.current = createReactorStore(initReactorStore(props));\n console.debug(\"[ReactorProvider] Reactor store created successfully\");\n }\n\n // Fan out props to individual variables so that the\n // useEffect hook can be optimized by only re-running when the\n // props that actually change.\n const {\n coordinatorUrl,\n modelName,\n jwtToken,\n insecureApiKey,\n directConnection,\n queueing,\n local,\n } = props;\n\n useEffect(() => {\n if (firstRender.current) {\n firstRender.current = false;\n\n // We know as a fact that the store is not undefined at this point\n const current = storeRef.current!;\n if (autoConnect && current.getState().status === \"disconnected\") {\n console.debug(\n \"[ReactorProvider] Starting autoconnect in first render...\"\n );\n current\n .getState()\n .connect()\n .then(() => {\n console.debug(\n \"[ReactorProvider] Autoconnect successful in first render\"\n );\n })\n .catch((error) => {\n console.error(\n \"[ReactorProvider] Failed to autoconnect in first render:\",\n error\n );\n });\n }\n return () => {\n console.debug(\n \"[ReactorProvider] Disconnecting in cleanup for first render\"\n );\n current\n .getState()\n .disconnect()\n .then(() => {\n console.debug(\n \"[ReactorProvider] Disconnect completed successfully in cleanup for first render\"\n );\n })\n .catch((error) => {\n console.error(\n \"[ReactorProvider] Failed to disconnect in cleanup for first render:\",\n error\n );\n });\n };\n }\n\n console.debug(\"[ReactorProvider] Updating reactor store\");\n storeRef.current = createReactorStore(\n initReactorStore({\n coordinatorUrl,\n modelName,\n jwtToken,\n insecureApiKey,\n directConnection,\n queueing,\n local,\n } satisfies ReactorInitializationProps)\n );\n\n // Store current reference to the store in the return\n const current = storeRef.current!;\n\n // Increment version to trigger re-render and propagate new store to Provider\n setStoreVersion((v) => v + 1);\n console.debug(\n \"[ReactorProvider] Reactor store updated successfully, and increased version\"\n );\n\n if (autoConnect && current.getState().status === \"disconnected\") {\n console.debug(\"[ReactorProvider] Starting autoconnect...\");\n current\n .getState()\n .connect()\n .then(() => {\n console.debug(\"[ReactorProvider] Autoconnect successful\");\n })\n .catch((error) => {\n console.error(\"[ReactorProvider] Failed to autoconnect:\", error);\n });\n }\n\n return () => {\n console.debug(\"[ReactorProvider] Disconnecting in cleanup\");\n current\n .getState()\n .disconnect()\n .then(() => {\n console.debug(\n \"[ReactorProvider] Disconnect completed successfully in cleanup\"\n );\n })\n .catch((error) => {\n console.error(\"[ReactorProvider] Failed to disconnect:\", error);\n });\n };\n }, [\n coordinatorUrl,\n modelName,\n jwtToken,\n insecureApiKey,\n directConnection,\n queueing,\n autoConnect,\n local,\n ]);\n\n return (\n <ReactorContext.Provider value={storeRef.current}>\n {children}\n </ReactorContext.Provider>\n );\n}\n\nexport function useReactorStore<T = ReactorStore>(\n selector: (state: ReactorStore) => T\n): T {\n const ctx = useContext(ReactorContext);\n if (!ctx) {\n throw new Error(\"useReactor must be used within a ReactorProvider\");\n }\n\n return useStore(ctx, selector);\n}\n","import { StoreApi } from \"zustand\";\nimport type { ReactorStatus, ReactorWaitingInfo, ReactorError } from \"../types\";\nimport { Reactor, type Options as ReactorOptions } from \"./Reactor\";\nimport { create } from \"zustand/react\";\nimport { createContext } from \"react\";\nimport type { RemoteVideoTrack } from \"livekit-client\";\n\nexport type ReactorStoreApi = ReturnType<typeof createReactorStore>;\n\nexport interface ReactorState {\n status: ReactorStatus;\n videoTrack: RemoteVideoTrack | null;\n //These are the machine FPS. The machine internally reports to the client the rate at which the frames are\n //being generated. This can be useful for the client to calcolate at which rate to run commands.\n fps?: number;\n waitingInfo?: ReactorWaitingInfo;\n lastError?: ReactorError;\n sessionExpiration?: number;\n}\n\nexport interface ReactorActions {\n sendMessage(message: any): Promise<void>;\n connect(): Promise<void>;\n disconnect(): Promise<void>;\n publishVideoStream(stream: MediaStream): Promise<void>;\n unpublishVideoStream(): Promise<void>;\n}\n\n// Internal state not exposed to components\ninterface ReactorInternalState {\n reactor: Reactor;\n}\n\nexport const ReactorContext = createContext<ReactorStoreApi | undefined>(\n undefined\n);\n\nexport type ReactorStore = ReactorState &\n ReactorActions & {\n internal: ReactorInternalState;\n };\n\nexport const defaultInitState: ReactorState = {\n status: \"disconnected\",\n videoTrack: null,\n fps: undefined,\n waitingInfo: undefined,\n lastError: undefined,\n sessionExpiration: undefined,\n};\n\nexport interface ReactorInitializationProps extends ReactorOptions {}\n\nexport const initReactorStore = (\n props: ReactorInitializationProps\n): ReactorState & ReactorInitializationProps => {\n return {\n ...defaultInitState,\n // These are only used for dev initialization, not exposed in the store\n ...props,\n };\n};\n\nexport const createReactorStore = (\n initProps: ReactorInitializationProps,\n publicState: ReactorState = defaultInitState\n): StoreApi<ReactorStore> => {\n console.debug(\"[ReactorStore] Creating store\", {\n coordinatorUrl: initProps.coordinatorUrl,\n initialState: publicState,\n });\n\n return create<ReactorStore>()((set, get) => {\n const reactor = new Reactor(initProps);\n\n console.debug(\"[ReactorStore] Setting up event listeners\");\n\n reactor.on(\"statusChanged\", (newStatus: ReactorStatus) => {\n console.debug(\"[ReactorStore] Status changed\", {\n oldStatus: get().status,\n newStatus,\n });\n set({ status: newStatus });\n });\n\n reactor.on(\"waitingInfoChanged\", (newWaitingInfo: ReactorWaitingInfo | undefined) => {\n console.debug(\"[ReactorStore] Waiting info changed\", {\n oldWaitingInfo: get().waitingInfo,\n newWaitingInfo: newWaitingInfo,\n });\n set({ waitingInfo: newWaitingInfo });\n });\n\n reactor.on(\"sessionExpirationChanged\", (newSessionExpiration: number | undefined) => {\n console.debug(\"[ReactorStore] Session expiration changed\", {\n oldSessionExpiration: get().sessionExpiration,\n newSessionExpiration: newSessionExpiration,\n });\n set({ sessionExpiration: newSessionExpiration });\n });\n\n reactor.on(\"streamChanged\", (videoTrack: RemoteVideoTrack | null) => {\n console.debug(\"[ReactorStore] Stream changed\", {\n hasVideoTrack: !!videoTrack,\n videoTrackKind: videoTrack?.kind,\n videoTrackSid: videoTrack?.sid,\n });\n set({ videoTrack: videoTrack });\n });\n\n reactor.on(\"fps\", (fps: number) => {\n console.debug(\"[ReactorStore] FPS updated\", { fps });\n set({ fps: fps });\n });\n\n reactor.on(\"error\", (error: ReactorError) => {\n console.debug(\"[ReactorStore] Error occurred\", error);\n set({ lastError: error });\n });\n\n return {\n ...publicState,\n internal: { reactor },\n\n // actions\n onMessage: (handler: (message: any) => void) => {\n console.debug(\"[ReactorStore] Registering message handler\");\n\n // Simply register the handler\n get().internal.reactor.on(\"newMessage\", handler);\n\n // Return a cleanup function that can be called to unregister\n return () => {\n console.debug(\"[ReactorStore] Cleaning up message handler\");\n get().internal.reactor.off(\"newMessage\", handler);\n };\n },\n sendMessage: async (mess: any) => {\n console.debug(\"[ReactorStore] Sending message\", { message: mess });\n\n try {\n await get().internal.reactor.sendMessage(mess);\n console.debug(\"[ReactorStore] Message sent successfully\");\n } catch (error) {\n console.error(\"[ReactorStore] Failed to send message:\", error);\n throw error;\n }\n },\n connect: async () => {\n console.debug(\"[ReactorStore] Connect called\");\n\n try {\n await get().internal.reactor.connect();\n console.debug(\"[ReactorStore] Connect completed successfully\");\n } catch (error) {\n console.error(\"[ReactorStore] Connect failed:\", error);\n throw error;\n }\n },\n disconnect: async () => {\n console.debug(\"[ReactorStore] Disconnect called\", {\n currentStatus: get().status,\n });\n\n try {\n await get().internal.reactor.disconnect();\n console.debug(\"[ReactorStore] Disconnect completed successfully\");\n } catch (error) {\n console.error(\"[ReactorStore] Disconnect failed:\", error);\n throw error;\n }\n },\n publishVideoStream: async (stream: MediaStream) => {\n console.debug(\"[ReactorStore] Publishing video stream\");\n\n try {\n await get().internal.reactor.publishVideoStream(stream);\n console.debug(\"[ReactorStore] Video stream published successfully\");\n } catch (error) {\n console.error(\n \"[ReactorStore] Failed to publish video stream:\",\n error\n );\n throw error;\n }\n },\n unpublishVideoStream: async () => {\n console.debug(\"[ReactorStore] Unpublishing video stream\");\n\n try {\n await get().internal.reactor.unpublishVideoStream();\n console.debug(\"[ReactorStore] Video stream unpublished successfully\");\n } catch (error) {\n console.error(\n \"[ReactorStore] Failed to unpublish video stream:\",\n error\n );\n throw error;\n }\n },\n };\n });\n};\n","import { useReactorStore } from \"./ReactorProvider\";\nimport type { ReactorStore } from \"../core/store\";\nimport { useShallow } from \"zustand/shallow\";\nimport { useEffect, useRef } from \"react\";\n\n/**\n * Generic hook for accessing selected parts of the Reactor store.\n *\n * @param selector - A function that selects part of the store state.\n * @returns The selected slice from the store.\n */\nexport function useReactor<T>(selector: (state: ReactorStore) => T): T {\n return useReactorStore(useShallow(selector));\n}\n\n/**\n * Hook for handling message subscriptions with proper React lifecycle management.\n *\n * @param handler - The message handler function\n */\nexport function useReactorMessage(handler: (message: any) => void): void {\n const reactor = useReactor((state) => state.internal.reactor);\n const handlerRef = useRef(handler);\n\n // Update the ref when handler changes\n useEffect(() => {\n handlerRef.current = handler;\n }, [handler]);\n\n useEffect(() => {\n console.debug(\"[useReactorMessage] Setting up message subscription\");\n\n // Create a stable handler that calls the current ref\n const stableHandler = (message: any) => {\n console.debug(\"[useReactorMessage] Message received\", { message });\n handlerRef.current(message);\n };\n\n // Register the handler and get the cleanup function\n reactor.on(\"newMessage\", stableHandler);\n\n console.debug(\"[useReactorMessage] Message handler registered\");\n\n // Return the cleanup function\n return () => {\n console.debug(\"[useReactorMessage] Cleaning up message subscription\");\n reactor.off(\"newMessage\", stableHandler);\n };\n }, [reactor]);\n}\n","\"use client\";\n\nimport { useReactor } from \"./hooks\";\nimport { useEffect, useRef } from \"react\";\nimport React from \"react\";\n\nexport interface ReactorViewProps {\n width?: number;\n height?: number;\n className?: string;\n style?: React.CSSProperties;\n videoObjectFit?: NonNullable<\n React.VideoHTMLAttributes<HTMLVideoElement>[\"style\"]\n >[\"objectFit\"];\n}\n\nexport function ReactorView({\n width,\n height,\n className,\n style,\n videoObjectFit = \"contain\",\n}: ReactorViewProps) {\n const { videoTrack, status } = useReactor((state) => ({\n videoTrack: state.videoTrack,\n status: state.status,\n }));\n\n const videoRef = useRef<HTMLVideoElement>(null);\n\n useEffect(() => {\n console.debug(\"[ReactorView] Video track effect triggered\", {\n hasVideoElement: !!videoRef.current,\n hasVideoTrack: !!videoTrack,\n videoTrackKind: videoTrack?.kind,\n });\n\n if (videoRef.current && videoTrack) {\n console.debug(\"[ReactorView] Attaching video track to element\");\n try {\n // Attach the LiveKit track to the video element\n videoTrack.attach(videoRef.current);\n console.debug(\"[ReactorView] Video track attached successfully\");\n } catch (error) {\n console.error(\"[ReactorView] Failed to attach video track:\", error);\n }\n\n // Cleanup: detach when track changes or component unmounts\n return () => {\n console.debug(\"[ReactorView] Detaching video track from element\");\n if (videoRef.current) {\n try {\n videoTrack.detach(videoRef.current);\n console.debug(\"[ReactorView] Video track detached successfully\");\n } catch (error) {\n console.error(\"[ReactorView] Failed to detach video track:\", error);\n }\n }\n };\n } else {\n console.debug(\"[ReactorView] No video track or element to attach\");\n }\n }, [videoTrack]);\n\n const showPlaceholder = !videoTrack;\n\n return (\n <div\n style={{\n position: \"relative\",\n background: \"#000\",\n ...(width && { width }),\n ...(height && { height }),\n ...style,\n }}\n className={className}\n >\n <video\n ref={videoRef}\n style={{\n width: \"100%\",\n height: \"100%\",\n objectFit: videoObjectFit,\n display: showPlaceholder ? \"none\" : \"block\",\n }}\n muted\n playsInline\n />\n {showPlaceholder && (\n <div\n style={{\n position: \"absolute\",\n top: 0,\n left: 0,\n width: \"100%\",\n height: \"100%\",\n color: \"#fff\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n fontSize: \"16px\",\n fontFamily: \"monospace\",\n textAlign: \"center\",\n padding: \"20px\",\n boxSizing: \"border-box\",\n }}\n >\n {status}\n </div>\n )}\n </div>\n );\n}\n","\"use client\";\n\nimport { useReactor } from \"./hooks\";\nimport { useEffect, useRef, useState } from \"react\";\nimport React from \"react\";\n\ninterface Props {\n className?: string;\n style?: React.CSSProperties;\n videoConstraints?: MediaTrackConstraints;\n showWebcam?: boolean;\n videoObjectFit?: NonNullable<\n React.VideoHTMLAttributes<HTMLVideoElement>[\"style\"]\n >[\"objectFit\"];\n}\n\nexport function WebcamStream({\n className,\n style,\n videoConstraints = {\n width: { ideal: 1280 },\n height: { ideal: 720 },\n },\n showWebcam = true,\n videoObjectFit = \"contain\",\n}: Props) {\n const [stream, setStream] = useState<MediaStream | null>(null);\n const [isPublishing, setIsPublishing] = useState(false);\n const [permissionDenied, setPermissionDenied] = useState(false);\n\n const { status, publishVideoStream, unpublishVideoStream, reactor } =\n useReactor((state) => ({\n status: state.status,\n publishVideoStream: state.publishVideoStream,\n unpublishVideoStream: state.unpublishVideoStream,\n reactor: state.internal.reactor,\n }));\n\n const videoRef = useRef<HTMLVideoElement>(null);\n\n // Start webcam\n const startWebcam = async () => {\n console.debug(\"[WebcamPublisher] Starting webcam\");\n\n try {\n const mediaStream = await navigator.mediaDevices.getUserMedia({\n video: videoConstraints,\n audio: false,\n });\n\n console.debug(\"[WebcamPublisher] Webcam started successfully\");\n setStream(mediaStream);\n setPermissionDenied(false);\n } catch (err) {\n console.error(\"[WebcamPublisher] Failed to start webcam:\", err);\n\n // Check if the error is a permission denial\n if (\n err instanceof DOMException &&\n (err.name === \"NotAllowedError\" || err.name === \"PermissionDeniedError\")\n ) {\n console.debug(\"[WebcamPublisher] Camera permission denied\");\n setPermissionDenied(true);\n }\n }\n };\n\n // Stop webcam\n const stopWebcam = async () => {\n console.debug(\"[WebcamPublisher] Stopping webcam\");\n\n // Unpublish if currently publishing\n try {\n await unpublishVideoStream();\n console.debug(\"[WebcamPublisher] Unpublished before stopping\");\n } catch (err) {\n console.error(\"[WebcamPublisher] Error unpublishing before stop:\", err);\n }\n\n setIsPublishing(false);\n\n // Stop all tracks\n stream?.getTracks().forEach((track) => {\n track.stop();\n console.debug(\"[WebcamPublisher] Stopped track:\", track.kind);\n });\n setStream(null);\n\n console.debug(\"[WebcamPublisher] Webcam stopped\");\n };\n\n // Attach stream to video element\n useEffect(() => {\n console.debug(\"[WebcamPublisher] Stream effect triggered\", {\n hasVideoElement: !!videoRef.current,\n hasStream: !!stream,\n });\n\n if (!videoRef.current) {\n return;\n }\n\n if (stream) {\n console.debug(\"[WebcamPublisher] Attaching stream to video element\");\n videoRef.current.srcObject = stream;\n console.debug(\"[WebcamPublisher] Stream attached successfully\");\n } else {\n console.debug(\"[WebcamPublisher] Clearing video element\");\n videoRef.current.srcObject = null;\n }\n }, [stream]);\n\n // Auto-publish when reactor is ready and webcam is active\n useEffect(() => {\n if (!stream) {\n return;\n }\n\n if (status === \"ready\" && !isPublishing) {\n console.debug(\n \"[WebcamPublisher] Reactor ready, auto-publishing webcam stream\"\n );\n publishVideoStream(stream)\n .then(() => {\n console.debug(\"[WebcamPublisher] Auto-publish successful\");\n setIsPublishing(true);\n })\n .catch((err) => {\n console.error(\"[WebcamPublisher] Auto-publish failed:\", err);\n });\n } else if (status !== \"ready\" && isPublishing) {\n console.debug(\"[WebcamPublisher] Reactor not ready, auto-unpublishing\");\n unpublishVideoStream()\n .then(() => {\n console.debug(\"[WebcamPublisher] Auto-unpublish successful\");\n setIsPublishing(false);\n })\n .catch((err) => {\n console.error(\"[WebcamPublisher] Auto-unpublish failed:\", err);\n });\n }\n }, [status, stream, isPublishing, publishVideoStream, unpublishVideoStream]);\n\n // Listen for error events from Reactor\n useEffect(() => {\n const handleError = (error: any) => {\n console.debug(\"[WebcamPublisher] Received error event:\", error);\n\n // Handle video publish failures by resetting state\n if (error.code === \"VIDEO_PUBLISH_FAILED\") {\n console.debug(\n \"[WebcamPublisher] Video publish failed, resetting isPublishing state\"\n );\n setIsPublishing(false);\n }\n };\n\n reactor.on(\"error\", handleError);\n\n return () => {\n reactor.off(\"error\", handleError);\n };\n }, [reactor]);\n\n // Reset publishing state when status changes away from ready\n useEffect(() => {\n if (status !== \"ready\") {\n console.debug(\n \"[WebcamPublisher] Status changed to\",\n status,\n \"- resetting isPublishing state\"\n );\n setIsPublishing(false);\n }\n }, [status, isPublishing]);\n\n // Auto-start webcam on mount and cleanup on unmount\n useEffect(() => {\n console.debug(\"[WebcamPublisher] Auto-starting webcam\");\n startWebcam();\n\n return () => {\n console.debug(\"[WebcamPublisher] Cleanup on unmount\");\n stopWebcam();\n };\n }, []); // eslint-disable-line react-hooks/exhaustive-deps\n\n const showPlaceholder = !stream;\n\n return (\n <div\n style={{\n display: showWebcam ? \"block\" : \"none\",\n position: \"relative\",\n background: \"#000\",\n ...style,\n }}\n className={className}\n >\n <video\n ref={videoRef}\n style={{\n width: \"100%\",\n height: \"100%\",\n objectFit: videoObjectFit,\n display: showPlaceholder ? \"none\" : \"block\",\n }}\n muted\n playsInline\n autoPlay\n />\n {showPlaceholder && (\n <div\n style={{\n position: \"absolute\",\n top: 0,\n left: 0,\n width: \"100%\",\n height: \"100%\",\n color: \"#fff\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n fontSize: \"16px\",\n fontFamily: \"monospace\",\n textAlign: \"center\",\n padding: \"20px\",\n boxSizing: \"border-box\",\n flexDirection: \"column\",\n gap: \"12px\",\n }}\n >\n {permissionDenied ? (\n <div style={{ fontSize: \"12px\", fontFamily: \"monospace\" }}>\n Camera access denied.\n <br />\n Please allow access in your browser settings.\n </div>\n ) : (\n <div style={{ fontSize: \"12px\", fontFamily: \"monospace\" }}>\n Starting camera...\n </div>\n )}\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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","names":["import_zod","_a","import_zod","OptionsSchema","import_react","import_react","current","import_react","import_react","import_jsx_runtime","import_react","import_jsx_runtime"]}
package/dist/index.mjs CHANGED
@@ -90,11 +90,19 @@ var WaitingInfoMessageSchema = z.object({
90
90
  type: z.literal("waiting-info"),
91
91
  data: WaitingInfoDataSchema
92
92
  });
93
+ var SessionExpirationDataSchema = z.object({
94
+ expire: z.number()
95
+ });
96
+ var SessionExpirationMessageSchema = z.object({
97
+ type: z.literal("session-expiration"),
98
+ data: SessionExpirationDataSchema
99
+ });
93
100
  var CoordinatorMessageSchema = z.discriminatedUnion("type", [
94
101
  WelcomeMessageSchema,
95
102
  GPUMachineAssignmentMessageSchema,
96
103
  EchoMessageSchema,
97
- WaitingInfoMessageSchema
104
+ WaitingInfoMessageSchema,
105
+ SessionExpirationMessageSchema
98
106
  ]);
99
107
  var GPUMachineSendMessageSchema = z.discriminatedUnion("type", [
100
108
  ApplicationMessageSchema
@@ -761,6 +769,12 @@ var Reactor = class {
761
769
  this.setWaitingInfo(__spreadValues(__spreadValues({}, this.waitingInfo), waitingData));
762
770
  }
763
771
  );
772
+ this.coordinatorClient.on(
773
+ "session-expiration",
774
+ (sessionExpirationData) => {
775
+ this.setSessionExpiration(sessionExpirationData.expire);
776
+ }
777
+ );
764
778
  this.coordinatorClient.on(
765
779
  "statusChanged",
766
780
  (newStatus) => {
@@ -826,7 +840,8 @@ var Reactor = class {
826
840
  this.machineClient = void 0;
827
841
  }
828
842
  this.setStatus("disconnected");
829
- this.waitingInfo = void 0;
843
+ this.setSessionExpiration(void 0);
844
+ this.setWaitingInfo(void 0);
830
845
  });
831
846
  }
832
847
  setStatus(newStatus) {
@@ -848,6 +863,20 @@ var Reactor = class {
848
863
  this.emit("waitingInfoChanged", newWaitingInfo);
849
864
  }
850
865
  }
866
+ /**
867
+ * Set the session expiration time.
868
+ * @param newSessionExpiration The new session expiration time in seconds.
869
+ */
870
+ setSessionExpiration(newSessionExpiration) {
871
+ console.debug(
872
+ "[Reactor] Setting session expiration:",
873
+ newSessionExpiration
874
+ );
875
+ if (this.sessionExpiration !== newSessionExpiration) {
876
+ this.sessionExpiration = newSessionExpiration;
877
+ this.emit("sessionExpirationChanged", newSessionExpiration);
878
+ }
879
+ }
851
880
  getStatus() {
852
881
  return this.status;
853
882
  }
@@ -903,7 +932,8 @@ var defaultInitState = {
903
932
  videoTrack: null,
904
933
  fps: void 0,
905
934
  waitingInfo: void 0,
906
- lastError: void 0
935
+ lastError: void 0,
936
+ sessionExpiration: void 0
907
937
  };
908
938
  var initReactorStore = (props) => {
909
939
  return __spreadValues(__spreadValues({}, defaultInitState), props);
@@ -930,6 +960,13 @@ var createReactorStore = (initProps, publicState = defaultInitState) => {
930
960
  });
931
961
  set({ waitingInfo: newWaitingInfo });
932
962
  });
963
+ reactor.on("sessionExpirationChanged", (newSessionExpiration) => {
964
+ console.debug("[ReactorStore] Session expiration changed", {
965
+ oldSessionExpiration: get().sessionExpiration,
966
+ newSessionExpiration
967
+ });
968
+ set({ sessionExpiration: newSessionExpiration });
969
+ });
933
970
  reactor.on("streamChanged", (videoTrack) => {
934
971
  console.debug("[ReactorStore] Stream changed", {
935
972
  hasVideoTrack: !!videoTrack,
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/core/types.ts","../src/core/CoordinatorClient.ts","../src/core/GPUMachineClient.ts","../src/core/Reactor.ts","../src/react/ReactorProvider.tsx","../src/core/store.ts","../src/react/hooks.ts","../src/react/ReactorView.tsx","../src/react/WebcamStream.tsx"],"sourcesContent":["/**\n * Internal types for the Reactor SDK.\n */\n\nimport { z } from \"zod\";\n\n// Base message schemas corresponding to Python Pydantic models\n\nexport const ApplicationMessageSchema = z.object({\n type: z.literal(\"application\"),\n data: z.any(), // Can be any JSON-serializable data\n});\n\n// Internal message that notifies the client of the current push rate of the machine\nexport const FPSMessageSchema = z.object({\n type: z.literal(\"fps\"),\n data: z.number(),\n});\n\nexport const GPUMachineReceiveMessageSchema = z.discriminatedUnion(\"type\", [\n ApplicationMessageSchema,\n FPSMessageSchema,\n]);\n\nexport const WelcomeMessageSchema = z.object({\n type: z.literal(\"welcome\"),\n data: z.record(z.string(), z.any()),\n});\n\nexport const GPUMachineAssignmentDataSchema = z.object({\n livekitWsUrl: z.string(),\n livekitJwtToken: z.string(),\n});\n\nexport const GPUMachineAssignmentMessageSchema = z.object({\n type: z.literal(\"gpu-machine-assigned\"),\n data: GPUMachineAssignmentDataSchema,\n});\n\nexport const EchoMessageSchema = z.object({\n type: z.literal(\"echo\"),\n data: z.record(z.string(), z.any()),\n});\n\nexport const WaitingInfoDataSchema = z.object({\n position: z.number().optional(),\n estimatedWaitTime: z.number().optional(),\n averageWaitTime: z.number().optional(),\n});\n\nexport const WaitingInfoMessageSchema = z.object({\n type: z.literal(\"waiting-info\"),\n data: WaitingInfoDataSchema,\n});\n\nexport const CoordinatorMessageSchema = z.discriminatedUnion(\"type\", [\n WelcomeMessageSchema,\n GPUMachineAssignmentMessageSchema,\n EchoMessageSchema,\n WaitingInfoMessageSchema,\n]);\n\nexport const GPUMachineSendMessageSchema = z.discriminatedUnion(\"type\", [\n ApplicationMessageSchema,\n]);\n\nexport const SessionSetupMessageSchema = z.object({\n type: z.literal(\"sessionSetup\"),\n data: z.object({\n modelName: z.string(),\n modelVersion: z.string().default(\"latest\"),\n }),\n});\n\n// TypeScript types derived from schemas\nexport type ApplicationMessage = z.infer<typeof ApplicationMessageSchema>;\nexport type GPUMachineReceiveMessageSchema = z.infer<\n typeof GPUMachineReceiveMessageSchema\n>;\nexport type WelcomeMessage = z.infer<typeof WelcomeMessageSchema>;\nexport type GPUMachineAssignmentData = z.infer<\n typeof GPUMachineAssignmentDataSchema\n>;\nexport type GPUMachineAssignmentMessage = z.infer<\n typeof GPUMachineAssignmentMessageSchema\n>;\nexport type EchoMessage = z.infer<typeof EchoMessageSchema>;\nexport type WaitingInfoData = z.infer<typeof WaitingInfoDataSchema>;\nexport type WaitingInfoMessage = z.infer<typeof WaitingInfoMessageSchema>;\nexport type CoordinatorMessage = z.infer<typeof CoordinatorMessageSchema>;\nexport type GPUMachineSendMessage = z.infer<typeof GPUMachineSendMessageSchema>;\nexport type SessionSetupMessage = z.infer<typeof SessionSetupMessageSchema>;\n\n// Internal connection status for individual components\nexport type InternalConnectionStatus =\n | \"disconnected\"\n | \"connecting\"\n | \"connected\"\n | \"error\";\n","/**\n * The CoordinatorClient is responsible for handling the connection to the coordinator.\n */\n\nimport {\n type CoordinatorMessage,\n CoordinatorMessageSchema,\n type SessionSetupMessage,\n} from \"./types\";\nimport { z } from \"zod\";\n\ntype EventHandler = (...args: any[]) => void;\n\nconst OptionsSchema = z\n .object({\n wsUrl: z.string().nonempty(),\n jwtToken: z.string().optional(),\n insecureApiKey: z.string().optional(),\n modelName: z.string(),\n modelVersion: z.string().default(\"latest\"),\n queueing: z.boolean().default(false),\n })\n .refine((data) => data.jwtToken || data.insecureApiKey, {\n message: \"At least one of jwtToken or insecureApiKey must be provided.\",\n });\n\ntype Options = z.input<typeof OptionsSchema>;\n\n// Infer message types from the schema - single source of truth\nexport type CoordinatorEvent = \"statusChanged\" | CoordinatorMessage[\"type\"];\n\nexport class CoordinatorClient {\n private websocket?: WebSocket;\n private wsUrl: string;\n private jwtToken?: string;\n private insecureApiKey?: string;\n private eventListeners: Map<CoordinatorEvent, Set<EventHandler>> = new Map();\n private modelName: string;\n private modelVersion: string;\n private queueing: boolean;\n\n constructor(options: Options) {\n const validatedOptions = OptionsSchema.parse(options);\n this.wsUrl = validatedOptions.wsUrl;\n this.jwtToken = validatedOptions.jwtToken;\n this.insecureApiKey = validatedOptions.insecureApiKey;\n this.modelName = validatedOptions.modelName;\n this.modelVersion = validatedOptions.modelVersion;\n this.queueing = validatedOptions.queueing;\n }\n\n // Event Emitter API\n on(event: CoordinatorEvent, handler: EventHandler) {\n if (!this.eventListeners.has(event)) {\n this.eventListeners.set(event, new Set());\n }\n this.eventListeners.get(event)!.add(handler);\n }\n\n off(event: CoordinatorEvent, handler: EventHandler) {\n this.eventListeners.get(event)?.delete(handler);\n }\n\n emit(event: CoordinatorEvent, ...args: any[]) {\n this.eventListeners.get(event)?.forEach((handler) => handler(...args));\n }\n\n sendMessage(message: any) {\n try {\n const messageStr =\n typeof message === \"string\" ? message : JSON.stringify(message);\n this.websocket?.send(messageStr);\n } catch (error) {\n console.error(\"[CoordinatorClient] Failed to send message:\", error);\n this.emit(\"statusChanged\", \"error\");\n }\n }\n\n async connect(): Promise<void> {\n // Build WebSocket URL with authentication query parameters\n const url = new URL(this.wsUrl);\n if (this.jwtToken) {\n url.searchParams.set(\"jwt_token\", this.jwtToken);\n } else if (this.insecureApiKey) {\n url.searchParams.set(\"api_key\", this.insecureApiKey);\n }\n\n // Add queued parameter only if queueing is true\n if (this.queueing) {\n url.searchParams.set(\"queueing\", \"true\");\n }\n\n console.debug(\"[CoordinatorClient] Connecting to\", url.toString());\n this.websocket = new WebSocket(url.toString());\n\n this.websocket.onopen = () => {\n console.debug(\"[CoordinatorClient] WebSocket opened\");\n this.emit(\"statusChanged\", \"connected\");\n };\n\n this.websocket.onmessage = (event) => {\n try {\n let parsedData: string | object;\n if (typeof event.data === \"string\") {\n parsedData = JSON.parse(event.data);\n } else {\n parsedData = event.data;\n }\n console.debug(\n \"[CoordinatorClient] Received message from coordinator:\",\n parsedData\n );\n const validatedData = CoordinatorMessageSchema.parse(parsedData);\n this.emit(validatedData.type, validatedData.data);\n } catch (error) {\n console.error(\n \"[CoordinatorClient] Failed to parse WebSocket message from coordinator:\",\n error,\n \"message\",\n event.data\n );\n this.emit(\"statusChanged\", \"error\");\n }\n };\n\n this.websocket.onclose = (event) => {\n console.debug(\"[CoordinatorClient] WebSocket closed\", event);\n this.websocket = undefined;\n this.emit(\"statusChanged\", \"disconnected\");\n };\n\n this.websocket.onerror = (error) => {\n console.error(\"[CoordinatorClient] WebSocket error:\", error);\n this.websocket = undefined;\n this.emit(\"statusChanged\", \"error\");\n };\n\n await new Promise<void>((resolve, reject) => {\n const onOpen = () => {\n this.websocket?.removeEventListener(\"error\", onError);\n resolve();\n };\n const onError = (error: Event) => {\n this.websocket?.removeEventListener(\"open\", onOpen);\n reject(error);\n };\n this.websocket?.addEventListener(\"open\", onOpen);\n this.websocket?.addEventListener(\"error\", onError);\n });\n\n console.log(\"[CoordinatorClient] WebSocket connected\");\n\n this.sendMessage({\n type: \"sessionSetup\",\n data: {\n modelName: this.modelName,\n modelVersion: this.modelVersion,\n },\n } satisfies SessionSetupMessage);\n\n console.debug(\"[CoordinatorClient] Setup session message sent\");\n }\n\n /**\n * Closes the WebSocket connection if it exists.\n * This will trigger the onclose event handler.\n */\n disconnect() {\n if (this.websocket) {\n console.debug(\"[CoordinatorClient] Closing WebSocket connection\");\n this.websocket.close();\n this.websocket = undefined;\n }\n }\n}\n","/**\n * The GPUMachineClient is responsible for handling the direct connection to the machine instance\n * after the coordinator has assigned a machine.\n */\n\nimport {\n type GPUMachineSendMessage,\n GPUMachineReceiveMessageSchema,\n} from \"./types\";\nimport {\n Room,\n RoomEvent,\n Track,\n RemoteVideoTrack,\n LocalVideoTrack,\n LocalAudioTrack,\n} from \"livekit-client\";\n\ntype EventHandler = (...args: any[]) => void;\nexport type GPUMachineEvent =\n | GPUMachineReceiveMessageSchema[\"type\"]\n | \"statusChanged\"\n | \"streamChanged\";\n\nexport class GPUMachineClient {\n private eventListeners: Map<GPUMachineEvent, Set<EventHandler>> = new Map();\n private roomInstance: Room | undefined;\n private machineFPS: number | undefined;\n private token: string;\n private videoStream: MediaStream | undefined;\n private liveKitUrl: string;\n private publishedVideoTrack: LocalVideoTrack | undefined;\n private publishedAudioTrack: LocalAudioTrack | undefined;\n\n constructor(token: string, liveKitUrl: string) {\n this.token = token;\n this.liveKitUrl = liveKitUrl;\n }\n\n // Event Emitter API\n on(event: GPUMachineEvent, handler: EventHandler) {\n if (!this.eventListeners.has(event)) {\n this.eventListeners.set(event, new Set());\n }\n this.eventListeners.get(event)!.add(handler);\n }\n\n off(event: GPUMachineEvent, handler: EventHandler) {\n this.eventListeners.get(event)?.delete(handler);\n }\n\n emit(event: GPUMachineEvent, ...args: any[]) {\n this.eventListeners.get(event)?.forEach((handler) => handler(...args));\n }\n\n async sendMessage(message: GPUMachineSendMessage): Promise<void> {\n try {\n if (this.roomInstance) {\n const messageStr = JSON.stringify(message);\n // Send message via LiveKit text channel\n await this.roomInstance.localParticipant.sendText(messageStr, {\n topic: \"application\",\n });\n } else {\n console.warn(\n \"[GPUMachineClient] Cannot send message - not connected to room\"\n );\n }\n } catch (error) {\n console.error(\"[GPUMachineClient] Failed to send message:\", error);\n this.emit(\"statusChanged\", \"error\");\n }\n }\n\n async connect(): Promise<void> {\n this.roomInstance = new Room({\n adaptiveStream: true,\n dynacast: true,\n });\n\n this.roomInstance.on(RoomEvent.Connected, () => {\n console.debug(\"[GPUMachineClient] Connected to room\");\n this.emit(\"statusChanged\", \"connected\");\n });\n\n this.roomInstance.on(RoomEvent.Disconnected, () => {\n console.debug(\"[GPUMachineClient] Disconnected from room\");\n this.emit(\"statusChanged\", \"disconnected\");\n });\n\n // Handle video track subscriptions from GPU machine\n this.roomInstance.on(\n RoomEvent.TrackSubscribed,\n (track, _publication, participant) => {\n console.debug(\n \"[GPUMachineClient] Track subscribed:\",\n track.kind,\n participant.identity\n );\n\n if (track.kind === Track.Kind.Video) {\n const videoTrack = track as RemoteVideoTrack;\n this.emit(\"streamChanged\", videoTrack);\n }\n }\n );\n\n this.roomInstance.on(\n RoomEvent.TrackUnsubscribed,\n (track, _publication, participant) => {\n console.debug(\n \"[GPUMachineClient] Track unsubscribed:\",\n track.kind,\n participant.identity\n );\n\n if (track.kind === Track.Kind.Video) {\n this.emit(\"streamChanged\", null);\n }\n }\n );\n\n this.roomInstance.registerTextStreamHandler(\n \"application\",\n async (reader, participant) => {\n const text = await reader.readAll();\n console.log(\"[GPUMachineClient] Received message:\", text);\n try {\n const parsedData = JSON.parse(text);\n\n const validatedMessage =\n GPUMachineReceiveMessageSchema.parse(parsedData);\n if (validatedMessage.type === \"fps\") {\n this.machineFPS = validatedMessage.data;\n }\n\n this.emit(validatedMessage.type, validatedMessage.data);\n } catch (error) {\n console.error(\n \"[GPUMachineClient] Failed to parse/validate message:\",\n error\n );\n this.emit(\"statusChanged\", \"error\");\n }\n }\n );\n\n await this.roomInstance.connect(this.liveKitUrl, this.token);\n\n console.log(\"[GPUMachineClient] Room connected\");\n }\n\n /**\n * Closes the LiveKit connection if it exists.\n * This will trigger the onclose event handler.\n */\n async disconnect() {\n // Unpublish any published tracks before disconnecting\n if (this.publishedVideoTrack) {\n await this.unpublishVideoTrack();\n }\n if (this.publishedAudioTrack) {\n await this.unpublishAudioTrack();\n }\n\n if (this.roomInstance) {\n console.debug(\"[GPUMachineClient] Closing LiveKit connection\");\n await this.roomInstance.disconnect();\n this.roomInstance = undefined;\n }\n this.machineFPS = undefined;\n }\n\n /**\n * Returns the current fps rate of the machine.\n * @returns The current fps rate of the machine.\n */\n getFPS(): number | undefined {\n return this.machineFPS;\n }\n\n /**\n * Returns the current video stream from the GPU machine.\n * @returns The current video stream or undefined if not available.\n */\n getVideoStream(): MediaStream | undefined {\n return this.videoStream;\n }\n\n /**\n * Publishes a video track from the provided MediaStream to the LiveKit room.\n * Only one video track can be published at a time. If a video track is already\n * published, it will be unpublished first.\n *\n * @param mediaStream The MediaStream containing the video track to publish\n * @throws Error if no video track is found in the MediaStream or room is not connected\n */\n async publishVideoTrack(mediaStream: MediaStream): Promise<void> {\n if (!this.roomInstance) {\n throw new Error(\n \"[GPUMachineClient] Cannot publish track - not connected to room\"\n );\n }\n\n const videoTracks = mediaStream.getVideoTracks();\n if (videoTracks.length === 0) {\n throw new Error(\"[GPUMachineClient] No video track found in MediaStream\");\n }\n\n // Unpublish existing video track if any\n if (this.publishedVideoTrack) {\n await this.unpublishVideoTrack();\n }\n\n try {\n const videoTrack = videoTracks[0];\n const localVideoTrack =\n await this.roomInstance.localParticipant.publishTrack(videoTrack, {\n name: \"client-video\",\n source: Track.Source.Camera,\n });\n\n this.publishedVideoTrack = localVideoTrack.track as LocalVideoTrack;\n console.debug(\"[GPUMachineClient] Video track published successfully\");\n } catch (error) {\n console.error(\"[GPUMachineClient] Failed to publish video track:\", error);\n throw error;\n }\n }\n\n /**\n * Unpublishes the currently published video track.\n * Note: We pass false to unpublishTrack to prevent LiveKit from stopping\n * the source MediaStreamTrack, as it's owned by the component that created it.\n */\n async unpublishVideoTrack(): Promise<void> {\n if (!this.roomInstance || !this.publishedVideoTrack) {\n return;\n }\n\n const publishedVideoTrack = this.publishedVideoTrack;\n this.publishedVideoTrack = undefined;\n\n try {\n await this.roomInstance.localParticipant.unpublishTrack(\n publishedVideoTrack,\n false // Don't stop the source track - it's managed externally\n );\n console.debug(\"[GPUMachineClient] Video track unpublished successfully\");\n } catch (error) {\n console.error(\n \"[GPUMachineClient] Failed to unpublish video track:\",\n error\n );\n throw error;\n }\n }\n\n /**\n * Publishes an audio track from the provided MediaStream to the LiveKit room.\n * This is an internal method. Only one audio track can be published at a time.\n *\n * @param mediaStream The MediaStream containing the audio track to publish\n * @private\n */\n private async publishAudioTrack(mediaStream: MediaStream): Promise<void> {\n if (!this.roomInstance) {\n throw new Error(\n \"[GPUMachineClient] Cannot publish track - not connected to room\"\n );\n }\n\n const audioTracks = mediaStream.getAudioTracks();\n if (audioTracks.length === 0) {\n throw new Error(\"[GPUMachineClient] No audio track found in MediaStream\");\n }\n\n // Unpublish existing audio track if any\n if (this.publishedAudioTrack) {\n await this.unpublishAudioTrack();\n }\n\n try {\n const audioTrack = audioTracks[0];\n const localAudioTrack =\n await this.roomInstance.localParticipant.publishTrack(audioTrack, {\n name: \"client-audio\",\n source: Track.Source.Microphone,\n });\n\n this.publishedAudioTrack = localAudioTrack.track as LocalAudioTrack;\n console.debug(\"[GPUMachineClient] Audio track published successfully\");\n } catch (error) {\n console.error(\"[GPUMachineClient] Failed to publish audio track:\", error);\n throw error;\n }\n }\n\n /**\n * Unpublishes the currently published audio track.\n * Note: We pass false to unpublishTrack to prevent LiveKit from stopping\n * the source MediaStreamTrack, as it's owned by the component that created it.\n * @private\n */\n private async unpublishAudioTrack(): Promise<void> {\n if (!this.roomInstance || !this.publishedAudioTrack) {\n return;\n }\n\n const publishedAudioTrack = this.publishedAudioTrack;\n this.publishedAudioTrack = undefined;\n\n try {\n await this.roomInstance.localParticipant.unpublishTrack(\n publishedAudioTrack,\n false // Don't stop the source track - it's managed externally\n );\n console.debug(\"[GPUMachineClient] Audio track unpublished successfully\");\n } catch (error) {\n console.error(\n \"[GPUMachineClient] Failed to unpublish audio track:\",\n error\n );\n throw error;\n }\n }\n}\n","import type {\n ApplicationMessage,\n InternalConnectionStatus,\n GPUMachineAssignmentData,\n} from \"./types\";\nimport type {\n ReactorEvent,\n ReactorStatus,\n ReactorState,\n ReactorError,\n ReactorWaitingInfo,\n} from \"../types\";\nimport { CoordinatorClient } from \"./CoordinatorClient\";\nimport { GPUMachineClient } from \"./GPUMachineClient\";\nimport { z } from \"zod\";\n\nconst LOCAL_COORDINATOR_URL = \"ws://localhost:8080/ws\";\nconst LOCAL_INSECURE_API_KEY = \"1234\";\nconst PROD_COORDINATOR_URL = \"wss://api.reactor.inc/ws\";\n\nconst OptionsSchema = z\n .object({\n directConnection: z\n .object({\n livekitJwtToken: z.string(),\n livekitWsUrl: z.string(),\n })\n .optional(),\n insecureApiKey: z.string().optional(),\n jwtToken: z.string().optional(),\n coordinatorUrl: z.string().default(PROD_COORDINATOR_URL),\n modelName: z.string(),\n queueing: z.boolean().default(false),\n local: z.boolean().default(false),\n })\n .refine(\n (data) =>\n data.directConnection ||\n data.insecureApiKey ||\n data.jwtToken ||\n data.local,\n {\n message:\n \"At least one of directConnection, insecureApiKey, or jwtToken or local must be provided.\",\n }\n );\nexport type Options = z.input<typeof OptionsSchema>;\n\ntype EventHandler = (...args: any[]) => void;\n\nexport class Reactor {\n private coordinatorClient: CoordinatorClient | undefined; //client for the coordinator\n private machineClient: GPUMachineClient | undefined; //client for the machine instance\n private status: ReactorStatus = \"disconnected\";\n private coordinatorUrl: string;\n private lastError?: ReactorError;\n private waitingInfo?: ReactorWaitingInfo;\n private jwtToken?: string;\n private insecureApiKey?: string;\n private directConnection?: {\n livekitJwtToken: string;\n livekitWsUrl: string;\n };\n private modelName: string;\n private modelVersion: string;\n private queueing: boolean;\n\n constructor(options: Options) {\n const validatedOptions = OptionsSchema.parse(options);\n this.coordinatorUrl = validatedOptions.coordinatorUrl;\n this.jwtToken = validatedOptions.jwtToken;\n this.insecureApiKey = validatedOptions.insecureApiKey;\n this.directConnection = validatedOptions.directConnection;\n this.modelName = validatedOptions.modelName;\n this.queueing = validatedOptions.queueing;\n // TODO: Use the model version from the options once we have a way to handle multiple versions\n this.modelVersion = \"1.0.0\";\n if (validatedOptions.local) {\n this.coordinatorUrl = LOCAL_COORDINATOR_URL;\n this.insecureApiKey = LOCAL_INSECURE_API_KEY;\n }\n }\n\n // Generic event map\n private eventListeners: Map<ReactorEvent, Set<EventHandler>> = new Map();\n\n // Event Emitter API\n on(event: ReactorEvent, handler: EventHandler) {\n if (!this.eventListeners.has(event)) {\n this.eventListeners.set(event, new Set());\n }\n this.eventListeners.get(event)!.add(handler);\n }\n\n off(event: ReactorEvent, handler: EventHandler) {\n this.eventListeners.get(event)?.delete(handler);\n }\n\n emit(event: ReactorEvent, ...args: any[]) {\n this.eventListeners.get(event)?.forEach((handler) => handler(...args));\n }\n\n /**\n * Public method to send a message to the machine.\n * Automatically wraps the message in an application message.\n * @param message The message to send to the machine.\n * @throws Error if not in ready state\n */\n async sendMessage(message: any): Promise<void> {\n // Synchronous validation - throw immediately\n if (process.env.NODE_ENV !== \"development\" && this.status !== \"ready\") {\n const errorMessage = `Cannot send message, status is ${this.status}`;\n console.error(\"[Reactor] Not ready, cannot send message\");\n throw new Error(errorMessage);\n }\n\n try {\n // Automatically wrap the user-message in an application message.\n const applicationMessage: ApplicationMessage = {\n type: \"application\",\n data: message,\n };\n await this.machineClient?.sendMessage(applicationMessage);\n } catch (error) {\n // Async operational error - emit event only\n console.error(\"[Reactor] Failed to send message:\", error);\n this.createError(\n \"MESSAGE_SEND_FAILED\",\n `Failed to send message: ${error}`,\n \"gpu\",\n true\n );\n // Don't re-throw - let the error event handle it\n }\n }\n\n /**\n * Public method to publish a video stream to the machine.\n * @param videoStream The video stream to send to the machine.\n */\n async publishVideoStream(videoStream: MediaStream): Promise<void> {\n // Synchronous validation - throw immediately\n if (process.env.NODE_ENV !== \"development\" && this.status !== \"ready\") {\n const errorMessage = `Cannot publish video stream, status is ${this.status}`;\n console.error(\"[Reactor] Not ready, cannot publish video stream\");\n throw new Error(errorMessage);\n }\n\n try {\n await this.machineClient?.publishVideoTrack(videoStream);\n } catch (error) {\n console.error(\"[Reactor] Failed to publish video:\", error);\n this.createError(\n \"VIDEO_PUBLISH_FAILED\",\n `Failed to publish video: ${error}`,\n \"gpu\",\n true\n );\n }\n }\n\n /**\n * Public method to unpublish video stream to the machine.\n * This unpublishes the video track that was previously sent.\n */\n async unpublishVideoStream(): Promise<void> {\n try {\n await this.machineClient?.unpublishVideoTrack();\n } catch (error) {\n console.error(\"[Reactor] Failed to unpublish video:\", error);\n this.createError(\n \"VIDEO_UNPUBLISH_FAILED\",\n `Failed to unpublish video: ${error}`,\n \"gpu\",\n true\n );\n }\n }\n\n /**\n * Connects to the machine via LiveKit and waits for the gpu machine to be ready.\n * Once the machine is ready, the Reactor will establish the LiveKit connection.\n * @param livekitJwtToken The JWT token for LiveKit authentication\n * @param livekitWsUrl The WebSocket URL for LiveKit connection\n */\n private async connectToGPUMachine(\n livekitJwtToken: string,\n livekitWsUrl: string\n ) {\n console.debug(\"[Reactor] Connecting to machine room...\");\n\n try {\n this.machineClient = new GPUMachineClient(livekitJwtToken, livekitWsUrl);\n\n this.machineClient.on(\"application\", (message: any) => {\n // escalate the message event through the instance, so that the user can listen to it.\n this.emit(\"newMessage\", message);\n });\n\n this.machineClient.on(\n \"statusChanged\",\n (status: InternalConnectionStatus) => {\n switch (status) {\n case \"connected\":\n this.setStatus(\"ready\");\n break;\n case \"disconnected\":\n // gpu machine has disconnected. Close any other connection to any other entity\n // such as the coordinator or the LiveKit connection.\n this.disconnect();\n break;\n case \"error\":\n // gpu machine has errored. Close any other connection to any other entity\n // such as the coordinator or the LiveKit connection.\n this.createError(\n \"GPU_CONNECTION_ERROR\",\n \"GPU machine connection failed\",\n \"gpu\",\n true\n );\n this.disconnect();\n break;\n }\n }\n );\n\n this.machineClient.on(\"fps\", (fps: number) => {\n this.emit(\"fps\", fps);\n });\n\n this.machineClient.on(\"streamChanged\", (videoTrack) => {\n this.emit(\"streamChanged\", videoTrack);\n });\n\n console.debug(\"[Reactor] About to connect to machine\");\n await this.machineClient.connect();\n } catch (error) {\n // For private methods, we can still throw since the caller will handle it appropriately\n throw error;\n }\n }\n\n /**\n * Connects to the coordinator and waits for a GPU to be assigned.\n * Once a GPU is assigned, the Reactor will connect to the gpu machine via LiveKit.\n */\n async connect(): Promise<void> {\n console.debug(\"[Reactor] Connecting, status:\", this.status);\n\n // Synchronous validation - throw immediately\n if (this.status !== \"disconnected\")\n throw new Error(\"Already connected or connecting\");\n\n if (this.directConnection) {\n return this.connectToGPUMachine(\n this.directConnection.livekitJwtToken,\n this.directConnection.livekitWsUrl\n );\n }\n\n this.setStatus(\"connecting\");\n\n try {\n console.debug(\n \"[Reactor] Connecting to coordinator with authenticated URL\"\n );\n\n this.coordinatorClient = new CoordinatorClient({\n wsUrl: this.coordinatorUrl,\n jwtToken: this.jwtToken,\n insecureApiKey: this.insecureApiKey,\n modelName: this.modelName,\n modelVersion: this.modelVersion,\n queueing: this.queueing,\n });\n\n this.coordinatorClient.on(\n \"gpu-machine-assigned\",\n async (assignmentData: GPUMachineAssignmentData) => {\n console.debug(\n \"[Reactor] GPU machine assigned by coordinator:\",\n assignmentData\n );\n try {\n await this.connectToGPUMachine(\n assignmentData.livekitJwtToken,\n assignmentData.livekitWsUrl\n );\n } catch (error) {\n console.error(\"[Reactor] Failed to connect to GPU machine:\", error);\n // Emit error event for async GPU connection failure\n this.createError(\n \"GPU_CONNECTION_FAILED\",\n `Failed to connect to GPU machine: ${error}`,\n \"gpu\",\n true\n );\n this.disconnect();\n }\n }\n );\n\n this.coordinatorClient.on(\n \"waiting-info\",\n (waitingData: ReactorWaitingInfo) => {\n console.debug(\"[Reactor] Waiting info update received:\", waitingData);\n // Update waiting info\n this.setWaitingInfo({\n ...this.waitingInfo,\n ...waitingData,\n });\n }\n );\n\n this.coordinatorClient.on(\n \"statusChanged\",\n (newStatus: InternalConnectionStatus) => {\n switch (newStatus) {\n case \"connected\":\n this.setStatus(\"waiting\");\n // Initialize waiting info when entering waiting state\n this.setWaitingInfo({\n position: undefined,\n estimatedWaitTime: undefined,\n averageWaitTime: undefined,\n });\n break;\n case \"disconnected\":\n this.disconnect();\n break;\n case \"error\":\n this.createError(\n \"COORDINATOR_CONNECTION_ERROR\",\n \"Coordinator connection failed\",\n \"coordinator\",\n true\n );\n this.disconnect();\n break;\n }\n }\n );\n\n await this.coordinatorClient.connect();\n } catch (error) {\n console.error(\"[Reactor] Authentication failed:\", error);\n this.createError(\n \"AUTHENTICATION_FAILED\",\n `Authentication failed: ${error}`,\n \"coordinator\",\n true\n );\n this.setStatus(\"disconnected\");\n // Keep throwing for authentication failures as these are immediate/sync failures\n throw error;\n }\n }\n\n /**\n * Disconnects from the coordinator and the gpu machine.\n * Ensures cleanup completes even if individual disconnections fail.\n */\n async disconnect() {\n if (this.status === \"disconnected\") return;\n\n // Disconnect coordinator client with error handling\n if (this.coordinatorClient) {\n try {\n this.coordinatorClient.disconnect();\n } catch (error) {\n console.error(\"[Reactor] Error disconnecting from coordinator:\", error);\n // Continue with cleanup even if coordinator disconnect fails\n }\n this.coordinatorClient = undefined;\n }\n\n // Disconnect machine client with error handling\n if (this.machineClient) {\n try {\n await this.machineClient.disconnect();\n } catch (error) {\n console.error(\"[Reactor] Error disconnecting from GPU machine:\", error);\n // Continue with cleanup even if machine disconnect fails\n }\n this.machineClient = undefined;\n }\n\n this.setStatus(\"disconnected\");\n\n // Clear waiting info when disconnecting\n this.waitingInfo = undefined;\n }\n\n private setStatus(newStatus: ReactorStatus) {\n console.debug(\"[Reactor] Setting status:\", newStatus, \"from\", this.status);\n if (this.status !== newStatus) {\n this.status = newStatus;\n this.emit(\"statusChanged\", newStatus);\n }\n }\n\n private setWaitingInfo(newWaitingInfo: ReactorWaitingInfo) {\n console.debug(\n \"[Reactor] Setting waiting info:\",\n newWaitingInfo,\n \"from\",\n this.waitingInfo\n );\n if (this.waitingInfo !== newWaitingInfo) {\n this.waitingInfo = newWaitingInfo;\n this.emit(\"waitingInfoChanged\", newWaitingInfo);\n }\n }\n\n getStatus(): ReactorStatus {\n return this.status;\n }\n\n /**\n * Get the current state including status, error, and waiting info\n */\n getState(): ReactorState {\n return {\n status: this.status,\n waitingInfo: this.waitingInfo,\n lastError: this.lastError,\n };\n }\n\n /**\n * Get waiting information when status is 'waiting'\n */\n getWaitingInfo(): ReactorWaitingInfo | undefined {\n return this.waitingInfo;\n }\n\n /**\n * Get the last error that occurred\n */\n getLastError(): ReactorError | undefined {\n return this.lastError;\n }\n\n /**\n * Create and store an error\n */\n private createError(\n code: string,\n message: string,\n component: \"coordinator\" | \"gpu\" | \"livekit\",\n recoverable: boolean,\n retryAfter?: number\n ) {\n this.lastError = {\n code,\n message,\n timestamp: Date.now(),\n recoverable,\n component,\n retryAfter,\n };\n\n // Emit error event\n this.emit(\"error\", this.lastError);\n }\n}\n","\"use client\";\n\nimport { ReactNode, useContext, useEffect, useRef, useState } from \"react\";\nimport {\n createReactorStore,\n initReactorStore,\n ReactorContext,\n ReactorStore,\n ReactorStoreApi,\n type ReactorInitializationProps,\n} from \"../core/store\";\nimport { useStore } from \"zustand\";\n\n// Provider props\ninterface ReactorProviderProps extends ReactorInitializationProps {\n autoConnect?: boolean;\n children: ReactNode;\n}\n\n// tsx component\nexport function ReactorProvider({\n children,\n autoConnect = true,\n ...props\n}: ReactorProviderProps) {\n // Stable Reactor instance\n const storeRef = useRef<ReactorStoreApi | undefined>(undefined);\n const firstRender = useRef(true);\n // State to trigger re-renders when store changes\n const [_storeVersion, setStoreVersion] = useState(0);\n\n if (storeRef.current === undefined) {\n console.debug(\"[ReactorProvider] Creating new reactor store\");\n // We create the store without autoconnecting, to avoid duplicate connections.\n // We actually connect when the component is mounted, to be on sync with the react component lifecycle.\n storeRef.current = createReactorStore(initReactorStore(props));\n console.debug(\"[ReactorProvider] Reactor store created successfully\");\n }\n\n // Fan out props to individual variables so that the\n // useEffect hook can be optimized by only re-running when the\n // props that actually change.\n const {\n coordinatorUrl,\n modelName,\n jwtToken,\n insecureApiKey,\n directConnection,\n queueing,\n local,\n } = props;\n\n useEffect(() => {\n if (firstRender.current) {\n firstRender.current = false;\n\n // We know as a fact that the store is not undefined at this point\n const current = storeRef.current!;\n if (autoConnect && current.getState().status === \"disconnected\") {\n console.debug(\n \"[ReactorProvider] Starting autoconnect in first render...\"\n );\n current\n .getState()\n .connect()\n .then(() => {\n console.debug(\n \"[ReactorProvider] Autoconnect successful in first render\"\n );\n })\n .catch((error) => {\n console.error(\n \"[ReactorProvider] Failed to autoconnect in first render:\",\n error\n );\n });\n }\n return () => {\n console.debug(\n \"[ReactorProvider] Disconnecting in cleanup for first render\"\n );\n current\n .getState()\n .disconnect()\n .then(() => {\n console.debug(\n \"[ReactorProvider] Disconnect completed successfully in cleanup for first render\"\n );\n })\n .catch((error) => {\n console.error(\n \"[ReactorProvider] Failed to disconnect in cleanup for first render:\",\n error\n );\n });\n };\n }\n\n console.debug(\"[ReactorProvider] Updating reactor store\");\n storeRef.current = createReactorStore(\n initReactorStore({\n coordinatorUrl,\n modelName,\n jwtToken,\n insecureApiKey,\n directConnection,\n queueing,\n local,\n } satisfies ReactorInitializationProps)\n );\n\n // Store current reference to the store in the return\n const current = storeRef.current!;\n\n // Increment version to trigger re-render and propagate new store to Provider\n setStoreVersion((v) => v + 1);\n console.debug(\n \"[ReactorProvider] Reactor store updated successfully, and increased version\"\n );\n\n if (autoConnect && current.getState().status === \"disconnected\") {\n console.debug(\"[ReactorProvider] Starting autoconnect...\");\n current\n .getState()\n .connect()\n .then(() => {\n console.debug(\"[ReactorProvider] Autoconnect successful\");\n })\n .catch((error) => {\n console.error(\"[ReactorProvider] Failed to autoconnect:\", error);\n });\n }\n\n return () => {\n console.debug(\"[ReactorProvider] Disconnecting in cleanup\");\n current\n .getState()\n .disconnect()\n .then(() => {\n console.debug(\n \"[ReactorProvider] Disconnect completed successfully in cleanup\"\n );\n })\n .catch((error) => {\n console.error(\"[ReactorProvider] Failed to disconnect:\", error);\n });\n };\n }, [\n coordinatorUrl,\n modelName,\n jwtToken,\n insecureApiKey,\n directConnection,\n queueing,\n autoConnect,\n local,\n ]);\n\n return (\n <ReactorContext.Provider value={storeRef.current}>\n {children}\n </ReactorContext.Provider>\n );\n}\n\nexport function useReactorStore<T = ReactorStore>(\n selector: (state: ReactorStore) => T\n): T {\n const ctx = useContext(ReactorContext);\n if (!ctx) {\n throw new Error(\"useReactor must be used within a ReactorProvider\");\n }\n\n return useStore(ctx, selector);\n}\n","import { StoreApi } from \"zustand\";\nimport type { ReactorStatus, ReactorWaitingInfo, ReactorError } from \"../types\";\nimport { Reactor, type Options as ReactorOptions } from \"./Reactor\";\nimport { create } from \"zustand/react\";\nimport { createContext } from \"react\";\nimport type { RemoteVideoTrack } from \"livekit-client\";\n\nexport type ReactorStoreApi = ReturnType<typeof createReactorStore>;\n\nexport interface ReactorState {\n status: ReactorStatus;\n videoTrack: RemoteVideoTrack | null;\n //These are the machine FPS. The machine internally reports to the client the rate at which the frames are\n //being generated. This can be useful for the client to calcolate at which rate to run commands.\n fps?: number;\n waitingInfo?: ReactorWaitingInfo;\n lastError?: ReactorError;\n}\n\nexport interface ReactorActions {\n sendMessage(message: any): Promise<void>;\n connect(): Promise<void>;\n disconnect(): Promise<void>;\n publishVideoStream(stream: MediaStream): Promise<void>;\n unpublishVideoStream(): Promise<void>;\n}\n\n// Internal state not exposed to components\ninterface ReactorInternalState {\n reactor: Reactor;\n}\n\nexport const ReactorContext = createContext<ReactorStoreApi | undefined>(\n undefined\n);\n\nexport type ReactorStore = ReactorState &\n ReactorActions & {\n internal: ReactorInternalState;\n };\n\nexport const defaultInitState: ReactorState = {\n status: \"disconnected\",\n videoTrack: null,\n fps: undefined,\n waitingInfo: undefined,\n lastError: undefined,\n};\n\nexport interface ReactorInitializationProps extends ReactorOptions {}\n\nexport const initReactorStore = (\n props: ReactorInitializationProps\n): ReactorState & ReactorInitializationProps => {\n return {\n ...defaultInitState,\n // These are only used for dev initialization, not exposed in the store\n ...props,\n };\n};\n\nexport const createReactorStore = (\n initProps: ReactorInitializationProps,\n publicState: ReactorState = defaultInitState\n): StoreApi<ReactorStore> => {\n console.debug(\"[ReactorStore] Creating store\", {\n coordinatorUrl: initProps.coordinatorUrl,\n initialState: publicState,\n });\n\n return create<ReactorStore>()((set, get) => {\n const reactor = new Reactor(initProps);\n\n console.debug(\"[ReactorStore] Setting up event listeners\");\n\n reactor.on(\"statusChanged\", (newStatus: ReactorStatus) => {\n console.debug(\"[ReactorStore] Status changed\", {\n oldStatus: get().status,\n newStatus,\n });\n set({ status: newStatus });\n });\n\n reactor.on(\"waitingInfoChanged\", (newWaitingInfo: ReactorWaitingInfo) => {\n console.debug(\"[ReactorStore] Waiting info changed\", {\n oldWaitingInfo: get().waitingInfo,\n newWaitingInfo,\n });\n set({ waitingInfo: newWaitingInfo });\n });\n\n reactor.on(\"streamChanged\", (videoTrack: RemoteVideoTrack | null) => {\n console.debug(\"[ReactorStore] Stream changed\", {\n hasVideoTrack: !!videoTrack,\n videoTrackKind: videoTrack?.kind,\n videoTrackSid: videoTrack?.sid,\n });\n set({ videoTrack: videoTrack });\n });\n\n reactor.on(\"fps\", (fps: number) => {\n console.debug(\"[ReactorStore] FPS updated\", { fps });\n set({ fps: fps });\n });\n\n reactor.on(\"error\", (error: ReactorError) => {\n console.debug(\"[ReactorStore] Error occurred\", error);\n set({ lastError: error });\n });\n\n return {\n ...publicState,\n internal: { reactor },\n\n // actions\n onMessage: (handler: (message: any) => void) => {\n console.debug(\"[ReactorStore] Registering message handler\");\n\n // Simply register the handler\n get().internal.reactor.on(\"newMessage\", handler);\n\n // Return a cleanup function that can be called to unregister\n return () => {\n console.debug(\"[ReactorStore] Cleaning up message handler\");\n get().internal.reactor.off(\"newMessage\", handler);\n };\n },\n sendMessage: async (mess: any) => {\n console.debug(\"[ReactorStore] Sending message\", { message: mess });\n\n try {\n await get().internal.reactor.sendMessage(mess);\n console.debug(\"[ReactorStore] Message sent successfully\");\n } catch (error) {\n console.error(\"[ReactorStore] Failed to send message:\", error);\n throw error;\n }\n },\n connect: async () => {\n console.debug(\"[ReactorStore] Connect called\");\n\n try {\n await get().internal.reactor.connect();\n console.debug(\"[ReactorStore] Connect completed successfully\");\n } catch (error) {\n console.error(\"[ReactorStore] Connect failed:\", error);\n throw error;\n }\n },\n disconnect: async () => {\n console.debug(\"[ReactorStore] Disconnect called\", {\n currentStatus: get().status,\n });\n\n try {\n await get().internal.reactor.disconnect();\n console.debug(\"[ReactorStore] Disconnect completed successfully\");\n } catch (error) {\n console.error(\"[ReactorStore] Disconnect failed:\", error);\n throw error;\n }\n },\n publishVideoStream: async (stream: MediaStream) => {\n console.debug(\"[ReactorStore] Publishing video stream\");\n\n try {\n await get().internal.reactor.publishVideoStream(stream);\n console.debug(\"[ReactorStore] Video stream published successfully\");\n } catch (error) {\n console.error(\n \"[ReactorStore] Failed to publish video stream:\",\n error\n );\n throw error;\n }\n },\n unpublishVideoStream: async () => {\n console.debug(\"[ReactorStore] Unpublishing video stream\");\n\n try {\n await get().internal.reactor.unpublishVideoStream();\n console.debug(\"[ReactorStore] Video stream unpublished successfully\");\n } catch (error) {\n console.error(\n \"[ReactorStore] Failed to unpublish video stream:\",\n error\n );\n throw error;\n }\n },\n };\n });\n};\n","import { useReactorStore } from \"./ReactorProvider\";\nimport type { ReactorStore } from \"../core/store\";\nimport { useShallow } from \"zustand/shallow\";\nimport { useEffect, useRef } from \"react\";\n\n/**\n * Generic hook for accessing selected parts of the Reactor store.\n *\n * @param selector - A function that selects part of the store state.\n * @returns The selected slice from the store.\n */\nexport function useReactor<T>(selector: (state: ReactorStore) => T): T {\n return useReactorStore(useShallow(selector));\n}\n\n/**\n * Hook for handling message subscriptions with proper React lifecycle management.\n *\n * @param handler - The message handler function\n */\nexport function useReactorMessage(handler: (message: any) => void): void {\n const reactor = useReactor((state) => state.internal.reactor);\n const handlerRef = useRef(handler);\n\n // Update the ref when handler changes\n useEffect(() => {\n handlerRef.current = handler;\n }, [handler]);\n\n useEffect(() => {\n console.debug(\"[useReactorMessage] Setting up message subscription\");\n\n // Create a stable handler that calls the current ref\n const stableHandler = (message: any) => {\n console.debug(\"[useReactorMessage] Message received\", { message });\n handlerRef.current(message);\n };\n\n // Register the handler and get the cleanup function\n reactor.on(\"newMessage\", stableHandler);\n\n console.debug(\"[useReactorMessage] Message handler registered\");\n\n // Return the cleanup function\n return () => {\n console.debug(\"[useReactorMessage] Cleaning up message subscription\");\n reactor.off(\"newMessage\", stableHandler);\n };\n }, [reactor]);\n}\n","\"use client\";\n\nimport { useReactor } from \"./hooks\";\nimport { useEffect, useRef } from \"react\";\nimport React from \"react\";\n\nexport interface ReactorViewProps {\n width?: number;\n height?: number;\n className?: string;\n style?: React.CSSProperties;\n videoObjectFit?: NonNullable<\n React.VideoHTMLAttributes<HTMLVideoElement>[\"style\"]\n >[\"objectFit\"];\n}\n\nexport function ReactorView({\n width,\n height,\n className,\n style,\n videoObjectFit = \"contain\",\n}: ReactorViewProps) {\n const { videoTrack, status } = useReactor((state) => ({\n videoTrack: state.videoTrack,\n status: state.status,\n }));\n\n const videoRef = useRef<HTMLVideoElement>(null);\n\n useEffect(() => {\n console.debug(\"[ReactorView] Video track effect triggered\", {\n hasVideoElement: !!videoRef.current,\n hasVideoTrack: !!videoTrack,\n videoTrackKind: videoTrack?.kind,\n });\n\n if (videoRef.current && videoTrack) {\n console.debug(\"[ReactorView] Attaching video track to element\");\n try {\n // Attach the LiveKit track to the video element\n videoTrack.attach(videoRef.current);\n console.debug(\"[ReactorView] Video track attached successfully\");\n } catch (error) {\n console.error(\"[ReactorView] Failed to attach video track:\", error);\n }\n\n // Cleanup: detach when track changes or component unmounts\n return () => {\n console.debug(\"[ReactorView] Detaching video track from element\");\n if (videoRef.current) {\n try {\n videoTrack.detach(videoRef.current);\n console.debug(\"[ReactorView] Video track detached successfully\");\n } catch (error) {\n console.error(\"[ReactorView] Failed to detach video track:\", error);\n }\n }\n };\n } else {\n console.debug(\"[ReactorView] No video track or element to attach\");\n }\n }, [videoTrack]);\n\n const showPlaceholder = !videoTrack;\n\n return (\n <div\n style={{\n position: \"relative\",\n background: \"#000\",\n ...(width && { width }),\n ...(height && { height }),\n ...style,\n }}\n className={className}\n >\n <video\n ref={videoRef}\n style={{\n width: \"100%\",\n height: \"100%\",\n objectFit: videoObjectFit,\n display: showPlaceholder ? \"none\" : \"block\",\n }}\n muted\n playsInline\n />\n {showPlaceholder && (\n <div\n style={{\n position: \"absolute\",\n top: 0,\n left: 0,\n width: \"100%\",\n height: \"100%\",\n color: \"#fff\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n fontSize: \"16px\",\n fontFamily: \"monospace\",\n textAlign: \"center\",\n padding: \"20px\",\n boxSizing: \"border-box\",\n }}\n >\n {status}\n </div>\n )}\n </div>\n );\n}\n","\"use client\";\n\nimport { useReactor } from \"./hooks\";\nimport { useEffect, useRef, useState } from \"react\";\nimport React from \"react\";\n\ninterface Props {\n className?: string;\n style?: React.CSSProperties;\n videoConstraints?: MediaTrackConstraints;\n showWebcam?: boolean;\n videoObjectFit?: NonNullable<\n React.VideoHTMLAttributes<HTMLVideoElement>[\"style\"]\n >[\"objectFit\"];\n}\n\nexport function WebcamStream({\n className,\n style,\n videoConstraints = {\n width: { ideal: 1280 },\n height: { ideal: 720 },\n },\n showWebcam = true,\n videoObjectFit = \"contain\",\n}: Props) {\n const [stream, setStream] = useState<MediaStream | null>(null);\n const [isPublishing, setIsPublishing] = useState(false);\n const [permissionDenied, setPermissionDenied] = useState(false);\n\n const { status, publishVideoStream, unpublishVideoStream, reactor } =\n useReactor((state) => ({\n status: state.status,\n publishVideoStream: state.publishVideoStream,\n unpublishVideoStream: state.unpublishVideoStream,\n reactor: state.internal.reactor,\n }));\n\n const videoRef = useRef<HTMLVideoElement>(null);\n\n // Start webcam\n const startWebcam = async () => {\n console.debug(\"[WebcamPublisher] Starting webcam\");\n\n try {\n const mediaStream = await navigator.mediaDevices.getUserMedia({\n video: videoConstraints,\n audio: false,\n });\n\n console.debug(\"[WebcamPublisher] Webcam started successfully\");\n setStream(mediaStream);\n setPermissionDenied(false);\n } catch (err) {\n console.error(\"[WebcamPublisher] Failed to start webcam:\", err);\n\n // Check if the error is a permission denial\n if (\n err instanceof DOMException &&\n (err.name === \"NotAllowedError\" || err.name === \"PermissionDeniedError\")\n ) {\n console.debug(\"[WebcamPublisher] Camera permission denied\");\n setPermissionDenied(true);\n }\n }\n };\n\n // Stop webcam\n const stopWebcam = async () => {\n console.debug(\"[WebcamPublisher] Stopping webcam\");\n\n // Unpublish if currently publishing\n try {\n await unpublishVideoStream();\n console.debug(\"[WebcamPublisher] Unpublished before stopping\");\n } catch (err) {\n console.error(\"[WebcamPublisher] Error unpublishing before stop:\", err);\n }\n\n setIsPublishing(false);\n\n // Stop all tracks\n stream?.getTracks().forEach((track) => {\n track.stop();\n console.debug(\"[WebcamPublisher] Stopped track:\", track.kind);\n });\n setStream(null);\n\n console.debug(\"[WebcamPublisher] Webcam stopped\");\n };\n\n // Attach stream to video element\n useEffect(() => {\n console.debug(\"[WebcamPublisher] Stream effect triggered\", {\n hasVideoElement: !!videoRef.current,\n hasStream: !!stream,\n });\n\n if (!videoRef.current) {\n return;\n }\n\n if (stream) {\n console.debug(\"[WebcamPublisher] Attaching stream to video element\");\n videoRef.current.srcObject = stream;\n console.debug(\"[WebcamPublisher] Stream attached successfully\");\n } else {\n console.debug(\"[WebcamPublisher] Clearing video element\");\n videoRef.current.srcObject = null;\n }\n }, [stream]);\n\n // Auto-publish when reactor is ready and webcam is active\n useEffect(() => {\n if (!stream) {\n return;\n }\n\n if (status === \"ready\" && !isPublishing) {\n console.debug(\n \"[WebcamPublisher] Reactor ready, auto-publishing webcam stream\"\n );\n publishVideoStream(stream)\n .then(() => {\n console.debug(\"[WebcamPublisher] Auto-publish successful\");\n setIsPublishing(true);\n })\n .catch((err) => {\n console.error(\"[WebcamPublisher] Auto-publish failed:\", err);\n });\n } else if (status !== \"ready\" && isPublishing) {\n console.debug(\"[WebcamPublisher] Reactor not ready, auto-unpublishing\");\n unpublishVideoStream()\n .then(() => {\n console.debug(\"[WebcamPublisher] Auto-unpublish successful\");\n setIsPublishing(false);\n })\n .catch((err) => {\n console.error(\"[WebcamPublisher] Auto-unpublish failed:\", err);\n });\n }\n }, [status, stream, isPublishing, publishVideoStream, unpublishVideoStream]);\n\n // Listen for error events from Reactor\n useEffect(() => {\n const handleError = (error: any) => {\n console.debug(\"[WebcamPublisher] Received error event:\", error);\n\n // Handle video publish failures by resetting state\n if (error.code === \"VIDEO_PUBLISH_FAILED\") {\n console.debug(\n \"[WebcamPublisher] Video publish failed, resetting isPublishing state\"\n );\n setIsPublishing(false);\n }\n };\n\n reactor.on(\"error\", handleError);\n\n return () => {\n reactor.off(\"error\", handleError);\n };\n }, [reactor]);\n\n // Reset publishing state when status changes away from ready\n useEffect(() => {\n if (status !== \"ready\") {\n console.debug(\n \"[WebcamPublisher] Status changed to\",\n status,\n \"- resetting isPublishing state\"\n );\n setIsPublishing(false);\n }\n }, [status, isPublishing]);\n\n // Auto-start webcam on mount and cleanup on unmount\n useEffect(() => {\n console.debug(\"[WebcamPublisher] Auto-starting webcam\");\n startWebcam();\n\n return () => {\n console.debug(\"[WebcamPublisher] Cleanup on unmount\");\n stopWebcam();\n };\n }, []); // eslint-disable-line react-hooks/exhaustive-deps\n\n const showPlaceholder = !stream;\n\n return (\n <div\n style={{\n display: showWebcam ? \"block\" : \"none\",\n position: \"relative\",\n background: \"#000\",\n ...style,\n }}\n className={className}\n >\n <video\n ref={videoRef}\n style={{\n width: \"100%\",\n height: \"100%\",\n objectFit: videoObjectFit,\n display: showPlaceholder ? \"none\" : \"block\",\n }}\n muted\n playsInline\n autoPlay\n />\n {showPlaceholder && (\n <div\n style={{\n position: \"absolute\",\n top: 0,\n left: 0,\n width: \"100%\",\n height: \"100%\",\n color: \"#fff\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n fontSize: \"16px\",\n fontFamily: \"monospace\",\n textAlign: \"center\",\n padding: \"20px\",\n boxSizing: \"border-box\",\n flexDirection: \"column\",\n gap: \"12px\",\n }}\n >\n {permissionDenied ? (\n <div style={{ fontSize: \"12px\", fontFamily: \"monospace\" }}>\n Camera access denied.\n <br />\n Please allow access in your browser settings.\n </div>\n ) : (\n <div style={{ fontSize: \"12px\", fontFamily: \"monospace\" }}>\n Starting camera...\n </div>\n )}\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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","names":["z","z","_a","z","OptionsSchema","z","current","useEffect","useRef","useEffect","useRef","jsx","useRef","useEffect","useEffect","useRef","useState","jsx","jsxs","useState","useRef","useEffect"]}
1
+ {"version":3,"sources":["../src/core/types.ts","../src/core/CoordinatorClient.ts","../src/core/GPUMachineClient.ts","../src/core/Reactor.ts","../src/react/ReactorProvider.tsx","../src/core/store.ts","../src/react/hooks.ts","../src/react/ReactorView.tsx","../src/react/WebcamStream.tsx"],"sourcesContent":["/**\n * Internal types for the Reactor SDK.\n */\n\nimport { z } from \"zod\";\n\n// Base message schemas corresponding to Python Pydantic models\n\nexport const ApplicationMessageSchema = z.object({\n type: z.literal(\"application\"),\n data: z.any(), // Can be any JSON-serializable data\n});\n\n// Internal message that notifies the client of the current push rate of the machine\nexport const FPSMessageSchema = z.object({\n type: z.literal(\"fps\"),\n data: z.number(),\n});\n\nexport const GPUMachineReceiveMessageSchema = z.discriminatedUnion(\"type\", [\n ApplicationMessageSchema,\n FPSMessageSchema,\n]);\n\nexport const WelcomeMessageSchema = z.object({\n type: z.literal(\"welcome\"),\n data: z.record(z.string(), z.any()),\n});\n\nexport const GPUMachineAssignmentDataSchema = z.object({\n livekitWsUrl: z.string(),\n livekitJwtToken: z.string(),\n});\n\nexport const GPUMachineAssignmentMessageSchema = z.object({\n type: z.literal(\"gpu-machine-assigned\"),\n data: GPUMachineAssignmentDataSchema,\n});\n\nexport const EchoMessageSchema = z.object({\n type: z.literal(\"echo\"),\n data: z.record(z.string(), z.any()),\n});\n\nexport const WaitingInfoDataSchema = z.object({\n position: z.number().optional(),\n estimatedWaitTime: z.number().optional(),\n averageWaitTime: z.number().optional(),\n});\n\nexport const WaitingInfoMessageSchema = z.object({\n type: z.literal(\"waiting-info\"),\n data: WaitingInfoDataSchema,\n});\n\nexport const SessionExpirationDataSchema = z.object({\n expire: z.number(),\n});\n\nexport const SessionExpirationMessageSchema = z.object({\n type: z.literal(\"session-expiration\"),\n data: SessionExpirationDataSchema,\n});\n\nexport const CoordinatorMessageSchema = z.discriminatedUnion(\"type\", [\n WelcomeMessageSchema,\n GPUMachineAssignmentMessageSchema,\n EchoMessageSchema,\n WaitingInfoMessageSchema,\n SessionExpirationMessageSchema,\n]);\n\nexport const GPUMachineSendMessageSchema = z.discriminatedUnion(\"type\", [\n ApplicationMessageSchema,\n]);\n\nexport const SessionSetupMessageSchema = z.object({\n type: z.literal(\"sessionSetup\"),\n data: z.object({\n modelName: z.string(),\n modelVersion: z.string().default(\"latest\"),\n }),\n});\n\n// TypeScript types derived from schemas\nexport type ApplicationMessage = z.infer<typeof ApplicationMessageSchema>;\nexport type GPUMachineReceiveMessageSchema = z.infer<\n typeof GPUMachineReceiveMessageSchema\n>;\nexport type WelcomeMessage = z.infer<typeof WelcomeMessageSchema>;\nexport type GPUMachineAssignmentData = z.infer<\n typeof GPUMachineAssignmentDataSchema\n>;\nexport type GPUMachineAssignmentMessage = z.infer<\n typeof GPUMachineAssignmentMessageSchema\n>;\nexport type EchoMessage = z.infer<typeof EchoMessageSchema>;\nexport type WaitingInfoData = z.infer<typeof WaitingInfoDataSchema>;\nexport type WaitingInfoMessage = z.infer<typeof WaitingInfoMessageSchema>;\nexport type CoordinatorMessage = z.infer<typeof CoordinatorMessageSchema>;\nexport type GPUMachineSendMessage = z.infer<typeof GPUMachineSendMessageSchema>;\nexport type SessionSetupMessage = z.infer<typeof SessionSetupMessageSchema>;\n\n// Internal connection status for individual components\nexport type InternalConnectionStatus =\n | \"disconnected\"\n | \"connecting\"\n | \"connected\"\n | \"error\";\n","/**\n * The CoordinatorClient is responsible for handling the connection to the coordinator.\n */\n\nimport {\n type CoordinatorMessage,\n CoordinatorMessageSchema,\n type SessionSetupMessage,\n} from \"./types\";\nimport { z } from \"zod\";\n\ntype EventHandler = (...args: any[]) => void;\n\nconst OptionsSchema = z\n .object({\n wsUrl: z.string().nonempty(),\n jwtToken: z.string().optional(),\n insecureApiKey: z.string().optional(),\n modelName: z.string(),\n modelVersion: z.string().default(\"latest\"),\n queueing: z.boolean().default(false),\n })\n .refine((data) => data.jwtToken || data.insecureApiKey, {\n message: \"At least one of jwtToken or insecureApiKey must be provided.\",\n });\n\ntype Options = z.input<typeof OptionsSchema>;\n\n// Infer message types from the schema - single source of truth\nexport type CoordinatorEvent = \"statusChanged\" | CoordinatorMessage[\"type\"];\n\nexport class CoordinatorClient {\n private websocket?: WebSocket;\n private wsUrl: string;\n private jwtToken?: string;\n private insecureApiKey?: string;\n private eventListeners: Map<CoordinatorEvent, Set<EventHandler>> = new Map();\n private modelName: string;\n private modelVersion: string;\n private queueing: boolean;\n\n constructor(options: Options) {\n const validatedOptions = OptionsSchema.parse(options);\n this.wsUrl = validatedOptions.wsUrl;\n this.jwtToken = validatedOptions.jwtToken;\n this.insecureApiKey = validatedOptions.insecureApiKey;\n this.modelName = validatedOptions.modelName;\n this.modelVersion = validatedOptions.modelVersion;\n this.queueing = validatedOptions.queueing;\n }\n\n // Event Emitter API\n on(event: CoordinatorEvent, handler: EventHandler) {\n if (!this.eventListeners.has(event)) {\n this.eventListeners.set(event, new Set());\n }\n this.eventListeners.get(event)!.add(handler);\n }\n\n off(event: CoordinatorEvent, handler: EventHandler) {\n this.eventListeners.get(event)?.delete(handler);\n }\n\n emit(event: CoordinatorEvent, ...args: any[]) {\n this.eventListeners.get(event)?.forEach((handler) => handler(...args));\n }\n\n sendMessage(message: any) {\n try {\n const messageStr =\n typeof message === \"string\" ? message : JSON.stringify(message);\n this.websocket?.send(messageStr);\n } catch (error) {\n console.error(\"[CoordinatorClient] Failed to send message:\", error);\n this.emit(\"statusChanged\", \"error\");\n }\n }\n\n async connect(): Promise<void> {\n // Build WebSocket URL with authentication query parameters\n const url = new URL(this.wsUrl);\n if (this.jwtToken) {\n url.searchParams.set(\"jwt_token\", this.jwtToken);\n } else if (this.insecureApiKey) {\n url.searchParams.set(\"api_key\", this.insecureApiKey);\n }\n\n // Add queued parameter only if queueing is true\n if (this.queueing) {\n url.searchParams.set(\"queueing\", \"true\");\n }\n\n console.debug(\"[CoordinatorClient] Connecting to\", url.toString());\n this.websocket = new WebSocket(url.toString());\n\n this.websocket.onopen = () => {\n console.debug(\"[CoordinatorClient] WebSocket opened\");\n this.emit(\"statusChanged\", \"connected\");\n };\n\n this.websocket.onmessage = (event) => {\n try {\n let parsedData: string | object;\n if (typeof event.data === \"string\") {\n parsedData = JSON.parse(event.data);\n } else {\n parsedData = event.data;\n }\n console.debug(\n \"[CoordinatorClient] Received message from coordinator:\",\n parsedData\n );\n const validatedData = CoordinatorMessageSchema.parse(parsedData);\n this.emit(validatedData.type, validatedData.data);\n } catch (error) {\n console.error(\n \"[CoordinatorClient] Failed to parse WebSocket message from coordinator:\",\n error,\n \"message\",\n event.data\n );\n this.emit(\"statusChanged\", \"error\");\n }\n };\n\n this.websocket.onclose = (event) => {\n console.debug(\"[CoordinatorClient] WebSocket closed\", event);\n this.websocket = undefined;\n this.emit(\"statusChanged\", \"disconnected\");\n };\n\n this.websocket.onerror = (error) => {\n console.error(\"[CoordinatorClient] WebSocket error:\", error);\n this.websocket = undefined;\n this.emit(\"statusChanged\", \"error\");\n };\n\n await new Promise<void>((resolve, reject) => {\n const onOpen = () => {\n this.websocket?.removeEventListener(\"error\", onError);\n resolve();\n };\n const onError = (error: Event) => {\n this.websocket?.removeEventListener(\"open\", onOpen);\n reject(error);\n };\n this.websocket?.addEventListener(\"open\", onOpen);\n this.websocket?.addEventListener(\"error\", onError);\n });\n\n console.log(\"[CoordinatorClient] WebSocket connected\");\n\n this.sendMessage({\n type: \"sessionSetup\",\n data: {\n modelName: this.modelName,\n modelVersion: this.modelVersion,\n },\n } satisfies SessionSetupMessage);\n\n console.debug(\"[CoordinatorClient] Setup session message sent\");\n }\n\n /**\n * Closes the WebSocket connection if it exists.\n * This will trigger the onclose event handler.\n */\n disconnect() {\n if (this.websocket) {\n console.debug(\"[CoordinatorClient] Closing WebSocket connection\");\n this.websocket.close();\n this.websocket = undefined;\n }\n }\n}\n","/**\n * The GPUMachineClient is responsible for handling the direct connection to the machine instance\n * after the coordinator has assigned a machine.\n */\n\nimport {\n type GPUMachineSendMessage,\n GPUMachineReceiveMessageSchema,\n} from \"./types\";\nimport {\n Room,\n RoomEvent,\n Track,\n RemoteVideoTrack,\n LocalVideoTrack,\n LocalAudioTrack,\n} from \"livekit-client\";\n\ntype EventHandler = (...args: any[]) => void;\nexport type GPUMachineEvent =\n | GPUMachineReceiveMessageSchema[\"type\"]\n | \"statusChanged\"\n | \"streamChanged\";\n\nexport class GPUMachineClient {\n private eventListeners: Map<GPUMachineEvent, Set<EventHandler>> = new Map();\n private roomInstance: Room | undefined;\n private machineFPS: number | undefined;\n private token: string;\n private videoStream: MediaStream | undefined;\n private liveKitUrl: string;\n private publishedVideoTrack: LocalVideoTrack | undefined;\n private publishedAudioTrack: LocalAudioTrack | undefined;\n\n constructor(token: string, liveKitUrl: string) {\n this.token = token;\n this.liveKitUrl = liveKitUrl;\n }\n\n // Event Emitter API\n on(event: GPUMachineEvent, handler: EventHandler) {\n if (!this.eventListeners.has(event)) {\n this.eventListeners.set(event, new Set());\n }\n this.eventListeners.get(event)!.add(handler);\n }\n\n off(event: GPUMachineEvent, handler: EventHandler) {\n this.eventListeners.get(event)?.delete(handler);\n }\n\n emit(event: GPUMachineEvent, ...args: any[]) {\n this.eventListeners.get(event)?.forEach((handler) => handler(...args));\n }\n\n async sendMessage(message: GPUMachineSendMessage): Promise<void> {\n try {\n if (this.roomInstance) {\n const messageStr = JSON.stringify(message);\n // Send message via LiveKit text channel\n await this.roomInstance.localParticipant.sendText(messageStr, {\n topic: \"application\",\n });\n } else {\n console.warn(\n \"[GPUMachineClient] Cannot send message - not connected to room\"\n );\n }\n } catch (error) {\n console.error(\"[GPUMachineClient] Failed to send message:\", error);\n this.emit(\"statusChanged\", \"error\");\n }\n }\n\n async connect(): Promise<void> {\n this.roomInstance = new Room({\n adaptiveStream: true,\n dynacast: true,\n });\n\n this.roomInstance.on(RoomEvent.Connected, () => {\n console.debug(\"[GPUMachineClient] Connected to room\");\n this.emit(\"statusChanged\", \"connected\");\n });\n\n this.roomInstance.on(RoomEvent.Disconnected, () => {\n console.debug(\"[GPUMachineClient] Disconnected from room\");\n this.emit(\"statusChanged\", \"disconnected\");\n });\n\n // Handle video track subscriptions from GPU machine\n this.roomInstance.on(\n RoomEvent.TrackSubscribed,\n (track, _publication, participant) => {\n console.debug(\n \"[GPUMachineClient] Track subscribed:\",\n track.kind,\n participant.identity\n );\n\n if (track.kind === Track.Kind.Video) {\n const videoTrack = track as RemoteVideoTrack;\n this.emit(\"streamChanged\", videoTrack);\n }\n }\n );\n\n this.roomInstance.on(\n RoomEvent.TrackUnsubscribed,\n (track, _publication, participant) => {\n console.debug(\n \"[GPUMachineClient] Track unsubscribed:\",\n track.kind,\n participant.identity\n );\n\n if (track.kind === Track.Kind.Video) {\n this.emit(\"streamChanged\", null);\n }\n }\n );\n\n this.roomInstance.registerTextStreamHandler(\n \"application\",\n async (reader, participant) => {\n const text = await reader.readAll();\n console.log(\"[GPUMachineClient] Received message:\", text);\n try {\n const parsedData = JSON.parse(text);\n\n const validatedMessage =\n GPUMachineReceiveMessageSchema.parse(parsedData);\n if (validatedMessage.type === \"fps\") {\n this.machineFPS = validatedMessage.data;\n }\n\n this.emit(validatedMessage.type, validatedMessage.data);\n } catch (error) {\n console.error(\n \"[GPUMachineClient] Failed to parse/validate message:\",\n error\n );\n this.emit(\"statusChanged\", \"error\");\n }\n }\n );\n\n await this.roomInstance.connect(this.liveKitUrl, this.token);\n\n console.log(\"[GPUMachineClient] Room connected\");\n }\n\n /**\n * Closes the LiveKit connection if it exists.\n * This will trigger the onclose event handler.\n */\n async disconnect() {\n // Unpublish any published tracks before disconnecting\n if (this.publishedVideoTrack) {\n await this.unpublishVideoTrack();\n }\n if (this.publishedAudioTrack) {\n await this.unpublishAudioTrack();\n }\n\n if (this.roomInstance) {\n console.debug(\"[GPUMachineClient] Closing LiveKit connection\");\n await this.roomInstance.disconnect();\n this.roomInstance = undefined;\n }\n this.machineFPS = undefined;\n }\n\n /**\n * Returns the current fps rate of the machine.\n * @returns The current fps rate of the machine.\n */\n getFPS(): number | undefined {\n return this.machineFPS;\n }\n\n /**\n * Returns the current video stream from the GPU machine.\n * @returns The current video stream or undefined if not available.\n */\n getVideoStream(): MediaStream | undefined {\n return this.videoStream;\n }\n\n /**\n * Publishes a video track from the provided MediaStream to the LiveKit room.\n * Only one video track can be published at a time. If a video track is already\n * published, it will be unpublished first.\n *\n * @param mediaStream The MediaStream containing the video track to publish\n * @throws Error if no video track is found in the MediaStream or room is not connected\n */\n async publishVideoTrack(mediaStream: MediaStream): Promise<void> {\n if (!this.roomInstance) {\n throw new Error(\n \"[GPUMachineClient] Cannot publish track - not connected to room\"\n );\n }\n\n const videoTracks = mediaStream.getVideoTracks();\n if (videoTracks.length === 0) {\n throw new Error(\"[GPUMachineClient] No video track found in MediaStream\");\n }\n\n // Unpublish existing video track if any\n if (this.publishedVideoTrack) {\n await this.unpublishVideoTrack();\n }\n\n try {\n const videoTrack = videoTracks[0];\n const localVideoTrack =\n await this.roomInstance.localParticipant.publishTrack(videoTrack, {\n name: \"client-video\",\n source: Track.Source.Camera,\n });\n\n this.publishedVideoTrack = localVideoTrack.track as LocalVideoTrack;\n console.debug(\"[GPUMachineClient] Video track published successfully\");\n } catch (error) {\n console.error(\"[GPUMachineClient] Failed to publish video track:\", error);\n throw error;\n }\n }\n\n /**\n * Unpublishes the currently published video track.\n * Note: We pass false to unpublishTrack to prevent LiveKit from stopping\n * the source MediaStreamTrack, as it's owned by the component that created it.\n */\n async unpublishVideoTrack(): Promise<void> {\n if (!this.roomInstance || !this.publishedVideoTrack) {\n return;\n }\n\n const publishedVideoTrack = this.publishedVideoTrack;\n this.publishedVideoTrack = undefined;\n\n try {\n await this.roomInstance.localParticipant.unpublishTrack(\n publishedVideoTrack,\n false // Don't stop the source track - it's managed externally\n );\n console.debug(\"[GPUMachineClient] Video track unpublished successfully\");\n } catch (error) {\n console.error(\n \"[GPUMachineClient] Failed to unpublish video track:\",\n error\n );\n throw error;\n }\n }\n\n /**\n * Publishes an audio track from the provided MediaStream to the LiveKit room.\n * This is an internal method. Only one audio track can be published at a time.\n *\n * @param mediaStream The MediaStream containing the audio track to publish\n * @private\n */\n private async publishAudioTrack(mediaStream: MediaStream): Promise<void> {\n if (!this.roomInstance) {\n throw new Error(\n \"[GPUMachineClient] Cannot publish track - not connected to room\"\n );\n }\n\n const audioTracks = mediaStream.getAudioTracks();\n if (audioTracks.length === 0) {\n throw new Error(\"[GPUMachineClient] No audio track found in MediaStream\");\n }\n\n // Unpublish existing audio track if any\n if (this.publishedAudioTrack) {\n await this.unpublishAudioTrack();\n }\n\n try {\n const audioTrack = audioTracks[0];\n const localAudioTrack =\n await this.roomInstance.localParticipant.publishTrack(audioTrack, {\n name: \"client-audio\",\n source: Track.Source.Microphone,\n });\n\n this.publishedAudioTrack = localAudioTrack.track as LocalAudioTrack;\n console.debug(\"[GPUMachineClient] Audio track published successfully\");\n } catch (error) {\n console.error(\"[GPUMachineClient] Failed to publish audio track:\", error);\n throw error;\n }\n }\n\n /**\n * Unpublishes the currently published audio track.\n * Note: We pass false to unpublishTrack to prevent LiveKit from stopping\n * the source MediaStreamTrack, as it's owned by the component that created it.\n * @private\n */\n private async unpublishAudioTrack(): Promise<void> {\n if (!this.roomInstance || !this.publishedAudioTrack) {\n return;\n }\n\n const publishedAudioTrack = this.publishedAudioTrack;\n this.publishedAudioTrack = undefined;\n\n try {\n await this.roomInstance.localParticipant.unpublishTrack(\n publishedAudioTrack,\n false // Don't stop the source track - it's managed externally\n );\n console.debug(\"[GPUMachineClient] Audio track unpublished successfully\");\n } catch (error) {\n console.error(\n \"[GPUMachineClient] Failed to unpublish audio track:\",\n error\n );\n throw error;\n }\n }\n}\n","import type {\n ApplicationMessage,\n InternalConnectionStatus,\n GPUMachineAssignmentData,\n} from \"./types\";\nimport type {\n ReactorEvent,\n ReactorStatus,\n ReactorState,\n ReactorError,\n ReactorWaitingInfo,\n ReactorSessionExpiration,\n} from \"../types\";\nimport { CoordinatorClient } from \"./CoordinatorClient\";\nimport { GPUMachineClient } from \"./GPUMachineClient\";\nimport { z } from \"zod\";\n\nconst LOCAL_COORDINATOR_URL = \"ws://localhost:8080/ws\";\nconst LOCAL_INSECURE_API_KEY = \"1234\";\nconst PROD_COORDINATOR_URL = \"wss://api.reactor.inc/ws\";\n\nconst OptionsSchema = z\n .object({\n directConnection: z\n .object({\n livekitJwtToken: z.string(),\n livekitWsUrl: z.string(),\n })\n .optional(),\n insecureApiKey: z.string().optional(),\n jwtToken: z.string().optional(),\n coordinatorUrl: z.string().default(PROD_COORDINATOR_URL),\n modelName: z.string(),\n queueing: z.boolean().default(false),\n local: z.boolean().default(false),\n })\n .refine(\n (data) =>\n data.directConnection ||\n data.insecureApiKey ||\n data.jwtToken ||\n data.local,\n {\n message:\n \"At least one of directConnection, insecureApiKey, or jwtToken or local must be provided.\",\n }\n );\nexport type Options = z.input<typeof OptionsSchema>;\n\ntype EventHandler = (...args: any[]) => void;\n\nexport class Reactor {\n private coordinatorClient: CoordinatorClient | undefined; //client for the coordinator\n private machineClient: GPUMachineClient | undefined; //client for the machine instance\n private status: ReactorStatus = \"disconnected\";\n private coordinatorUrl: string;\n private lastError?: ReactorError;\n private waitingInfo?: ReactorWaitingInfo;\n private jwtToken?: string;\n private insecureApiKey?: string;\n private directConnection?: {\n livekitJwtToken: string;\n livekitWsUrl: string;\n };\n private modelName: string;\n private modelVersion: string;\n private queueing: boolean;\n private sessionExpiration?: number;\n\n constructor(options: Options) {\n const validatedOptions = OptionsSchema.parse(options);\n this.coordinatorUrl = validatedOptions.coordinatorUrl;\n this.jwtToken = validatedOptions.jwtToken;\n this.insecureApiKey = validatedOptions.insecureApiKey;\n this.directConnection = validatedOptions.directConnection;\n this.modelName = validatedOptions.modelName;\n this.queueing = validatedOptions.queueing;\n // TODO: Use the model version from the options once we have a way to handle multiple versions\n this.modelVersion = \"1.0.0\";\n if (validatedOptions.local) {\n this.coordinatorUrl = LOCAL_COORDINATOR_URL;\n this.insecureApiKey = LOCAL_INSECURE_API_KEY;\n }\n }\n\n // Generic event map\n private eventListeners: Map<ReactorEvent, Set<EventHandler>> = new Map();\n\n // Event Emitter API\n on(event: ReactorEvent, handler: EventHandler) {\n if (!this.eventListeners.has(event)) {\n this.eventListeners.set(event, new Set());\n }\n this.eventListeners.get(event)!.add(handler);\n }\n\n off(event: ReactorEvent, handler: EventHandler) {\n this.eventListeners.get(event)?.delete(handler);\n }\n\n emit(event: ReactorEvent, ...args: any[]) {\n this.eventListeners.get(event)?.forEach((handler) => handler(...args));\n }\n\n /**\n * Public method to send a message to the machine.\n * Automatically wraps the message in an application message.\n * @param message The message to send to the machine.\n * @throws Error if not in ready state\n */\n async sendMessage(message: any): Promise<void> {\n // Synchronous validation - throw immediately\n if (process.env.NODE_ENV !== \"development\" && this.status !== \"ready\") {\n const errorMessage = `Cannot send message, status is ${this.status}`;\n console.error(\"[Reactor] Not ready, cannot send message\");\n throw new Error(errorMessage);\n }\n\n try {\n // Automatically wrap the user-message in an application message.\n const applicationMessage: ApplicationMessage = {\n type: \"application\",\n data: message,\n };\n await this.machineClient?.sendMessage(applicationMessage);\n } catch (error) {\n // Async operational error - emit event only\n console.error(\"[Reactor] Failed to send message:\", error);\n this.createError(\n \"MESSAGE_SEND_FAILED\",\n `Failed to send message: ${error}`,\n \"gpu\",\n true\n );\n // Don't re-throw - let the error event handle it\n }\n }\n\n /**\n * Public method to publish a video stream to the machine.\n * @param videoStream The video stream to send to the machine.\n */\n async publishVideoStream(videoStream: MediaStream): Promise<void> {\n // Synchronous validation - throw immediately\n if (process.env.NODE_ENV !== \"development\" && this.status !== \"ready\") {\n const errorMessage = `Cannot publish video stream, status is ${this.status}`;\n console.error(\"[Reactor] Not ready, cannot publish video stream\");\n throw new Error(errorMessage);\n }\n\n try {\n await this.machineClient?.publishVideoTrack(videoStream);\n } catch (error) {\n console.error(\"[Reactor] Failed to publish video:\", error);\n this.createError(\n \"VIDEO_PUBLISH_FAILED\",\n `Failed to publish video: ${error}`,\n \"gpu\",\n true\n );\n }\n }\n\n /**\n * Public method to unpublish video stream to the machine.\n * This unpublishes the video track that was previously sent.\n */\n async unpublishVideoStream(): Promise<void> {\n try {\n await this.machineClient?.unpublishVideoTrack();\n } catch (error) {\n console.error(\"[Reactor] Failed to unpublish video:\", error);\n this.createError(\n \"VIDEO_UNPUBLISH_FAILED\",\n `Failed to unpublish video: ${error}`,\n \"gpu\",\n true\n );\n }\n }\n\n /**\n * Connects to the machine via LiveKit and waits for the gpu machine to be ready.\n * Once the machine is ready, the Reactor will establish the LiveKit connection.\n * @param livekitJwtToken The JWT token for LiveKit authentication\n * @param livekitWsUrl The WebSocket URL for LiveKit connection\n */\n private async connectToGPUMachine(\n livekitJwtToken: string,\n livekitWsUrl: string\n ) {\n console.debug(\"[Reactor] Connecting to machine room...\");\n\n try {\n this.machineClient = new GPUMachineClient(livekitJwtToken, livekitWsUrl);\n\n this.machineClient.on(\"application\", (message: any) => {\n // escalate the message event through the instance, so that the user can listen to it.\n this.emit(\"newMessage\", message);\n });\n\n this.machineClient.on(\n \"statusChanged\",\n (status: InternalConnectionStatus) => {\n switch (status) {\n case \"connected\":\n this.setStatus(\"ready\");\n break;\n case \"disconnected\":\n // gpu machine has disconnected. Close any other connection to any other entity\n // such as the coordinator or the LiveKit connection.\n this.disconnect();\n break;\n case \"error\":\n // gpu machine has errored. Close any other connection to any other entity\n // such as the coordinator or the LiveKit connection.\n this.createError(\n \"GPU_CONNECTION_ERROR\",\n \"GPU machine connection failed\",\n \"gpu\",\n true\n );\n this.disconnect();\n break;\n }\n }\n );\n\n this.machineClient.on(\"fps\", (fps: number) => {\n this.emit(\"fps\", fps);\n });\n\n this.machineClient.on(\"streamChanged\", (videoTrack) => {\n this.emit(\"streamChanged\", videoTrack);\n });\n\n console.debug(\"[Reactor] About to connect to machine\");\n await this.machineClient.connect();\n } catch (error) {\n // For private methods, we can still throw since the caller will handle it appropriately\n throw error;\n }\n }\n\n /**\n * Connects to the coordinator and waits for a GPU to be assigned.\n * Once a GPU is assigned, the Reactor will connect to the gpu machine via LiveKit.\n */\n async connect(): Promise<void> {\n console.debug(\"[Reactor] Connecting, status:\", this.status);\n\n // Synchronous validation - throw immediately\n if (this.status !== \"disconnected\")\n throw new Error(\"Already connected or connecting\");\n\n if (this.directConnection) {\n return this.connectToGPUMachine(\n this.directConnection.livekitJwtToken,\n this.directConnection.livekitWsUrl\n );\n }\n\n this.setStatus(\"connecting\");\n\n try {\n console.debug(\n \"[Reactor] Connecting to coordinator with authenticated URL\"\n );\n\n this.coordinatorClient = new CoordinatorClient({\n wsUrl: this.coordinatorUrl,\n jwtToken: this.jwtToken,\n insecureApiKey: this.insecureApiKey,\n modelName: this.modelName,\n modelVersion: this.modelVersion,\n queueing: this.queueing,\n });\n\n this.coordinatorClient.on(\n \"gpu-machine-assigned\",\n async (assignmentData: GPUMachineAssignmentData) => {\n console.debug(\n \"[Reactor] GPU machine assigned by coordinator:\",\n assignmentData\n );\n try {\n await this.connectToGPUMachine(\n assignmentData.livekitJwtToken,\n assignmentData.livekitWsUrl\n );\n } catch (error) {\n console.error(\"[Reactor] Failed to connect to GPU machine:\", error);\n // Emit error event for async GPU connection failure\n this.createError(\n \"GPU_CONNECTION_FAILED\",\n `Failed to connect to GPU machine: ${error}`,\n \"gpu\",\n true\n );\n this.disconnect();\n }\n }\n );\n\n this.coordinatorClient.on(\n \"waiting-info\",\n (waitingData: ReactorWaitingInfo) => {\n console.debug(\"[Reactor] Waiting info update received:\", waitingData);\n // Update waiting info\n this.setWaitingInfo({\n ...this.waitingInfo,\n ...waitingData,\n });\n }\n );\n\n this.coordinatorClient.on(\n \"session-expiration\",\n (sessionExpirationData: ReactorSessionExpiration) => {\n this.setSessionExpiration(sessionExpirationData.expire);\n }\n );\n\n this.coordinatorClient.on(\n \"statusChanged\",\n (newStatus: InternalConnectionStatus) => {\n switch (newStatus) {\n case \"connected\":\n this.setStatus(\"waiting\");\n // Initialize waiting info when entering waiting state\n this.setWaitingInfo({\n position: undefined,\n estimatedWaitTime: undefined,\n averageWaitTime: undefined,\n });\n break;\n case \"disconnected\":\n this.disconnect();\n break;\n case \"error\":\n this.createError(\n \"COORDINATOR_CONNECTION_ERROR\",\n \"Coordinator connection failed\",\n \"coordinator\",\n true\n );\n this.disconnect();\n break;\n }\n }\n );\n\n await this.coordinatorClient.connect();\n } catch (error) {\n console.error(\"[Reactor] Authentication failed:\", error);\n this.createError(\n \"AUTHENTICATION_FAILED\",\n `Authentication failed: ${error}`,\n \"coordinator\",\n true\n );\n this.setStatus(\"disconnected\");\n // Keep throwing for authentication failures as these are immediate/sync failures\n throw error;\n }\n }\n\n /**\n * Disconnects from the coordinator and the gpu machine.\n * Ensures cleanup completes even if individual disconnections fail.\n */\n async disconnect() {\n if (this.status === \"disconnected\") return;\n\n // Disconnect coordinator client with error handling\n if (this.coordinatorClient) {\n try {\n this.coordinatorClient.disconnect();\n } catch (error) {\n console.error(\"[Reactor] Error disconnecting from coordinator:\", error);\n // Continue with cleanup even if coordinator disconnect fails\n }\n this.coordinatorClient = undefined;\n }\n\n // Disconnect machine client with error handling\n if (this.machineClient) {\n try {\n await this.machineClient.disconnect();\n } catch (error) {\n console.error(\"[Reactor] Error disconnecting from GPU machine:\", error);\n // Continue with cleanup even if machine disconnect fails\n }\n this.machineClient = undefined;\n }\n\n this.setStatus(\"disconnected\");\n this.setSessionExpiration(undefined);\n\n // Clear waiting info when disconnecting\n this.setWaitingInfo(undefined);\n }\n\n private setStatus(newStatus: ReactorStatus) {\n console.debug(\"[Reactor] Setting status:\", newStatus, \"from\", this.status);\n if (this.status !== newStatus) {\n this.status = newStatus;\n this.emit(\"statusChanged\", newStatus);\n }\n }\n\n private setWaitingInfo(newWaitingInfo: ReactorWaitingInfo | undefined) {\n console.debug(\n \"[Reactor] Setting waiting info:\",\n newWaitingInfo,\n \"from\",\n this.waitingInfo\n );\n if (this.waitingInfo !== newWaitingInfo) {\n this.waitingInfo = newWaitingInfo;\n this.emit(\"waitingInfoChanged\", newWaitingInfo);\n }\n }\n /**\n * Set the session expiration time.\n * @param newSessionExpiration The new session expiration time in seconds.\n */\n private setSessionExpiration(newSessionExpiration: number | undefined) {\n console.debug(\n \"[Reactor] Setting session expiration:\",\n newSessionExpiration\n );\n if (this.sessionExpiration !== newSessionExpiration) {\n this.sessionExpiration = newSessionExpiration;\n this.emit(\"sessionExpirationChanged\", newSessionExpiration);\n }\n }\n\n getStatus(): ReactorStatus {\n return this.status;\n }\n\n /**\n * Get the current state including status, error, and waiting info\n */\n getState(): ReactorState {\n return {\n status: this.status,\n waitingInfo: this.waitingInfo,\n lastError: this.lastError,\n };\n }\n\n /**\n * Get waiting information when status is 'waiting'\n */\n getWaitingInfo(): ReactorWaitingInfo | undefined {\n return this.waitingInfo;\n }\n\n /**\n * Get the last error that occurred\n */\n getLastError(): ReactorError | undefined {\n return this.lastError;\n }\n\n /**\n * Create and store an error\n */\n private createError(\n code: string,\n message: string,\n component: \"coordinator\" | \"gpu\" | \"livekit\",\n recoverable: boolean,\n retryAfter?: number\n ) {\n this.lastError = {\n code,\n message,\n timestamp: Date.now(),\n recoverable,\n component,\n retryAfter,\n };\n\n // Emit error event\n this.emit(\"error\", this.lastError);\n }\n}\n","\"use client\";\n\nimport { ReactNode, useContext, useEffect, useRef, useState } from \"react\";\nimport {\n createReactorStore,\n initReactorStore,\n ReactorContext,\n ReactorStore,\n ReactorStoreApi,\n type ReactorInitializationProps,\n} from \"../core/store\";\nimport { useStore } from \"zustand\";\n\n// Provider props\ninterface ReactorProviderProps extends ReactorInitializationProps {\n autoConnect?: boolean;\n children: ReactNode;\n}\n\n// tsx component\nexport function ReactorProvider({\n children,\n autoConnect = true,\n ...props\n}: ReactorProviderProps) {\n // Stable Reactor instance\n const storeRef = useRef<ReactorStoreApi | undefined>(undefined);\n const firstRender = useRef(true);\n // State to trigger re-renders when store changes\n const [_storeVersion, setStoreVersion] = useState(0);\n\n if (storeRef.current === undefined) {\n console.debug(\"[ReactorProvider] Creating new reactor store\");\n // We create the store without autoconnecting, to avoid duplicate connections.\n // We actually connect when the component is mounted, to be on sync with the react component lifecycle.\n storeRef.current = createReactorStore(initReactorStore(props));\n console.debug(\"[ReactorProvider] Reactor store created successfully\");\n }\n\n // Fan out props to individual variables so that the\n // useEffect hook can be optimized by only re-running when the\n // props that actually change.\n const {\n coordinatorUrl,\n modelName,\n jwtToken,\n insecureApiKey,\n directConnection,\n queueing,\n local,\n } = props;\n\n useEffect(() => {\n if (firstRender.current) {\n firstRender.current = false;\n\n // We know as a fact that the store is not undefined at this point\n const current = storeRef.current!;\n if (autoConnect && current.getState().status === \"disconnected\") {\n console.debug(\n \"[ReactorProvider] Starting autoconnect in first render...\"\n );\n current\n .getState()\n .connect()\n .then(() => {\n console.debug(\n \"[ReactorProvider] Autoconnect successful in first render\"\n );\n })\n .catch((error) => {\n console.error(\n \"[ReactorProvider] Failed to autoconnect in first render:\",\n error\n );\n });\n }\n return () => {\n console.debug(\n \"[ReactorProvider] Disconnecting in cleanup for first render\"\n );\n current\n .getState()\n .disconnect()\n .then(() => {\n console.debug(\n \"[ReactorProvider] Disconnect completed successfully in cleanup for first render\"\n );\n })\n .catch((error) => {\n console.error(\n \"[ReactorProvider] Failed to disconnect in cleanup for first render:\",\n error\n );\n });\n };\n }\n\n console.debug(\"[ReactorProvider] Updating reactor store\");\n storeRef.current = createReactorStore(\n initReactorStore({\n coordinatorUrl,\n modelName,\n jwtToken,\n insecureApiKey,\n directConnection,\n queueing,\n local,\n } satisfies ReactorInitializationProps)\n );\n\n // Store current reference to the store in the return\n const current = storeRef.current!;\n\n // Increment version to trigger re-render and propagate new store to Provider\n setStoreVersion((v) => v + 1);\n console.debug(\n \"[ReactorProvider] Reactor store updated successfully, and increased version\"\n );\n\n if (autoConnect && current.getState().status === \"disconnected\") {\n console.debug(\"[ReactorProvider] Starting autoconnect...\");\n current\n .getState()\n .connect()\n .then(() => {\n console.debug(\"[ReactorProvider] Autoconnect successful\");\n })\n .catch((error) => {\n console.error(\"[ReactorProvider] Failed to autoconnect:\", error);\n });\n }\n\n return () => {\n console.debug(\"[ReactorProvider] Disconnecting in cleanup\");\n current\n .getState()\n .disconnect()\n .then(() => {\n console.debug(\n \"[ReactorProvider] Disconnect completed successfully in cleanup\"\n );\n })\n .catch((error) => {\n console.error(\"[ReactorProvider] Failed to disconnect:\", error);\n });\n };\n }, [\n coordinatorUrl,\n modelName,\n jwtToken,\n insecureApiKey,\n directConnection,\n queueing,\n autoConnect,\n local,\n ]);\n\n return (\n <ReactorContext.Provider value={storeRef.current}>\n {children}\n </ReactorContext.Provider>\n );\n}\n\nexport function useReactorStore<T = ReactorStore>(\n selector: (state: ReactorStore) => T\n): T {\n const ctx = useContext(ReactorContext);\n if (!ctx) {\n throw new Error(\"useReactor must be used within a ReactorProvider\");\n }\n\n return useStore(ctx, selector);\n}\n","import { StoreApi } from \"zustand\";\nimport type { ReactorStatus, ReactorWaitingInfo, ReactorError } from \"../types\";\nimport { Reactor, type Options as ReactorOptions } from \"./Reactor\";\nimport { create } from \"zustand/react\";\nimport { createContext } from \"react\";\nimport type { RemoteVideoTrack } from \"livekit-client\";\n\nexport type ReactorStoreApi = ReturnType<typeof createReactorStore>;\n\nexport interface ReactorState {\n status: ReactorStatus;\n videoTrack: RemoteVideoTrack | null;\n //These are the machine FPS. The machine internally reports to the client the rate at which the frames are\n //being generated. This can be useful for the client to calcolate at which rate to run commands.\n fps?: number;\n waitingInfo?: ReactorWaitingInfo;\n lastError?: ReactorError;\n sessionExpiration?: number;\n}\n\nexport interface ReactorActions {\n sendMessage(message: any): Promise<void>;\n connect(): Promise<void>;\n disconnect(): Promise<void>;\n publishVideoStream(stream: MediaStream): Promise<void>;\n unpublishVideoStream(): Promise<void>;\n}\n\n// Internal state not exposed to components\ninterface ReactorInternalState {\n reactor: Reactor;\n}\n\nexport const ReactorContext = createContext<ReactorStoreApi | undefined>(\n undefined\n);\n\nexport type ReactorStore = ReactorState &\n ReactorActions & {\n internal: ReactorInternalState;\n };\n\nexport const defaultInitState: ReactorState = {\n status: \"disconnected\",\n videoTrack: null,\n fps: undefined,\n waitingInfo: undefined,\n lastError: undefined,\n sessionExpiration: undefined,\n};\n\nexport interface ReactorInitializationProps extends ReactorOptions {}\n\nexport const initReactorStore = (\n props: ReactorInitializationProps\n): ReactorState & ReactorInitializationProps => {\n return {\n ...defaultInitState,\n // These are only used for dev initialization, not exposed in the store\n ...props,\n };\n};\n\nexport const createReactorStore = (\n initProps: ReactorInitializationProps,\n publicState: ReactorState = defaultInitState\n): StoreApi<ReactorStore> => {\n console.debug(\"[ReactorStore] Creating store\", {\n coordinatorUrl: initProps.coordinatorUrl,\n initialState: publicState,\n });\n\n return create<ReactorStore>()((set, get) => {\n const reactor = new Reactor(initProps);\n\n console.debug(\"[ReactorStore] Setting up event listeners\");\n\n reactor.on(\"statusChanged\", (newStatus: ReactorStatus) => {\n console.debug(\"[ReactorStore] Status changed\", {\n oldStatus: get().status,\n newStatus,\n });\n set({ status: newStatus });\n });\n\n reactor.on(\"waitingInfoChanged\", (newWaitingInfo: ReactorWaitingInfo | undefined) => {\n console.debug(\"[ReactorStore] Waiting info changed\", {\n oldWaitingInfo: get().waitingInfo,\n newWaitingInfo: newWaitingInfo,\n });\n set({ waitingInfo: newWaitingInfo });\n });\n\n reactor.on(\"sessionExpirationChanged\", (newSessionExpiration: number | undefined) => {\n console.debug(\"[ReactorStore] Session expiration changed\", {\n oldSessionExpiration: get().sessionExpiration,\n newSessionExpiration: newSessionExpiration,\n });\n set({ sessionExpiration: newSessionExpiration });\n });\n\n reactor.on(\"streamChanged\", (videoTrack: RemoteVideoTrack | null) => {\n console.debug(\"[ReactorStore] Stream changed\", {\n hasVideoTrack: !!videoTrack,\n videoTrackKind: videoTrack?.kind,\n videoTrackSid: videoTrack?.sid,\n });\n set({ videoTrack: videoTrack });\n });\n\n reactor.on(\"fps\", (fps: number) => {\n console.debug(\"[ReactorStore] FPS updated\", { fps });\n set({ fps: fps });\n });\n\n reactor.on(\"error\", (error: ReactorError) => {\n console.debug(\"[ReactorStore] Error occurred\", error);\n set({ lastError: error });\n });\n\n return {\n ...publicState,\n internal: { reactor },\n\n // actions\n onMessage: (handler: (message: any) => void) => {\n console.debug(\"[ReactorStore] Registering message handler\");\n\n // Simply register the handler\n get().internal.reactor.on(\"newMessage\", handler);\n\n // Return a cleanup function that can be called to unregister\n return () => {\n console.debug(\"[ReactorStore] Cleaning up message handler\");\n get().internal.reactor.off(\"newMessage\", handler);\n };\n },\n sendMessage: async (mess: any) => {\n console.debug(\"[ReactorStore] Sending message\", { message: mess });\n\n try {\n await get().internal.reactor.sendMessage(mess);\n console.debug(\"[ReactorStore] Message sent successfully\");\n } catch (error) {\n console.error(\"[ReactorStore] Failed to send message:\", error);\n throw error;\n }\n },\n connect: async () => {\n console.debug(\"[ReactorStore] Connect called\");\n\n try {\n await get().internal.reactor.connect();\n console.debug(\"[ReactorStore] Connect completed successfully\");\n } catch (error) {\n console.error(\"[ReactorStore] Connect failed:\", error);\n throw error;\n }\n },\n disconnect: async () => {\n console.debug(\"[ReactorStore] Disconnect called\", {\n currentStatus: get().status,\n });\n\n try {\n await get().internal.reactor.disconnect();\n console.debug(\"[ReactorStore] Disconnect completed successfully\");\n } catch (error) {\n console.error(\"[ReactorStore] Disconnect failed:\", error);\n throw error;\n }\n },\n publishVideoStream: async (stream: MediaStream) => {\n console.debug(\"[ReactorStore] Publishing video stream\");\n\n try {\n await get().internal.reactor.publishVideoStream(stream);\n console.debug(\"[ReactorStore] Video stream published successfully\");\n } catch (error) {\n console.error(\n \"[ReactorStore] Failed to publish video stream:\",\n error\n );\n throw error;\n }\n },\n unpublishVideoStream: async () => {\n console.debug(\"[ReactorStore] Unpublishing video stream\");\n\n try {\n await get().internal.reactor.unpublishVideoStream();\n console.debug(\"[ReactorStore] Video stream unpublished successfully\");\n } catch (error) {\n console.error(\n \"[ReactorStore] Failed to unpublish video stream:\",\n error\n );\n throw error;\n }\n },\n };\n });\n};\n","import { useReactorStore } from \"./ReactorProvider\";\nimport type { ReactorStore } from \"../core/store\";\nimport { useShallow } from \"zustand/shallow\";\nimport { useEffect, useRef } from \"react\";\n\n/**\n * Generic hook for accessing selected parts of the Reactor store.\n *\n * @param selector - A function that selects part of the store state.\n * @returns The selected slice from the store.\n */\nexport function useReactor<T>(selector: (state: ReactorStore) => T): T {\n return useReactorStore(useShallow(selector));\n}\n\n/**\n * Hook for handling message subscriptions with proper React lifecycle management.\n *\n * @param handler - The message handler function\n */\nexport function useReactorMessage(handler: (message: any) => void): void {\n const reactor = useReactor((state) => state.internal.reactor);\n const handlerRef = useRef(handler);\n\n // Update the ref when handler changes\n useEffect(() => {\n handlerRef.current = handler;\n }, [handler]);\n\n useEffect(() => {\n console.debug(\"[useReactorMessage] Setting up message subscription\");\n\n // Create a stable handler that calls the current ref\n const stableHandler = (message: any) => {\n console.debug(\"[useReactorMessage] Message received\", { message });\n handlerRef.current(message);\n };\n\n // Register the handler and get the cleanup function\n reactor.on(\"newMessage\", stableHandler);\n\n console.debug(\"[useReactorMessage] Message handler registered\");\n\n // Return the cleanup function\n return () => {\n console.debug(\"[useReactorMessage] Cleaning up message subscription\");\n reactor.off(\"newMessage\", stableHandler);\n };\n }, [reactor]);\n}\n","\"use client\";\n\nimport { useReactor } from \"./hooks\";\nimport { useEffect, useRef } from \"react\";\nimport React from \"react\";\n\nexport interface ReactorViewProps {\n width?: number;\n height?: number;\n className?: string;\n style?: React.CSSProperties;\n videoObjectFit?: NonNullable<\n React.VideoHTMLAttributes<HTMLVideoElement>[\"style\"]\n >[\"objectFit\"];\n}\n\nexport function ReactorView({\n width,\n height,\n className,\n style,\n videoObjectFit = \"contain\",\n}: ReactorViewProps) {\n const { videoTrack, status } = useReactor((state) => ({\n videoTrack: state.videoTrack,\n status: state.status,\n }));\n\n const videoRef = useRef<HTMLVideoElement>(null);\n\n useEffect(() => {\n console.debug(\"[ReactorView] Video track effect triggered\", {\n hasVideoElement: !!videoRef.current,\n hasVideoTrack: !!videoTrack,\n videoTrackKind: videoTrack?.kind,\n });\n\n if (videoRef.current && videoTrack) {\n console.debug(\"[ReactorView] Attaching video track to element\");\n try {\n // Attach the LiveKit track to the video element\n videoTrack.attach(videoRef.current);\n console.debug(\"[ReactorView] Video track attached successfully\");\n } catch (error) {\n console.error(\"[ReactorView] Failed to attach video track:\", error);\n }\n\n // Cleanup: detach when track changes or component unmounts\n return () => {\n console.debug(\"[ReactorView] Detaching video track from element\");\n if (videoRef.current) {\n try {\n videoTrack.detach(videoRef.current);\n console.debug(\"[ReactorView] Video track detached successfully\");\n } catch (error) {\n console.error(\"[ReactorView] Failed to detach video track:\", error);\n }\n }\n };\n } else {\n console.debug(\"[ReactorView] No video track or element to attach\");\n }\n }, [videoTrack]);\n\n const showPlaceholder = !videoTrack;\n\n return (\n <div\n style={{\n position: \"relative\",\n background: \"#000\",\n ...(width && { width }),\n ...(height && { height }),\n ...style,\n }}\n className={className}\n >\n <video\n ref={videoRef}\n style={{\n width: \"100%\",\n height: \"100%\",\n objectFit: videoObjectFit,\n display: showPlaceholder ? \"none\" : \"block\",\n }}\n muted\n playsInline\n />\n {showPlaceholder && (\n <div\n style={{\n position: \"absolute\",\n top: 0,\n left: 0,\n width: \"100%\",\n height: \"100%\",\n color: \"#fff\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n fontSize: \"16px\",\n fontFamily: \"monospace\",\n textAlign: \"center\",\n padding: \"20px\",\n boxSizing: \"border-box\",\n }}\n >\n {status}\n </div>\n )}\n </div>\n );\n}\n","\"use client\";\n\nimport { useReactor } from \"./hooks\";\nimport { useEffect, useRef, useState } from \"react\";\nimport React from \"react\";\n\ninterface Props {\n className?: string;\n style?: React.CSSProperties;\n videoConstraints?: MediaTrackConstraints;\n showWebcam?: boolean;\n videoObjectFit?: NonNullable<\n React.VideoHTMLAttributes<HTMLVideoElement>[\"style\"]\n >[\"objectFit\"];\n}\n\nexport function WebcamStream({\n className,\n style,\n videoConstraints = {\n width: { ideal: 1280 },\n height: { ideal: 720 },\n },\n showWebcam = true,\n videoObjectFit = \"contain\",\n}: Props) {\n const [stream, setStream] = useState<MediaStream | null>(null);\n const [isPublishing, setIsPublishing] = useState(false);\n const [permissionDenied, setPermissionDenied] = useState(false);\n\n const { status, publishVideoStream, unpublishVideoStream, reactor } =\n useReactor((state) => ({\n status: state.status,\n publishVideoStream: state.publishVideoStream,\n unpublishVideoStream: state.unpublishVideoStream,\n reactor: state.internal.reactor,\n }));\n\n const videoRef = useRef<HTMLVideoElement>(null);\n\n // Start webcam\n const startWebcam = async () => {\n console.debug(\"[WebcamPublisher] Starting webcam\");\n\n try {\n const mediaStream = await navigator.mediaDevices.getUserMedia({\n video: videoConstraints,\n audio: false,\n });\n\n console.debug(\"[WebcamPublisher] Webcam started successfully\");\n setStream(mediaStream);\n setPermissionDenied(false);\n } catch (err) {\n console.error(\"[WebcamPublisher] Failed to start webcam:\", err);\n\n // Check if the error is a permission denial\n if (\n err instanceof DOMException &&\n (err.name === \"NotAllowedError\" || err.name === \"PermissionDeniedError\")\n ) {\n console.debug(\"[WebcamPublisher] Camera permission denied\");\n setPermissionDenied(true);\n }\n }\n };\n\n // Stop webcam\n const stopWebcam = async () => {\n console.debug(\"[WebcamPublisher] Stopping webcam\");\n\n // Unpublish if currently publishing\n try {\n await unpublishVideoStream();\n console.debug(\"[WebcamPublisher] Unpublished before stopping\");\n } catch (err) {\n console.error(\"[WebcamPublisher] Error unpublishing before stop:\", err);\n }\n\n setIsPublishing(false);\n\n // Stop all tracks\n stream?.getTracks().forEach((track) => {\n track.stop();\n console.debug(\"[WebcamPublisher] Stopped track:\", track.kind);\n });\n setStream(null);\n\n console.debug(\"[WebcamPublisher] Webcam stopped\");\n };\n\n // Attach stream to video element\n useEffect(() => {\n console.debug(\"[WebcamPublisher] Stream effect triggered\", {\n hasVideoElement: !!videoRef.current,\n hasStream: !!stream,\n });\n\n if (!videoRef.current) {\n return;\n }\n\n if (stream) {\n console.debug(\"[WebcamPublisher] Attaching stream to video element\");\n videoRef.current.srcObject = stream;\n console.debug(\"[WebcamPublisher] Stream attached successfully\");\n } else {\n console.debug(\"[WebcamPublisher] Clearing video element\");\n videoRef.current.srcObject = null;\n }\n }, [stream]);\n\n // Auto-publish when reactor is ready and webcam is active\n useEffect(() => {\n if (!stream) {\n return;\n }\n\n if (status === \"ready\" && !isPublishing) {\n console.debug(\n \"[WebcamPublisher] Reactor ready, auto-publishing webcam stream\"\n );\n publishVideoStream(stream)\n .then(() => {\n console.debug(\"[WebcamPublisher] Auto-publish successful\");\n setIsPublishing(true);\n })\n .catch((err) => {\n console.error(\"[WebcamPublisher] Auto-publish failed:\", err);\n });\n } else if (status !== \"ready\" && isPublishing) {\n console.debug(\"[WebcamPublisher] Reactor not ready, auto-unpublishing\");\n unpublishVideoStream()\n .then(() => {\n console.debug(\"[WebcamPublisher] Auto-unpublish successful\");\n setIsPublishing(false);\n })\n .catch((err) => {\n console.error(\"[WebcamPublisher] Auto-unpublish failed:\", err);\n });\n }\n }, [status, stream, isPublishing, publishVideoStream, unpublishVideoStream]);\n\n // Listen for error events from Reactor\n useEffect(() => {\n const handleError = (error: any) => {\n console.debug(\"[WebcamPublisher] Received error event:\", error);\n\n // Handle video publish failures by resetting state\n if (error.code === \"VIDEO_PUBLISH_FAILED\") {\n console.debug(\n \"[WebcamPublisher] Video publish failed, resetting isPublishing state\"\n );\n setIsPublishing(false);\n }\n };\n\n reactor.on(\"error\", handleError);\n\n return () => {\n reactor.off(\"error\", handleError);\n };\n }, [reactor]);\n\n // Reset publishing state when status changes away from ready\n useEffect(() => {\n if (status !== \"ready\") {\n console.debug(\n \"[WebcamPublisher] Status changed to\",\n status,\n \"- resetting isPublishing state\"\n );\n setIsPublishing(false);\n }\n }, [status, isPublishing]);\n\n // Auto-start webcam on mount and cleanup on unmount\n useEffect(() => {\n console.debug(\"[WebcamPublisher] Auto-starting webcam\");\n startWebcam();\n\n return () => {\n console.debug(\"[WebcamPublisher] Cleanup on unmount\");\n stopWebcam();\n };\n }, []); // eslint-disable-line react-hooks/exhaustive-deps\n\n const showPlaceholder = !stream;\n\n return (\n <div\n style={{\n display: showWebcam ? \"block\" : \"none\",\n position: \"relative\",\n background: \"#000\",\n ...style,\n }}\n className={className}\n >\n <video\n ref={videoRef}\n style={{\n width: \"100%\",\n height: \"100%\",\n objectFit: videoObjectFit,\n display: showPlaceholder ? \"none\" : \"block\",\n }}\n muted\n playsInline\n autoPlay\n />\n {showPlaceholder && (\n <div\n style={{\n position: \"absolute\",\n top: 0,\n left: 0,\n width: \"100%\",\n height: \"100%\",\n color: \"#fff\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n fontSize: \"16px\",\n fontFamily: \"monospace\",\n textAlign: \"center\",\n padding: \"20px\",\n boxSizing: \"border-box\",\n flexDirection: \"column\",\n gap: \"12px\",\n }}\n >\n {permissionDenied ? (\n <div style={{ fontSize: \"12px\", fontFamily: \"monospace\" }}>\n Camera access denied.\n <br />\n Please allow access in your browser settings.\n </div>\n ) : (\n <div style={{ fontSize: \"12px\", fontFamily: \"monospace\" }}>\n Starting camera...\n </div>\n )}\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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","names":["z","z","_a","z","OptionsSchema","z","current","useEffect","useRef","useEffect","useRef","jsx","useRef","useEffect","useEffect","useRef","useState","jsx","jsxs","useState","useRef","useEffect"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reactor-team/js-sdk",
3
- "version": "1.0.15",
3
+ "version": "1.0.16",
4
4
  "description": "Reactor JavaScript frontend SDK",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",