fix: align realtime event contracts

This commit is contained in:
jjbrunton committed 2026-08-08 14:54:09 +01:00
1 parent 51e3e28a9b
commit 9f4f198800
2 files changed
+151 -18

No files matched your search

+127 -9
View File
@@ -3,33 +3,151 @@ import { SyncProgressSchema } from './chats.js';
const EventBase = {
id: z.string(),
occurredAt: z.number(),
occurredAt: z.string().datetime({ offset: true }),
};
export const BotRuntimeStatusSchema = z.union([
z.literal('starting'),
z.literal('running'),
z.literal('stopping'),
z.literal('stopped'),
]);
export const ConversationStatusSchema = z.union([
z.literal('new'),
z.literal('awaiting-reply'),
z.literal('replied'),
z.literal('closed'),
]);
export const RealtimeSyncKindSchema = z.union([
z.literal('media'),
z.literal('messages'),
z.literal('conversations'),
z.literal('full'),
]);
export const RealtimeRedditSessionStatusSchema = z.union([
z.literal('unknown'),
z.literal('authenticating'),
z.literal('authenticated'),
z.literal('expired'),
z.literal('logged-out'),
z.literal('error'),
]);
export const DashboardEventSchema = z.discriminatedUnion('type', [
z.strictObject({
...EventBase,
type: z.literal('stream.connected'),
payload: z.strictObject({}),
type: z.literal('bot.status.changed'),
payload: z.strictObject({
status: BotRuntimeStatusSchema,
dryRun: z.boolean(),
reason: z.string().optional(),
}),
}),
z.strictObject({
...EventBase,
type: z.literal('log.created'),
type: z.literal('message.sent'),
payload: z.strictObject({
level: z.union([z.literal('info'), z.literal('warn'), z.literal('error'), z.literal('debug')]),
message: z.string(),
data: z.unknown().optional(),
messageId: z.string(),
recipient: z.string(),
conversationId: z.string().optional(),
}),
}),
z.strictObject({
...EventBase,
type: z.literal('message.failed'),
payload: z.strictObject({
recipient: z.string(),
reason: z.string(),
messageId: z.string().optional(),
conversationId: z.string().optional(),
code: z.string().optional(),
retryable: z.boolean().optional(),
}),
}),
z.strictObject({
...EventBase,
type: z.literal('conversation.updated'),
payload: z.strictObject({
conversationId: z.string(),
status: ConversationStatusSchema,
unreadCount: z.number().optional(),
}),
}),
z.strictObject({
...EventBase,
type: z.literal('reply.received'),
payload: z.strictObject({
conversationId: z.string(),
replyId: z.string(),
sender: z.string(),
preview: z.string().optional(),
}),
}),
z.strictObject({
...EventBase,
type: z.literal('sync.started'),
payload: z.strictObject({
syncId: z.string(),
kind: RealtimeSyncKindSchema,
}),
}),
z.strictObject({
...EventBase,
type: z.literal('sync.progress'),
payload: SyncProgressSchema,
payload: z.strictObject({
syncId: z.string(),
kind: RealtimeSyncKindSchema,
completed: z.number(),
total: z.number().optional(),
message: z.string().optional(),
}),
}),
z.strictObject({
...EventBase,
type: z.literal('sync.completed'),
payload: z.strictObject({ kind: z.union([z.literal('full'), z.literal('delta')]) }),
payload: z.strictObject({
syncId: z.string(),
kind: RealtimeSyncKindSchema,
processed: z.number(),
}),
}),
z.strictObject({
...EventBase,
type: z.literal('sync.failed'),
payload: z.strictObject({
syncId: z.string(),
kind: RealtimeSyncKindSchema,
reason: z.string(),
code: z.string().optional(),
}),
}),
z.strictObject({
...EventBase,
type: z.literal('rate-limit.changed'),
payload: z.strictObject({
limited: z.boolean(),
remaining: z.number().optional(),
resetsAt: z.string().optional(),
reason: z.string().optional(),
}),
}),
z.strictObject({
...EventBase,
type: z.literal('reddit.session.changed'),
payload: z.strictObject({
status: RealtimeRedditSessionStatusSchema,
username: z.string().optional(),
reason: z.string().optional(),
}),
}),
z.strictObject({
...EventBase,
type: z.literal('log.created'),
payload: z.strictObject({
level: z.union([z.literal('debug'), z.literal('info'), z.literal('warn'), z.literal('error')]),
message: z.string(),
data: z.unknown().optional(),
}),
}),
]);