Skip to content
WIP

This guide is a work in progress. Barry is also a work in progress.

@barry-rocks/sdk/events

Event types and schemas for Barry’s event feed, plus announce, which records an event (with a severity and a type) that sessions and people can read. Use it to report progress or results from a bag.

import { … } from "@barry-rocks/sdk/events";
Property Type Description
baseUrl string | (() => string) Where the bus owner listens, e.g. http://127.0.0.1:3854/api/v1.
id string -
kind string -
path string Path under baseUrl that publishes, e.g. /identities/announce.
timeoutMs? number -
topic string -

AnnounceResult = { ok: true; queued: number; } | { ok: false; reason: string; }

Telling subscribers something changed, from whichever process you happen to be.

The realtime bus is an in-memory map of topic -> websocket, so it lives in exactly one process: whichever one holds the sockets. Almost nothing that CAUSES a change runs there. barry events emit is a one-shot CLI process, record_event runs in the engine, launchd jobs shell out to the CLI, and identity writes run in bags/identities, a different service from the one holding the websockets.

So there are two halves, and which one applies is decided by who is running: the bus owner publishes to its own sockets, everyone else posts across the process boundary and lets the owner publish. Wiring only the first half is the trap this module exists to avoid — it looks correct, passes an in-process test, and is silent for every change that actually happens in production.

Generalized from bags/events/src/announce.ts, which solved this first for events. Kept as one implementation rather than a copy per topic, because two copies of the in-process/cross-process choice is how one of them silently stops matching the other.

Best-effort throughout: the write that triggered this already succeeded and clients refetch on their next poll or reconnect, so a delivery failure must never fail it. Failures are RETURNED, not thrown and not swallowed — a silent void would make a missing secret or a stopped service look exactly like a quiet feed.


BarryEvent = z.infer<typeof EventSchema>


EventSeverity = z.infer<typeof EventSeveritySchema>


EventType = z.infer<typeof EventTypeSchema>


InProcessPublisher = (topic, id, kind) => number

What a bus owner registers so its own writes skip the HTTP round trip.

Parameter Type
topic string
id string
kind string

number

const CreateEventRequestSchema: ZodObject<{ body: ZodOptional<ZodString>; data: ZodOptional<ZodRecord<ZodString, ZodUnknown>>; metadata: ZodOptional<ZodRecord<ZodString, ZodUnknown>>; sessionId: ZodOptional<ZodString>; severity: ZodOptional<ZodEnum<{ error: "error"; info: "info"; success: "success"; warn: "warn"; }>>; source: ZodOptional<ZodString>; title: ZodString; type: ZodEnum<{ notification: "notification"; progress: "progress"; system_alert: "system_alert"; task_finished: "task_finished"; }>; }, $strict>


const EventListResponseSchema: ZodObject<{ events: ZodArray<ZodObject<{ body: ZodNullable<ZodString>; createdAt: ZodISODateTime; data: ZodRecord<ZodString, ZodUnknown>; deliveredVia: ZodArray<ZodString>; id: ZodString; metadata: ZodRecord<ZodString, ZodUnknown>; readAt: ZodNullable<ZodISODateTime>; sessionId: ZodNullable<ZodString>; severity: ZodEnum<{ error: "error"; info: "info"; success: "success"; warn: "warn"; }>; source: ZodString; title: ZodString; type: ZodEnum<{ notification: "notification"; progress: "progress"; system_alert: "system_alert"; task_finished: "task_finished"; }>; }, $strict>>; nextCursor: ZodNullable<ZodString>; }, $strict>


const EventResponseSchema: ZodObject<{ event: ZodObject<{ body: ZodNullable<ZodString>; createdAt: ZodISODateTime; data: ZodRecord<ZodString, ZodUnknown>; deliveredVia: ZodArray<ZodString>; id: ZodString; metadata: ZodRecord<ZodString, ZodUnknown>; readAt: ZodNullable<ZodISODateTime>; sessionId: ZodNullable<ZodString>; severity: ZodEnum<{ error: "error"; info: "info"; success: "success"; warn: "warn"; }>; source: ZodString; title: ZodString; type: ZodEnum<{ notification: "notification"; progress: "progress"; system_alert: "system_alert"; task_finished: "task_finished"; }>; }, $strict>; }, $strict>


const EventSchema: ZodObject<{ body: ZodNullable<ZodString>; createdAt: ZodISODateTime; data: ZodRecord<ZodString, ZodUnknown>; deliveredVia: ZodArray<ZodString>; id: ZodString; metadata: ZodRecord<ZodString, ZodUnknown>; readAt: ZodNullable<ZodISODateTime>; sessionId: ZodNullable<ZodString>; severity: ZodEnum<{ error: "error"; info: "info"; success: "success"; warn: "warn"; }>; source: ZodString; title: ZodString; type: ZodEnum<{ notification: "notification"; progress: "progress"; system_alert: "system_alert"; task_finished: "task_finished"; }>; }, $strict>


const EventSeveritySchema: ZodEnum<{ error: "error"; info: "info"; success: "success"; warn: "warn"; }>


const EventTypeSchema: ZodEnum<{ notification: "notification"; progress: "progress"; system_alert: "system_alert"; task_finished: "task_finished"; }>


const EventUnreadCountResponseSchema: ZodObject<{ count: ZodInt; }, $strict>

announce(options): Promise<AnnounceResult>

Parameter Type
options AnnounceOptions

Promise<AnnounceResult>


setInProcessPublisher(publish): void

Set by whichever service owns the sockets, at startup.

A function rather than a constant so the owner can register before its first write without import order deciding the answer, and so a test can exercise both halves.

Parameter Type
publish InProcessPublisher | null

void