Skip to content

fix "browser" test - #2118

Merged
coyotte508 merged 10 commits into
mainfrom
fix-browser-test
May 7, 2026
Merged

fix "browser" test#2118
coyotte508 merged 10 commits into
mainfrom
fix-browser-test

Conversation

@krampstudio

@krampstudio krampstudio commented Apr 22, 2026

Copy link
Copy Markdown
Collaborator

Note

Medium Risk
Touches WebBlob.create header parsing and test fetch behavior; failures would affect streamed/ranged downloads, but changes are small and add validation to reduce silent misbehavior.

Overview
Fixes browser-side WebBlob creation when Content-Length is missing or not usable by validating the content-length header and throwing a clearer error (including x- headers) instead of silently producing an invalid size.

Updates WebBlob tests to avoid relying on CORS-exposed HEAD headers by deriving size from a GET body and injecting a custom fetch that supplies content-length/accept-ranges for the HEAD request. Adds a root lint-staged config to run oxfmt on staged *.{cjs,ts} files.

Reviewed by Cursor Bugbot for commit 015531a. Bugbot is set up for automated code reviews on this repo. Configure here.

@krampstudio
krampstudio marked this pull request as ready for review April 22, 2026 16:20
@krampstudio
krampstudio requested a review from coyotte508 as a code owner April 22, 2026 16:20

@coyotte508 coyotte508 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this fixes the test, but does the problem happen in prod or not?

From a different origin

@krampstudio

krampstudio commented Apr 27, 2026

Copy link
Copy Markdown
Collaborator Author

this fixes the test, but does the problem happen in prod or not?

From a different origin

My understanding was that it has already a fallback to a GET in prod when the HEAD was failing or the Content-Length at 0:

const size = Number(response.headers.get("content-length"));
const contentType = response.headers.get("content-type") || "";
const supportRange = response.headers.get("accept-ranges") === "bytes";
if (!supportRange || size < (opts?.cacheBelow ?? 1_000_000)) {
return await (await customFetch(url)).blob();
}

(I will prevent a NaN here btw to be 100% sure)

Comment thread packages/hub/src/utils/WebBlob.ts Outdated
@coyotte508

coyotte508 commented Apr 27, 2026

Copy link
Copy Markdown
Member

this fixes the test, but does the problem happen in prod or not?
From a different origin

My understanding was that it has already a fallback to a GET in prod when the HEAD was failing or the Content-Length at 0:

const size = Number(response.headers.get("content-length"));
const contentType = response.headers.get("content-type") || "";
const supportRange = response.headers.get("accept-ranges") === "bytes";
if (!supportRange || size < (opts?.cacheBelow ?? 1_000_000)) {
return await (await customFetch(url)).blob();
}

(I will prevent a NaN here btw to be 100% sure)

Ideally though, to avoid downloading the whole blob in memory, CORS issue should be fixed / mitigated in a better way

(finding the root cause is already very nice)

@krampstudio

krampstudio commented May 5, 2026

Copy link
Copy Markdown
Collaborator Author

Ideally though, to avoid downloading the whole blob in memory, CORS issue should be fixed / mitigated in a better way

(finding the root cause is already very nice)

back on this

The only solution I see is to always use GET and cancel reading the body if the server send the accept-ranges header. The downside is the cancel that can be late and we'll start receiving data.
Something like this:

  const size = Number(response.headers.get("content-length") || 0);
  const contentType = response.headers.get("content-type") || "";
  const supportRange = response.headers.get("accept-ranges") === "bytes";

  if (supportRange && size >= (opts?.cacheBelow ?? 1_000_000)) {
    await response.body?.cancel();
    return new WebBlob(url, 0, size, contentType, true, customFetch, opts?.accessToken);
  }

  return response.blob();

Comment thread packages/blob/src/utils/WebBlob.ts

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit af35c19. Configure here.

Comment thread packages/hub/src/utils/WebBlob.ts
@coyotte508
coyotte508 marked this pull request as draft May 7, 2026 16:59
coyotte508 and others added 4 commits May 7, 2026 19:00
In browsers, when CloudFront gzips a response on the fly (typical for
small text/JSON files behind /api/resolve-cache/...), the cached
response loses both Content-Length and Accept-Ranges. Subsequent HEAD
requests served from the same cache entry inherit the missing headers,
so the lib could not tell either the file size or whether ranges were
supported, and silently fell back to buffering the whole blob in RAM.

Range responses are never content-encoded, so Content-Range (which
carries the total file size) and the strong ETag always survive
regardless of the cached encoding state. Switching the discovery probe
from HEAD to GET Range: bytes=0-0 gives us size + range support in a
single round trip and removes the test flake without any server change.

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
@coyotte508
coyotte508 marked this pull request as ready for review May 7, 2026 17:31
@coyotte508
coyotte508 merged commit ac45210 into main May 7, 2026
6 checks passed
@coyotte508
coyotte508 deleted the fix-browser-test branch May 7, 2026 17:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants