Initial commit
This commit is contained in:
149
client/src/network/protocol.ts
Normal file
149
client/src/network/protocol.ts
Normal file
@@ -0,0 +1,149 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
export const itemSchema = z.object({
|
||||
id: z.string(),
|
||||
type: z.enum(['radio_station', 'dice']),
|
||||
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<typeof incomingMessageSchema>;
|
||||
|
||||
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' }
|
||||
| { 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<string, unknown>;
|
||||
};
|
||||
|
||||
export type RemoteUser = {
|
||||
id: string;
|
||||
nickname: string;
|
||||
x: number;
|
||||
y: number;
|
||||
};
|
||||
Reference in New Issue
Block a user