Skip to content

Instantly share code, notes, and snippets.

@iamandrewluca
Created February 22, 2023 22:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save iamandrewluca/5896afda80ff0648ea3df1988c37d387 to your computer and use it in GitHub Desktop.
Save iamandrewluca/5896afda80ff0648ea3df1988c37d387 to your computer and use it in GitHub Desktop.
Zod message protoco
import { z } from 'zod'
function createMessageProtocol<T extends z.ZodObject<{ type: z.ZodLiteral<string> }>>(events: T[]) {
// Add types from Zod
function createSender(fn: (data: any) => void) {
return (data: any) => fn(data)
}
// extract event types somehow
let types = events.map((e) => e.shape.type._type)
function createReceiver(getter: any) {
let subscribers: unknown[] = []
let unsubscribe = getter((data: any) => subscribers.forEach((s: any) => s(data)))
// Add types from Zod
return (fn: any) => {
subscribers.push(fn)
return () => {
subscribers = subscribers.filter(s => s !== fn)
if (subscribers.length === 0) unsubscribe()
}
}
}
return { createSender, createReceiver, types }
}
let messageProtocol = createMessageProtocol([
z.object({
type: z.literal("LOG_IN"),
username: z.string(),
password: z.string(),
}),
z.object({
type: z.literal("LOG_OUT")
}),
])
let socket = new WebSocket('')
let send1 = messageProtocol.createSender((data) => socket.send(JSON.stringify(data)))
send1({ type: 'LOG_IN', username: '', pass: '' })
let receive1 = messageProtocol.createReceiver((send: any) => {
let cb = (e: any) => send(e.data)
socket.addEventListener('message', cb)
return () => socket.removeEventListener('message', cb)
})
let unsubscribe1 = receive1((data: any) => console.log(data))
unsubscribe1()
let window = globalThis.window
let send2 = messageProtocol.createSender(data => window.postMessage(data))
send2({ type: 'LOG_IN', username: '', pass: '' })
let receive2 = messageProtocol.createReceiver((send: any) => {
let cb = (e: any) => send(e.data)
window.addEventListener('message', cb)
return () => window.removeEventListener('message', cb)
})
let unsubscribe2 = receive2((data: any) => console.log(data))
unsubscribe2()
let element = document.createElement('button')
let send3 = messageProtocol.createSender(data => element.dispatchEvent(new CustomEvent(data.type, { detail: data })))
send3({ type: 'LOG_IN', username: '', pass: '' })
let receive3 = messageProtocol.createReceiver((send: any) => {
let cb = (e: any) => send((e as CustomEvent).detail)
messageProtocol.types.forEach(messageType => element.addEventListener(messageType, cb))
return () => messageProtocol.types.forEach(messageType => element.removeEventListener(messageType, cb))
})
let unsubscribe3 = receive3((data: any) => console.log(data))
unsubscribe3()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment