Resources: subscriptions/listen model on modern servers (era fork) (#1630) (#1730)

Fork resource subscriptions by protocol era: legacy keeps resources/subscribe; modern (2026-07-28) models subscriptions as a filter over one long-lived subscriptions/listen stream with reconnect-by-re-listen (capped backoff), an optimistic Connecting→Listening header badge, and a fix so the browser proxy no longer blocks listen() ~60s. Closes #1630.
This commit is contained in:
Cliff Hall 2026-07-20 19:33:40 -04:00 • committed by GitHub
commit 320daf2f67
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 1656 additions and 90 deletions

View file

@ -236,4 +236,71 @@ describe("ResourceSubscriptionsState", () => {
state.destroy();
expect(() => state.destroy()).not.toThrow();
});
describe("modern listen-stream state (#1630)", () => {
it("starts inactive and seeds from the client", () => {
const state = new ResourceSubscriptionsState(client);
expect(state.getStreamState()).toEqual({
active: false,
status: "ended",
honoredUris: [],
});
client.resourceSubscriptionStreamState = {
active: true,
status: "acknowledged",
honoredUris: ["file:///a"],
};
const seeded = new ResourceSubscriptionsState(client);
expect(seeded.getStreamState().active).toBe(true);
expect(seeded.getStreamState().honoredUris).toEqual(["file:///a"]);
});
it("forwards resourceSubscriptionStreamChange as streamStateChange", async () => {
const state = new ResourceSubscriptionsState(client);
const next = await new Promise((resolve) => {
state.addEventListener("streamStateChange", (e) => resolve(e.detail), {
once: true,
});
client.dispatchTypedEvent("resourceSubscriptionStreamChange", {
active: true,
status: "reconnecting",
honoredUris: [],
});
});
expect(next).toEqual({
active: true,
status: "reconnecting",
honoredUris: [],
});
expect(state.getStreamState().status).toBe("reconnecting");
});
it("resets stream state to inactive on a terminal status change", () => {
const state = new ResourceSubscriptionsState(client);
client.dispatchTypedEvent("resourceSubscriptionStreamChange", {
active: true,
status: "acknowledged",
honoredUris: ["file:///a"],
});
expect(state.getStreamState().active).toBe(true);
const handler = vi.fn();
state.addEventListener("streamStateChange", handler);
client.setStatus("disconnected");
expect(state.getStreamState().active).toBe(false);
expect(handler).toHaveBeenCalled();
});
it("resets stream state on destroy", () => {
const state = new ResourceSubscriptionsState(client);
client.dispatchTypedEvent("resourceSubscriptionStreamChange", {
active: true,
status: "acknowledged",
honoredUris: ["file:///a"],
});
state.destroy();
expect(state.getStreamState().active).toBe(false);
});
});
});

View file

@ -66,4 +66,57 @@ describe("useResourceSubscriptions", () => {
client.dispatchTypedEvent("resourceSubscriptionsChange", ["file:///a"]);
expect(result.current.subscriptions).toEqual([]);
});
it("returns an inactive stream state by default and when null", () => {
const { result: nullResult } = renderHook(() =>
useResourceSubscriptions(null),
);
expect(nullResult.current.streamState.active).toBe(false);
const { result } = renderHook(() => useResourceSubscriptions(state));
expect(result.current.streamState.active).toBe(false);
});
it("updates streamState when the store dispatches streamStateChange", async () => {
const { result } = renderHook(() => useResourceSubscriptions(state));
act(() => {
client.dispatchTypedEvent("resourceSubscriptionStreamChange", {
active: true,
status: "acknowledged",
honoredUris: ["file:///a"],
});
});
await waitFor(() => {
expect(result.current.streamState).toEqual({
active: true,
status: "acknowledged",
honoredUris: ["file:///a"],
});
});
});
it("resets streamState when the state prop becomes null", async () => {
const { result, rerender } = renderHook(
({ s }: { s: ResourceSubscriptionsState | null }) =>
useResourceSubscriptions(s),
{ initialProps: { s: state as ResourceSubscriptionsState | null } },
);
act(() => {
client.dispatchTypedEvent("resourceSubscriptionStreamChange", {
active: true,
status: "acknowledged",
honoredUris: [],
});
});
await waitFor(() => {
expect(result.current.streamState.active).toBe(true);
});
rerender({ s: null });
await waitFor(() => {
expect(result.current.streamState.active).toBe(false);
});
});
});