Files
deepseek-harness/packages/client/hmr/src/events.ts
T

45 lines
1.9 KiB
TypeScript

/**
* Wire protocol of the `/plugins/events` dev SSE channel — single source for
* both halves of this package. Frames still cross a wire boundary: the
* browser half validates them at its JSON parse point; sharing the type keeps
* the two ends from drifting, not from parsing.
*/
import type { WebBootGraph } from '@deepseek-ai/dsh-client-modules'
/** One SSE frame: the full graph on connect, or one rebuilt bundle notice. */
export type PluginsEventFrame =
| { type: 'graph'; graph: WebBootGraph }
| { type: 'rebuilt'; id: string; rev: string }
/** Browser wire-parse result: known frame, forward-compatible unknown type, or malformed payload. */
export type PluginsEventParseResult =
| { kind: 'frame'; frame: PluginsEventFrame }
| { kind: 'unknown' }
| { kind: 'invalid' }
/**
* Validate one JSON-decoded SSE payload before it can mutate module state.
* @param value - Parsed JSON value from the EventSource message.
* @returns the known frame, an unknown-type marker, or an invalid marker.
*/
export function parsePluginsEventFrame(value: unknown): PluginsEventParseResult {
if (typeof value !== 'object' || value === null) return { kind: 'invalid' }
const record = value as Record<string, unknown>
switch (record.type) {
case 'rebuilt':
return typeof record.id === 'string' && typeof record.rev === 'string'
? { kind: 'frame', frame: { type: 'rebuilt', id: record.id, rev: record.rev } }
: { kind: 'invalid' }
case 'graph':
return typeof record.graph === 'object' && record.graph !== null
? { kind: 'frame', frame: { type: 'graph', graph: record.graph as WebBootGraph } }
: { kind: 'invalid' }
default:
return typeof record.type === 'string' ? { kind: 'unknown' } : { kind: 'invalid' }
}
}
/** System SSE endpoint pushing graph/rebuilt frames (wire protocol constant). */
export const EVENTS_ENDPOINT = '/plugins/events'