@@ -5,6 +5,7 @@ import { createStore } from "solid-js/store"
55import { bootstrapGlobal , loadPathQuery , loadProjectsQuery } from "./bootstrap"
66import { ServerScope } from "@/runtime/server/scope"
77import type { ServerApi } from "@/runtime/server/api"
8+ import { createServerTransport } from "@/runtime/server/client"
89import type { ServerSync } from "@/runtime/server/sync"
910import { worktreeInventoryKey } from "@/workspaces/inventory"
1011
@@ -64,6 +65,44 @@ test("bootstraps projects through the native store setter and preserves subseque
6465 }
6566} )
6667
68+ // Chromium aborts in-flight loopback requests with ERR_NETWORK_CHANGED when Windows reconfigures an
69+ // adapter; the client wraps that as ClientError("Transport"), which the bootstrap retry must see through.
70+ test ( "recovers project metadata after the connection to the server is dropped" , async ( ) => {
71+ const body = JSON . stringify ( [ { id : "project" , canonical : "/repo" , time : { created : 1 , updated : 1 } , sandboxes : [ ] } ] )
72+ let dropped = 0
73+ const requests : string [ ] = [ ]
74+ const server = Bun . listen ( {
75+ hostname : "127.0.0.1" ,
76+ port : 0 ,
77+ socket : {
78+ open ( socket ) {
79+ if ( dropped >= 2 ) return
80+ dropped += 1
81+ socket . terminate ( )
82+ } ,
83+ data ( socket , chunk ) {
84+ requests . push ( String ( chunk ) . split ( " " ) [ 0 ] ?? "" )
85+ socket . end (
86+ `HTTP/1.1 200 OK\r\ncontent-type: application/json\r\ncontent-length: ${ Buffer . byteLength ( body ) } \r\naccess-control-allow-origin: *\r\nconnection: close\r\n\r\n${ body } ` ,
87+ )
88+ } ,
89+ } ,
90+ } )
91+ const transport = createServerTransport ( { http : { url : `http://127.0.0.1:${ server . port } ` } } )
92+
93+ try {
94+ const result = await new QueryClient ( { defaultOptions : { queries : { retry : false } } } ) . fetchQuery (
95+ loadProjectsQuery ( ServerScope . local , transport . api . project ) ,
96+ )
97+ expect ( dropped ) . toBe ( 2 )
98+ // happy-dom's fetch adds a CORS preflight; only the GET is the retried API call.
99+ expect ( requests . filter ( ( method ) => method === "GET" ) ) . toHaveLength ( 1 )
100+ expect ( result ) . toMatchObject ( [ { id : "project" , worktree : "/repo" } ] )
101+ } finally {
102+ server . stop ( true )
103+ }
104+ } )
105+
67106describe ( "query keys" , ( ) => {
68107 test ( "partitions identical directories by server scope" , ( ) => {
69108 const location = { } as ServerApi [ "location" ]
0 commit comments