diff --git a/packages/client-runtime/src/state/shell-sync.test.ts b/packages/client-runtime/src/state/shell-sync.test.ts index 062db03809cfc..1cfe20b403ee8 100644 --- a/packages/client-runtime/src/state/shell-sync.test.ts +++ b/packages/client-runtime/src/state/shell-sync.test.ts @@ -7,6 +7,7 @@ import { type ThreadPullRequestLink, } from "@t3tools/contracts"; import { describe, expect, it } from "@effect/vitest"; +import * as Cause from "effect/Cause"; import * as Deferred from "effect/Deferred"; import * as Effect from "effect/Effect"; import * as Exit from "effect/Exit"; @@ -1314,4 +1315,18 @@ describe("environment shell cold start", () => { yield* h.liveAt(HTTP_SEQUENCE + 1); }), ); + + it.effect("resubscribes on the next session after a stream defect (#4589)", () => + Effect.gen(function* () { + const h = yield* makeColdStart(RECENT_ORIGIN); + const first = yield* Queue.take(h.subscriptions); + yield* Queue.offer(first.events, { kind: "synchronized" }); + yield* h.liveAt(CACHED_SEQUENCE); + + yield* Queue.failCause(first.events, Cause.die(new Error("shell stream defect"))); + yield* h.reconnect; + const resumed = yield* Queue.take(h.subscriptions); + expect(resumed.input).toMatchObject({ afterSequence: CACHED_SEQUENCE }); + }), + ); }); diff --git a/packages/client-runtime/src/state/shell.ts b/packages/client-runtime/src/state/shell.ts index 808fd9fdece56..b62b1a7aa49f5 100644 --- a/packages/client-runtime/src/state/shell.ts +++ b/packages/client-runtime/src/state/shell.ts @@ -538,6 +538,7 @@ export const makeEnvironmentShellState = Effect.fn("EnvironmentShellState.make") }; }), { + onDefect: (cause) => setStreamError(Cause.squash(cause)), onExpectedFailure: (cause) => setStreamError(Cause.squash(cause)), retryExpectedFailureAfter: "250 millis", resubscribe: resubscriptions,