import { z } from "zod"; import { safeJsonParse } from "~/server/utils/json"; const backupCommandSchema = z .object({ type: z.literal("backup"), payload: z.object({ scheduleId: z.string() }), }) .strict(); const agentReadySchema = z .object({ type: z.literal("agent.ready"), payload: z.object({ agentId: z.string() }), }) .strict(); const backupStartedSchema = z .object({ type: z.literal("backup.started"), payload: z.object({ scheduleId: z.string() }), }) .strict(); const controllerMessageSchema = z.discriminatedUnion("type", [backupCommandSchema]); const agentMessageSchema = z.discriminatedUnion("type", [agentReadySchema, backupStartedSchema]); export type BackupCommandPayload = z.infer["payload"]; export type ControllerMessage = z.infer; export type AgentMessage = z.infer; type Brand = TValue & { readonly __brand: TBrand; }; type MessageSender = { send(message: string): unknown; }; export type ControllerWireMessage = Brand; export type AgentWireMessage = Brand; type PayloadForMessage = Extract< TMessage, { type: TType } >["payload"]; const parseJsonMessage = (data: string) => safeJsonParse(data); export const parseControllerMessage = (data: ControllerWireMessage) => { const parsed = parseJsonMessage(data); if (parsed === null) { return null; } return controllerMessageSchema.safeParse(parsed); }; export const parseAgentMessage = (data: string) => { const parsed = parseJsonMessage(data); if (parsed === null) { return null; } return agentMessageSchema.safeParse(parsed); }; export const createControllerMessage = ( type: TType, payload: PayloadForMessage, ) => JSON.stringify( controllerMessageSchema.parse({ type, payload, }), ) as ControllerWireMessage; export const createAgentMessage = ( type: TType, payload: PayloadForMessage, ) => JSON.stringify( agentMessageSchema.parse({ type, payload, }), ) as AgentWireMessage; export const sendControllerMessage = (target: MessageSender, message: ControllerWireMessage) => { target.send(message); }; export const sendAgentMessage = (target: MessageSender, message: AgentWireMessage) => { target.send(message); }; export type ControllerData = MessageEvent;