Typed Channels

Define message schemas per topic so event names and data shapes are validated at publish time. Catches typos and shape mismatches before they reach the wire - instead of silently sending garbage that the client ignores.

Setup

// src/lib/server/channels.js
import { createChannel } from 'svelte-adapter-uws/plugins/channels';

export const todos = createChannel('todos', {
  created: (d) => ({ id: d.id, text: d.text, done: d.done }),
  updated: (d) => ({ id: d.id, text: d.text, done: d.done }),
  deleted: (d) => ({ id: d.id })
});

Each event maps to a validator function. The function receives the raw data and returns the validated (and optionally transformed) output. Throw to reject.

With Zod (or any library that exposes .parse()):

import { z } from 'zod';
import { createChannel } from 'svelte-adapter-uws/plugins/channels';

const Todo = z.object({ id: z.string(), text: z.string(), done: z.boolean() });

export const todos = createChannel('todos', {
  created: Todo,
  updated: Todo,
  deleted: z.object({ id: z.string() })
});

Server API

MethodDescription
channel.publish(platform, event, data)Validate and broadcast to all subscribers
channel.send(platform, ws, event, data)Validate and send to a single connection
channel.topicThe topic string
channel.eventsArray of valid event names

Validators can strip private fields before publishing. If your validator returns { id, text } but the input had { id, text, secret }, only id and text reach clients.

Server example

import { todos } from '$lib/server/channels';

// In a form action or API route:
export async function POST({ request, platform }) {
  const data = await request.json();
  const todo = await db.save(data);

  todos.publish(platform, 'created', todo);  // validates, then publishes
  todos.publish(platform, 'typo', todo);     // throws: unknown event "typo"
  todos.publish(platform, 'created', {});    // throws: validation failed (if validator rejects)
}

Client API

The client wrapper is optional - it catches event name typos on the receiving side too.

<script>
  import { channel } from 'svelte-adapter-uws/plugins/channels/client';

  const todos = channel('todos', ['created', 'updated', 'deleted']);

  const all     = todos.on();          // all events (same as on('todos'))
  const created = todos.on('created'); // filtered  (same as on('todos', 'created'))
  const typo    = todos.on('craeted'); // throws Error immediately
</script>

The events array is optional. Without it, .on() works exactly like the regular on() with the topic pre-filled - no validation, just convenience.

You can still use crud(), lookup(), latest(), etc. directly with the topic string. The client channel is purely additive.

Limitations

  • Runtime only. The validation happens at publish/send time, not at compile time. TypeScript generics give you autocomplete for event names, but data shape checking is runtime.
  • No dependency on Zod. The plugin accepts any validator function or any object with a .parse() method. You bring your own validation library (or use plain functions).

Was this page helpful?