Move all hand-synced cross-app wire contracts into one built workspace package, @boocode/contracts, consumed by server/web/coder/coder-web via workspace:* + a per-subpath exports map. The ws-frames and provider-config Zod schemas are schema-first (z.infer); MessageMetadata, ErrorReason, AgentSessionConfig, the provider snapshot types, and WorktreeRiskReport are each single-sourced. Deletes the byte-identical copies and their parity tests, fixes a live AgentSessionConfig drift (coder dead copy removed, unified to the web required/nullable shape), removes the dead pending_change WS arms in the fallback SPA, and inverts the build order (contracts builds first) across root build, Dockerfile, and the coder deploy docs. Reverses the shared-package decision declined in v2.5.12. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
86 lines
2.7 KiB
TypeScript
86 lines
2.7 KiB
TypeScript
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
import {
|
|
type WsFrame,
|
|
} from '@boocode/contracts/ws-frames';
|
|
import { createBroker } from '../broker.js';
|
|
|
|
const VALID_UUID_A = '00000000-0000-0000-0000-000000000001';
|
|
const VALID_UUID_B = '00000000-0000-0000-0000-000000000002';
|
|
const VALID_TIMESTAMP = '2026-05-22T14:30:00.000Z';
|
|
|
|
describe('broker.publishFrame / publishUserFrame fail-closed behavior', () => {
|
|
let logErrors: Array<{ obj: unknown; msg: string }>;
|
|
let mockLog: Parameters<typeof createBroker>[0];
|
|
|
|
beforeEach(() => {
|
|
logErrors = [];
|
|
mockLog = {
|
|
error: (obj: unknown, msg: string) => {
|
|
logErrors.push({ obj, msg });
|
|
},
|
|
info: () => {},
|
|
warn: () => {},
|
|
debug: () => {},
|
|
trace: () => {},
|
|
fatal: () => {},
|
|
child: () => mockLog as never,
|
|
level: 'info',
|
|
silent: () => {},
|
|
} as unknown as Parameters<typeof createBroker>[0];
|
|
});
|
|
|
|
afterEach(() => {
|
|
vi.restoreAllMocks();
|
|
});
|
|
|
|
it('publishFrame delivers a valid frame to subscribers', () => {
|
|
const broker = createBroker(mockLog);
|
|
const received: WsFrame[] = [];
|
|
broker.subscribe('sess-1', (f) => received.push(f as WsFrame));
|
|
broker.publishFrame('sess-1', {
|
|
type: 'delta',
|
|
message_id: VALID_UUID_A,
|
|
chat_id: VALID_UUID_B,
|
|
content: 'hello',
|
|
});
|
|
expect(received).toHaveLength(1);
|
|
expect((received[0] as { type: string }).type).toBe('delta');
|
|
expect(logErrors).toHaveLength(0);
|
|
});
|
|
|
|
it('publishFrame drops + logs an invalid frame instead of delivering it', () => {
|
|
const broker = createBroker(mockLog);
|
|
const received: WsFrame[] = [];
|
|
broker.subscribe('sess-1', (f) => received.push(f as WsFrame));
|
|
broker.publishFrame('sess-1', {
|
|
type: 'delta',
|
|
message_id: 'not-a-uuid',
|
|
content: 'hello',
|
|
} as never);
|
|
expect(received).toHaveLength(0);
|
|
expect(logErrors).toHaveLength(1);
|
|
expect(logErrors[0]!.msg).toMatch(/ws-frame-validation-failed/);
|
|
});
|
|
|
|
it('publishUserFrame drops + logs an invalid user-channel frame', () => {
|
|
const broker = createBroker(mockLog);
|
|
const received: WsFrame[] = [];
|
|
broker.subscribeUser('default', (f) => received.push(f as WsFrame));
|
|
broker.publishUserFrame('default', {
|
|
type: 'chat_status',
|
|
chat_id: VALID_UUID_A,
|
|
status: 'working', // v1.12.1 dropped this enum value
|
|
at: VALID_TIMESTAMP,
|
|
} as never);
|
|
expect(received).toHaveLength(0);
|
|
expect(logErrors).toHaveLength(1);
|
|
});
|
|
|
|
it('publishFrame validation failure does not throw (no cascade into stream-phase)', () => {
|
|
const broker = createBroker(mockLog);
|
|
expect(() =>
|
|
broker.publishFrame('sess-1', { type: 'unknown_type' } as never),
|
|
).not.toThrow();
|
|
});
|
|
});
|