import { z } from 'zod'; export const itemSchema = z.object({ id: z.string(), type: z.enum(['radio_station', 'dice', 'wheel']), title: z.string(), x: z.number().int(), y: z.number().int(), createdBy: z.string(), createdAt: z.number().int(), updatedAt: z.number().int(), version: z.number().int(), capabilities: z.array(z.string()), useSound: z.string().optional(), params: z.record(z.string(), z.unknown()), carrierId: z.string().nullable().optional(), }); export const welcomeMessageSchema = z.object({ type: z.literal('welcome'), id: z.string(), users: z.array( z.object({ id: z.string(), nickname: z.string(), x: z.number().int(), y: z.number().int(), }), ), items: z.array(itemSchema).optional(), }); export const signalMessageSchema = z.object({ type: z.literal('signal'), senderId: z.string(), senderNickname: z.string().optional(), x: z.number().int().optional(), y: z.number().int().optional(), targetId: z.string().optional(), sdp: z.any().optional(), ice: z.any().optional(), }); export const updatePositionSchema = z.object({ type: z.literal('update_position'), id: z.string(), x: z.number().int(), y: z.number().int(), }); export const updateNicknameSchema = z.object({ type: z.literal('update_nickname'), id: z.string(), nickname: z.string().min(1).max(32), }); export const userLeftSchema = z.object({ type: z.literal('user_left'), id: z.string(), }); export const chatMessageSchema = z.object({ type: z.literal('chat_message'), message: z.string(), senderId: z.string().optional(), senderNickname: z.string().optional(), system: z.boolean().optional(), }); export const pongSchema = z.object({ type: z.literal('pong'), clientSentAt: z.number().int(), }); export const nicknameResultSchema = z.object({ type: z.literal('nickname_result'), accepted: z.boolean(), requestedNickname: z.string(), effectiveNickname: z.string(), reason: z.string().optional(), }); export const itemUpsertSchema = z.object({ type: z.literal('item_upsert'), item: itemSchema, }); export const itemRemoveSchema = z.object({ type: z.literal('item_remove'), itemId: z.string(), }); export const itemActionResultSchema = z.object({ type: z.literal('item_action_result'), ok: z.boolean(), action: z.enum(['add', 'pickup', 'drop', 'delete', 'use', 'update']), message: z.string(), itemId: z.string().optional(), }); export const itemUseSoundSchema = z.object({ type: z.literal('item_use_sound'), itemId: z.string(), sound: z.string(), x: z.number().int(), y: z.number().int(), }); export const incomingMessageSchema = z.discriminatedUnion('type', [ welcomeMessageSchema, signalMessageSchema, updatePositionSchema, updateNicknameSchema, userLeftSchema, chatMessageSchema, pongSchema, nicknameResultSchema, itemUpsertSchema, itemRemoveSchema, itemActionResultSchema, itemUseSoundSchema, ]); export type IncomingMessage = z.infer; export type OutgoingMessage = | { type: 'signal'; targetId: string; sdp?: RTCSessionDescriptionInit; ice?: RTCIceCandidateInit } | { type: 'update_position'; x: number; y: number } | { type: 'update_nickname'; nickname: string } | { type: 'chat_message'; message: string } | { type: 'ping'; clientSentAt: number } | { type: 'item_add'; itemType: 'radio_station' | 'dice' | 'wheel' } | { type: 'item_pickup'; itemId: string } | { type: 'item_drop'; itemId: string; x: number; y: number } | { type: 'item_delete'; itemId: string } | { type: 'item_use'; itemId: string } | { type: 'item_update'; itemId: string; title?: string; params?: Record; }; export type RemoteUser = { id: string; nickname: string; x: number; y: number; };