import { describe, expect, test } from "bun:test" import { coalesceServerEvents, enqueueServerEvent, resumeStreamAfterPageShow } from "./server-sdk" import type { Event } from "@opencode-ai/sdk/v2/client" describe("resumeStreamAfterPageShow", () => { test("restarts a stream only after a back-forward cache restore", () => { let starts = 0 const start = () => starts++ resumeStreamAfterPageShow({ persisted: false } as PageTransitionEvent, start) resumeStreamAfterPageShow({ persisted: true } as PageTransitionEvent, start) expect(starts).toBe(1) }) }) describe("coalesceServerEvents", () => { const delta = (value: string, field = "text", partID = "part") => ({ directory: "/repo", payload: { type: "message.part.delta", properties: { messageID: "msg", partID, field, delta: value }, } as Event, }) test("merges adjacent deltas for the same field", () => { const first = delta("hello ") const second = delta("world") first.payload.id = "first" second.payload.id = "second" const result = coalesceServerEvents([first, second]) expect(result).toHaveLength(1) expect(result[0]?.payload).toMatchObject({ id: "second", properties: { delta: "hello world" } }) }) test("preserves event boundaries and distinct fields", () => { const status = { directory: "/repo", payload: { type: "session.status", properties: { sessionID: "ses", status: { type: "idle" } } } as Event, } const result = coalesceServerEvents([delta("a"), delta("b", "metadata"), status, delta("c")]) expect(result.map((event) => event.payload.type)).toEqual([ "message.part.delta", "message.part.delta", "session.status", "message.part.delta", ]) }) test("preserves event ID order across interleaved deltas", () => { const first = delta("a") const other = delta("b", "text", "other") const last = delta("c") first.payload.id = "1" other.payload.id = "2" last.payload.id = "3" const result = coalesceServerEvents([first, other, last]) expect(result.map((event) => event.payload.id)).toEqual(["1", "2", "3"]) }) }) describe("enqueueServerEvent", () => { const partUpdated = (text: string) => ({ type: "message.part.updated", properties: { sessionID: "session", part: { id: "part", sessionID: "session", messageID: "message", type: "text", text }, }, }) as Event test("preserves part updates across message remove and re-add barriers", () => { const events: Array<{ directory: string; payload: Event }> = [] const enqueue = (payload: Event) => enqueueServerEvent(events, { directory: "/repo", payload }) enqueue(partUpdated("old")) enqueue({ type: "message.removed", properties: { sessionID: "session", messageID: "message" } } as Event) enqueue({ type: "message.updated", properties: { sessionID: "session", info: { id: "message", sessionID: "session", role: "user", time: { created: 1 }, agent: "build", model: { providerID: "provider", modelID: "model" }, }, }, } as Event) enqueue(partUpdated("new")) expect(events.map((event) => event.payload.type)).toEqual([ "message.part.updated", "message.removed", "message.updated", "message.part.updated", ]) }) test("preserves deltas after a replacement snapshot", () => { const events: Array<{ directory: string; payload: Event }> = [] const enqueue = (payload: Event) => enqueueServerEvent(events, { directory: "/repo", payload }) enqueue(partUpdated("a")) enqueue(partUpdated("ab")) enqueue({ type: "message.part.delta", properties: { sessionID: "session", messageID: "message", partID: "part", field: "text", delta: "c" }, } as Event) const result = coalesceServerEvents(events) expect(result.map((event) => event.payload.type)).toEqual(["message.part.updated", "message.part.delta"]) expect(result[0]?.payload).toMatchObject({ properties: { part: { text: "ab" } } }) expect(result[1]?.payload).toMatchObject({ properties: { delta: "c" } }) }) test("preserves updates after session deletion", () => { const events: Array<{ directory: string; payload: Event }> = [] const enqueue = (payload: Event) => enqueueServerEvent(events, { directory: "/repo", payload }) enqueue(partUpdated("old")) enqueue({ type: "session.deleted", properties: { sessionID: "session", info: { id: "session" } }, } as Event) enqueue(partUpdated("new")) expect(events.map((event) => event.payload.type)).toEqual([ "message.part.updated", "session.deleted", "message.part.updated", ]) }) test("does not coalesce edge-triggered session statuses", () => { const events: Array<{ directory: string; payload: Event }> = [] const enqueue = (status: "retry" | "busy") => enqueueServerEvent(events, { directory: "/repo", payload: { type: "session.status", properties: { sessionID: "session", status: status === "retry" ? { type: "retry", attempt: 1, message: "retry", next: 1 } : { type: "busy" }, }, } as Event, }) enqueue("retry") enqueue("busy") expect(events).toHaveLength(2) }) })