import { describe, expect, test } from "bun:test" import type { Message, OpencodeClient, Part } from "@opencode-ai/sdk/v2/client" import { ChildStoreManager } from "./child-store" import { SessionMessageLoader } from "./session-message-loader" const createRecord = (sessionID: string, id = "msg_1") => ({ info: { id, sessionID, role: "user", time: { created: 1 } } as Message, parts: [{ id: `part_${id}`, messageID: id, sessionID, type: "text", text: "hello" }] as Part[], }) const deferred = () => { let resolve!: (value: T) => void const promise = new Promise((next) => { resolve = next }) return { promise, resolve } } const response = (data: ReturnType[], cursor?: string) => ({ data, response: { headers: { get: (name: string) => name === "x-next-cursor" ? cursor ?? null : null } }, }) const createLoader = (messages: (input: { sessionID: string directory?: string limit?: number before?: string }) => Promise) => { const childStores = new ChildStoreManager() const sdk = { session: { messages } } as unknown as OpencodeClient const loader = new SessionMessageLoader(childStores, { sdk, runtimeKey: "runtime-a" }) return { childStores, loader } } describe("SessionMessageLoader", () => { test("deduplicates navigation and reactive loading for the same target", async () => { const pending = deferred>() let calls = 0 const { childStores, loader } = createLoader(async () => { calls += 1 return pending.promise }) const target = { directory: "/repo", sessionID: "session-a" } const navigation = loader.ensure(target, { reason: "navigation" }) const reactive = loader.ensure(target, { reason: "reactive" }) expect(calls).toBe(1) pending.resolve(response([createRecord(target.sessionID)])) await Promise.all([navigation, reactive]) expect(loader.getSnapshot(target).status).toBe("ready") expect(childStores.getChild(target.directory)?.getState().message[target.sessionID]?.length).toBe(1) loader.dispose() childStores.disposeAll() }) test("runs a requested tail refresh after an older in-flight load", async () => { const initial = deferred>() const refresh = deferred>() let calls = 0 const limits: number[] = [] const { childStores, loader } = createLoader(async ({ limit }) => { calls += 1 limits.push(limit ?? 0) return calls === 1 ? initial.promise : refresh.promise }) const target = { directory: "/repo", sessionID: "session-a" } const loading = loader.ensure(target, { reason: "navigation" }) const refreshing = loader.refreshTail(target, 30) const duplicateRefresh = loader.refreshTail(target, 80) expect(calls).toBe(1) expect(duplicateRefresh).toBe(refreshing) initial.resolve(response([createRecord(target.sessionID, "msg_1")])) await loading await Promise.resolve() expect(calls).toBe(2) expect(limits).toEqual([50, 80]) refresh.resolve(response([createRecord(target.sessionID, "msg_2")])) await Promise.all([refreshing, duplicateRefresh]) expect(childStores.getChild(target.directory)?.getState().message[target.sessionID]?.map((message) => message.id)) .toEqual(["msg_1", "msg_2"]) loader.dispose() childStores.disposeAll() }) test("preserves complete history coverage across a tail refresh", async () => { let calls = 0 const { childStores, loader } = createLoader(async ({ sessionID }) => { calls += 1 return calls === 1 ? response([createRecord(sessionID, "msg_1")]) : response([createRecord(sessionID, "msg_2")], "stale-tail-cursor") }) const target = { directory: "/repo", sessionID: "session-a" } await loader.ensure(target) expect(loader.getSnapshot(target).complete).toBe(true) expect(loader.getSnapshot(target).cursor).toBe(undefined) await loader.refreshTail(target, 2) expect(loader.getSnapshot(target).complete).toBe(true) expect(loader.getSnapshot(target).cursor).toBe(undefined) loader.dispose() childStores.disposeAll() }) test("does not deduplicate identical session IDs across directories", async () => { const calls: string[] = [] const { childStores, loader } = createLoader(async ({ directory, sessionID }) => { calls.push(directory ?? "") return response([createRecord(sessionID)]) }) await Promise.all([ loader.ensure({ directory: "/repo-a", sessionID: "shared" }), loader.ensure({ directory: "/repo-b", sessionID: "shared" }), ]) expect(calls.sort()).toEqual(["/repo-a", "/repo-b"]) loader.dispose() childStores.disposeAll() }) test("exposes a retryable error without clearing an existing snapshot", async () => { let fail = true const { childStores, loader } = createLoader(async ({ sessionID }) => { if (fail) return { error: { message: "rejected" }, response: { status: 400 } } return response([createRecord(sessionID)]) }) const target = { directory: "/repo", sessionID: "session-a" } const store = childStores.ensureChild(target.directory, { bootstrap: false }) store.setState({ message: { [target.sessionID]: [{ id: "cached", sessionID: target.sessionID, role: "user", time: { created: 0 } } as Message] } }) await loader.ensure(target, { force: true }) expect(loader.getSnapshot(target).status).toBe("error") expect(store.getState().message[target.sessionID]?.[0]?.id).toBe("cached") fail = false await loader.ensure(target, { force: true }) expect(loader.getSnapshot(target).status).toBe("ready") loader.dispose() childStores.disposeAll() }) test("prevents an evicted in-flight request from repopulating the store", async () => { const pending = deferred>() const { childStores, loader } = createLoader(async () => pending.promise) const target = { directory: "/repo", sessionID: "session-a" } const loading = loader.ensure(target) loader.invalidateSession(target) pending.resolve(response([createRecord(target.sessionID)])) await loading expect(childStores.getChild(target.directory)?.getState().message[target.sessionID]).toBe(undefined) expect(loader.getSnapshot(target).status).toBe("idle") loader.dispose() childStores.disposeAll() }) test("treats an empty successful response as resolved authoritative state", async () => { const { childStores, loader } = createLoader(async () => response([])) const target = { directory: "/repo", sessionID: "empty" } await loader.ensure(target) expect(loader.getSnapshot(target).resolved).toBe(true) expect(loader.getSnapshot(target).complete).toBe(true) expect(childStores.getChild(target.directory)?.getState().message[target.sessionID]).toEqual([]) loader.dispose() childStores.disposeAll() }) test("retries a missing message payload instead of treating it as an empty snapshot", async () => { let calls = 0 const { childStores, loader } = createLoader(async ({ sessionID }) => { calls += 1 return calls === 1 ? {} : response([createRecord(sessionID)]) }) const target = { directory: "/repo", sessionID: "session-a" } await loader.ensure(target) expect(calls).toBe(2) expect(loader.getSnapshot(target).status).toBe("ready") expect(childStores.getChild(target.directory)?.getState().message[target.sessionID]?.length).toBe(1) loader.dispose() childStores.disposeAll() }) })