@@ -184,6 +184,52 @@ describe("HttpApi UI fallback", () => {
184184 expect ( await response . text ( ) ) . toBe ( "console.log('ok')" )
185185 } )
186186
187+ // Regression for #25698 (Ope): upstream `transfer-encoding: chunked` was
188+ // forwarded through the proxy while the proxy itself re-frames the body,
189+ // causing browsers to fail with `ERR_INVALID_CHUNKED_ENCODING`.
190+ test ( "strips upstream transfer-encoding header from proxied assets" , async ( ) => {
191+ Flag . OPENCODE_EXPERIMENTAL_HTTPAPI = true
192+ Flag . OPENCODE_DISABLE_EMBEDDED_WEB_UI = true
193+
194+ const response = await Effect . runPromise (
195+ Effect . gen ( function * ( ) {
196+ const fs = yield * AppFileSystem . Service
197+ const client = yield * HttpClient . HttpClient
198+ return yield * serveUIEffect ( HttpServerRequest . fromWeb ( new Request ( "http://localhost/" ) ) , {
199+ fs,
200+ client,
201+ } )
202+ } ) . pipe (
203+ Effect . provide (
204+ Layer . mergeAll (
205+ AppFileSystem . defaultLayer ,
206+ Layer . succeed (
207+ HttpClient . HttpClient ,
208+ HttpClient . make ( ( request ) =>
209+ Effect . succeed (
210+ HttpClientResponse . fromWeb (
211+ request ,
212+ new Response ( "<html>opencode</html>" , {
213+ headers : {
214+ "transfer-encoding" : "chunked" ,
215+ "content-type" : "text/html" ,
216+ } ,
217+ } ) ,
218+ ) ,
219+ ) ,
220+ ) ,
221+ ) ,
222+ ) ,
223+ ) ,
224+ Effect . map ( HttpServerResponse . toWeb ) ,
225+ ) ,
226+ )
227+
228+ expect ( response . status ) . toBe ( 200 )
229+ expect ( response . headers . get ( "transfer-encoding" ) ) . toBeNull ( )
230+ expect ( await response . text ( ) ) . toBe ( "<html>opencode</html>" )
231+ } )
232+
187233 test ( "serves embedded UI assets when Bun can read them but access reports missing" , async ( ) => {
188234 Flag . OPENCODE_EXPERIMENTAL_HTTPAPI = true
189235 let readPath : string | undefined
@@ -257,6 +303,25 @@ describe("HttpApi UI fallback", () => {
257303 expect ( response . status ) . toBe ( 200 )
258304 } )
259305
306+ // Regression for #25698 (Ope): the browser fetches the PWA manifest and
307+ // its icons via flows that don't carry app-managed credentials (the
308+ // `<link rel="manifest">` request is not under page-auth control), so the
309+ // server returning 401 breaks PWA install. These specific public assets
310+ // should bypass auth.
311+ test ( "serves the PWA manifest without auth even when a server password is set" , async ( ) => {
312+ Flag . OPENCODE_EXPERIMENTAL_HTTPAPI = true
313+ Flag . OPENCODE_DISABLE_EMBEDDED_WEB_UI = true
314+
315+ for ( const path of [ "/site.webmanifest" , "/web-app-manifest-192x192.png" , "/web-app-manifest-512x512.png" ] ) {
316+ const response = await uiApp ( {
317+ password : "secret" ,
318+ username : "opencode" ,
319+ client : httpClient ( new Response ( "ok" ) ) ,
320+ } ) . request ( path )
321+ expect ( response . status ) . not . toBe ( 401 )
322+ }
323+ } )
324+
260325 test ( "allows web UI preflight without auth" , async ( ) => {
261326 Flag . OPENCODE_EXPERIMENTAL_HTTPAPI = true
262327
0 commit comments