feat(sp28): claimAcks slice + useTailStream/useMergedTail dispatch

This commit is contained in:
Nora
2026-07-02 11:31:17 -06:00
parent a97f1d1350
commit c54b2c1867
8 changed files with 326 additions and 6 deletions
+24
View File
@@ -127,6 +127,30 @@ describe("streamTail", () => {
expect(calledUrl).toBe("/api/ta1-acks/stream");
});
it("test_targets_claim_acks_stream_endpoint", async () => {
// SP28: the `claim-acks` resource is part of TailResource; the URL
// must be /api/claim-acks/stream. The claim↔ack link stream is a
// shared resource (not per-claim or per-ack) — both the ClaimDrawer
// and AckDrawer subscribe to the same endpoint and filter
// server-side via the page-specific filterFn passed to
// `useMergedTail`.
const driver = makeStream();
const fetchMock = vi.fn().mockResolvedValue(driver.response);
vi.stubGlobal("fetch", fetchMock);
// Drive an event so the iterator's first read resolves — same
// pattern as `test_parses_well_formed_ndjson_into_typed_events`
// (the `test_targets_acks_stream_endpoint` shape hangs in CI
// because it awaits `gen.next()` before any chunk arrives).
const gen = streamTail("claim-acks");
driver.push('{"type":"snapshot_end","data":{"count":0}}');
driver.close();
await gen.next();
await gen.return?.(undefined);
expect(fetchMock).toHaveBeenCalledTimes(1);
const [calledUrl] = fetchMock.mock.calls[0] as [string];
expect(calledUrl).toBe("/api/claim-acks/stream");
});
it("test_handles_heartbeat_silently", async () => {
// "Silently" here means: still yields the correctly-typed heartbeat
// (no special filtering) — the consumer (useTailStream) decides what
+7 -1
View File
@@ -26,7 +26,13 @@ export type TailEvent =
| { type: "item_dropped"; data: { id: string } }
| { type: "error"; data: { message: string } };
export type TailResource = "claims" | "remittances" | "activity" | "acks" | "ta1_acks";
export type TailResource =
| "claims"
| "remittances"
| "activity"
| "acks"
| "ta1_acks"
| "claim-acks";
export interface StreamTailOptions {
/** Forwarded to `fetch`; aborting the controller cleanly exits the generator. */