| 160 | type UpstreamSurrogate = { port: number; close: () => Promise<void> }; |
| 161 | |
| 162 | async function startDualLoopbackUpstream( |
| 163 | handler: Parameters<typeof createHttpServer>[1], |
| 164 | ): Promise<UpstreamSurrogate> { |
| 165 | const v6 = createHttpServer(handler); |
| 166 | await new Promise<void>((done, fail) => { |
| 167 | v6.once('error', fail); |
| 168 | v6.listen(0, '::1', () => { |
| 169 | v6.off('error', fail); |
| 170 | done(); |
| 171 | }); |
| 172 | }); |
| 173 | const port = (v6.address() as { port: number }).port; |
| 174 | const v4 = createHttpServer(handler); |
| 175 | try { |
| 176 | await new Promise<void>((done, fail) => { |
| 177 | v4.once('error', fail); |
| 178 | v4.listen(port, '127.0.0.1', () => { |
| 179 | v4.off('error', fail); |
| 180 | done(); |
| 181 | }); |
| 182 | }); |
| 183 | } catch (err) { |
| 184 | await new Promise<void>((r) => v6.close(() => r())); |
| 185 | throw err; |
| 186 | } |
| 187 | return { |
| 188 | port, |
| 189 | close: async () => { |
| 190 | await Promise.all([ |
| 191 | new Promise<void>((r) => v6.close(() => r())), |
| 192 | new Promise<void>((r) => v4.close(() => r())), |
| 193 | ]); |
| 194 | }, |
| 195 | }; |
| 196 | } |
| 197 | |
| 198 | describe('resolveRequestedPort', () => { |
| 199 | test('default is DEFAULT_UI_PORT with kernel-allocated fallback', () => { |