refactor(simulator): enhance mobile simulator UI with updated styles, improved security policies, and WebRTC signaling support

This commit is contained in:
2026-02-03 11:00:00 +00:00
parent f1919ca0e1
commit a2f6a22f97
5 changed files with 1184 additions and 790 deletions

View File

@@ -19,6 +19,13 @@ const commandAckSchema = z.object({
error: z.string().optional(),
});
const webrtcSignalSchema = z.object({
toDeviceId: z.string().uuid(),
streamSessionId: z.string().uuid(),
signalType: z.enum(['offer', 'answer', 'candidate', 'hangup']),
data: z.record(z.string(), z.unknown()).nullable().optional(),
});
const roomForDevice = (deviceId: string): string => `device:${deviceId}`;
let io: SocketIOServer | null = null;
@@ -286,6 +293,34 @@ export const setupRealtimeGateway = (server: HttpServer): SocketIOServer => {
});
});
socket.on('webrtc:signal', async (input) => {
const parsed = webrtcSignalSchema.safeParse(input);
if (!parsed.success) {
socket.emit('error:webrtc_signal', {
message: 'Invalid WebRTC signal payload',
errors: parsed.error.flatten(),
});
return;
}
const targetDevice = await db.query.devices.findFirst({
where: and(eq(devices.id, parsed.data.toDeviceId), eq(devices.userId, auth.userId)),
});
if (!targetDevice) {
socket.emit('error:webrtc_signal', { message: 'Target device not found for this account' });
return;
}
io?.to(roomForDevice(parsed.data.toDeviceId)).emit('webrtc:signal', {
fromDeviceId: auth.deviceId,
streamSessionId: parsed.data.streamSessionId,
signalType: parsed.data.signalType,
data: parsed.data.data ?? null,
});
});
socket.on('disconnect', async () => {
// Small delay allows fast reconnects to reuse presence without flapping.
setTimeout(async () => {