File
Blob: worker/src/shared/contracts/signaling.ts
| 1 | import { z } from 'zod'; |
| 2 | import { nowPlayingSchema, trackSchema } from './track.ts'; |
| 3 | |
| 4 | const count = z.number().int().nonnegative(); |
| 5 | export const descriptionSchema = z.object({ |
| 6 | type: z.enum(['offer', 'answer']), |
| 7 | sdp: z.string().max(16000).startsWith('v=0'), |
| 8 | }); |
| 9 | export const offerSchema = descriptionSchema.extend({ type: z.literal('offer') }); |
| 10 | export const answerSchema = descriptionSchema.extend({ type: z.literal('answer') }); |
| 11 | export const deviceStartSchema = z |
| 12 | .object({ |
| 13 | sessionDescription: offerSchema, |
| 14 | track: trackSchema.nullish(), |
| 15 | nowPlaying: nowPlayingSchema.optional(), |
| 16 | bootId: z |
| 17 | .string() |
| 18 | .regex(/^[a-f0-9]{32}$/) |
| 19 | .optional(), |
| 20 | }) |
| 21 | .strict(); |
| 22 | export const generationSchema = z.object({ generation: z.uuid() }).strict(); |
| 23 | export const deviceHeartbeatSchema = generationSchema.extend({ |
| 24 | nowPlaying: nowPlayingSchema.optional(), |
| 25 | }); |
| 26 | export const loginSchema = z.object({ password: z.string().min(1).max(256) }).strict(); |
| 27 | export const emptySchema = z.object({}).strict(); |
| 28 | export const answerInputSchema = z.object({ sessionDescription: answerSchema }).strict(); |
| 29 | export const leaveSchema = z.object({ viewerToken: z.uuid().optional() }).strict(); |
| 30 | export const viewerKeySchema = z.object({ id: z.uuid(), token: z.uuid() }); |
| 31 | export const statusSchema = z.object({ |
| 32 | online: z.boolean(), |
| 33 | viewers: count, |
| 34 | controller: z.string().nullable(), |
| 35 | generation: z.string().nullable(), |
| 36 | track: trackSchema.nullish(), |
| 37 | nowPlaying: nowPlayingSchema.nullish(), |
| 38 | }); |
| 39 | export const joinedSchema = z.object({ |
| 40 | id: z.uuid(), |
| 41 | viewerToken: z.uuid(), |
| 42 | generation: z.uuid(), |
| 43 | sessionDescription: offerSchema, |
| 44 | }); |
| 45 | export const controllerSchema = z.object({ controller: z.string().nullable() }); |
| 46 | export const okSchema = z.object({ ok: z.literal(true) }); |
| 47 | export const audioResponseSchema = z.object({ sessionDescription: offerSchema }); |
| 48 | |
| 49 | export type Description = z.infer<typeof descriptionSchema>; |
| 50 | export type DeviceStart = z.infer<typeof deviceStartSchema>; |
| 51 | export type ViewerKey = z.infer<typeof viewerKeySchema>; |
| 52 | export type Joined = z.infer<typeof joinedSchema>; |
| 53 | export type RoomStatus = z.infer<typeof statusSchema>; |
| 54 | export type Answer = z.infer<typeof answerSchema>; |
| 55 | export type ViewerCredentials = Pick<Joined, 'id' | 'viewerToken'>; |