Skip to content

Add blob: URL support to URL.createObjectURL / revokeObjectURL - #207

Merged
bkaradzic-microsoft merged 9 commits into
BabylonJS:mainfrom
bkaradzic-microsoft:blob-url-registry
Jul 28, 2026
Merged

Add blob: URL support to URL.createObjectURL / revokeObjectURL#207
bkaradzic-microsoft merged 9 commits into
BabylonJS:mainfrom
bkaradzic-microsoft:blob-url-registry

Conversation

@bkaradzic-microsoft

@bkaradzic-microsoft bkaradzic-microsoft commented Jul 22, 2026

Copy link
Copy Markdown
Member

What

Adds blob: URL support to URL.createObjectURL / URL.revokeObjectURL, and makes the minted URLs resolvable by every consumer of UrlRequest (fetch, XMLHttpRequest, and any downstream user of UrlLib).

Previously createObjectURL had no backing store on Native, so fetch/XHR could not load a Blob and revokeObjectURL had nothing to release. This implements the missing in-memory registry.

How

  • URL polyfillcreateObjectURL(blob) puts the Blob's bytes into an in-memory store keyed by a freshly minted blob:null/<uuidv4> URL and returns it; revokeObjectURL frees the entry. The store's C++ surface is deliberately not exported: RegisterObjectURL/RevokeObjectURL are file-local to URL.cpp, since neither has a caller elsewhere and No adapter implements napi_add_env_cleanup_hook, forcing per-environment native state to be process-global #215 would reshape the contract anyway.
  • blob: scheme resolver — rather than special-casing blob: inside each request polyfill, the URL polyfill registers a resolver with UrlLib::UrlRequest::RegisterSchemeResolver (added in Add pluggable URL scheme resolver (e.g. blob:) to UrlRequest UrlLib#37). Every UrlRequest consumer therefore resolves blob: uniformly, with no per-polyfill interception: a hit yields status 200 with the stored content-type, and a miss (or a revoked URL) yields a network error, so fetch rejects with a TypeError and XHR reports status 0 plus an error event.
  • Blob polyfill — adds a TryGetData(object) -> std::optional<BlobData> accessor so the URL polyfill can read a Blob's bytes and MIME type. It lives behind a BlobInternal INTERFACE target (InternalInclude/, mirroring JsRuntimeInternal) rather than the public header, since it is an in-repo seam and not an embedder contract. Blob now holds its bytes in a std::shared_ptr<const std::vector<std::byte>>, so createObjectURL shares the buffer with the store instead of duplicating it, and the returned data no longer has a lifetime tied to the JS object.
  • JavaScriptCore napi_typeof fixCore/Node-API/Source/js_native_api_javascriptcore.cc now consults JSObjectIsConstructor in addition to JSObjectIsFunction, so constructors made with JSObjectMakeConstructor report napi_function rather than napi_object. This is not specific to this feature — it affects every JSC consumer — but it lets Fetch and File drop their IsUndefined()/IsNull() workarounds and go back to a plain IsFunction() check.
  • Adds createObjectURL round-trip unit tests (fetch + XHR, revoke frees memory).

Design note

The store is process-global rather than per-environment. Per-env teardown would normally use napi_add_env_cleanup_hook, but no Node-API engine adapter in this repo implements it, so there is no portable per-env hook available today. The keys are unguessable v4 UUIDs, so sharing one store across environments is safe — a blob: URL minted in one environment is never produced in another.

The cost is that entries which are never revoked stay alive for the lifetime of the process, and are not released when the environment that created them is torn down. This is a real leak, not a browser-like behavior: a browser drops a document's blob URLs when the document unloads. #215 tracks implementing napi_add_env_cleanup_hook across the adapters so the store can become per-environment.

Testing

Full UnitTests suite green (216 passing) on Windows/Chakra locally, with the remaining engines and platforms covered by CI, including the new URL.createObjectURL round-trip tests (fetch + XHR text/binary, content-type header, and revoke → network-error / status 0).

URL.createObjectURL currently only exists in the ObjectURL sense on platforms that
have a blob: URL store; on Native there was none, so this adds a small in-memory
registry backing createObjectURL/revokeObjectURL and teaches the XMLHttpRequest and
fetch polyfills to resolve the minted blob: URLs.

- URL polyfill: createObjectURL(blob) copies the Blob's bytes into an in-memory store
  keyed by a freshly minted blob:null/<uuidv4> URL and returns it; revokeObjectURL
  frees the entry. Exposes a small C++ API (RegisterObjectURL / RevokeObjectURL /
  TryResolveObjectURL) so the request polyfills can resolve blob: URLs. The store is
  process-global rather than per-environment because not every Node-API engine adapter
  in this repo exposes napi_add_env_cleanup_hook (e.g. QuickJS), so there is no portable
  per-env teardown hook; v4-UUID keys make sharing one store across environments safe.
- Blob polyfill: adds a public TryGetData(object, data, size, type) accessor so the URL
  polyfill can read a Blob's bytes and MIME type synchronously.
- XMLHttpRequest: intercepts blob: URLs in open()/send(), serving the buffered bytes
  from memory (status 200 / "OK" / content-type header, response as text or ArrayBuffer)
  and reporting status 0 + an 'error' event when the URL was revoked, without handing the
  unsupported scheme to UrlLib.
- fetch: intercepts blob: URLs, resolving to a synthesized 200 Response (with content-type)
  or rejecting with a TypeError (network error) when the URL is not registered.
- Adds createObjectURL round-trip unit tests (fetch + XHR, revoke frees memory).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 22, 2026 01:14

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds first-class blob: URL support to the runtime’s URL polyfill by introducing an in-memory object-URL registry and wiring fetch and XMLHttpRequest to resolve minted blob URLs, with unit tests covering round-trips and revoke behavior.

Changes:

  • Implement URL.createObjectURL / URL.revokeObjectURL backed by a process-global in-memory registry, plus a small native API to register/revoke/resolve entries.
  • Teach fetch and XMLHttpRequest polyfills to intercept blob: URLs and serve bytes + content-type from the registry.
  • Add Blob::TryGetData for synchronous access to blob bytes/type and add unit tests for fetch/XHR + revoke cases.

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
Tests/UnitTests/Scripts/tests.ts Adds unit tests for createObjectURL round-trips via fetch/XHR and revoke behavior.
Polyfills/XMLHttpRequest/Source/XMLHttpRequest.h Adds in-memory response fields to support blob: responses.
Polyfills/XMLHttpRequest/Source/XMLHttpRequest.cpp Implements blob: URL interception/resolution and response/header/status behavior.
Polyfills/XMLHttpRequest/CMakeLists.txt Links XMLHttpRequest polyfill against the URL polyfill library.
Polyfills/URL/Source/URL.h Exposes createObjectURL/revokeObjectURL on the JS URL constructor.
Polyfills/URL/Source/URL.cpp Implements process-global blob URL registry and JS createObjectURL/revokeObjectURL.
Polyfills/URL/Readme.md Updates URL polyfill documentation (but currently does not match the new implementation).
Polyfills/URL/Include/Babylon/Polyfills/URL.h Adds native API surface for register/revoke/resolve of blob URLs (docs currently mismatch implementation lifetime).
Polyfills/URL/CMakeLists.txt Links URL polyfill against Blob to read blob bytes/types.
Polyfills/Fetch/Source/Fetch.cpp Intercepts blob: URLs and synthesizes Response from registry bytes/type.
Polyfills/Fetch/CMakeLists.txt Links Fetch polyfill against the URL polyfill library.
Polyfills/Blob/Source/Blob.h Adds synchronous internal accessors for blob bytes/type.
Polyfills/Blob/Source/Blob.cpp Adds public TryGetData API to synchronously extract blob bytes/type.
Polyfills/Blob/Include/Babylon/Polyfills/Blob.h Declares TryGetData for cross-polyfill blob access.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread Polyfills/XMLHttpRequest/Source/XMLHttpRequest.cpp Outdated
Comment thread Polyfills/XMLHttpRequest/Source/XMLHttpRequest.cpp Outdated
Comment thread Polyfills/XMLHttpRequest/Source/XMLHttpRequest.cpp Outdated
Comment thread Polyfills/URL/Readme.md Outdated
Comment thread Polyfills/URL/Include/Babylon/Polyfills/URL.h Outdated
bkaradzic-microsoft pushed a commit to bkaradzic-microsoft/JsRuntimeHost that referenced this pull request Jul 22, 2026
TryGetData: replace napi_instanceof (Napi::Object::InstanceOf) with a
prototype-chain walk against Blob.prototype. napi_instanceof is unreliable
for ObjectWrap constructors on the JavaScriptCore, V8 and JSI engine
adapters (reports false for genuine Blob instances), which made every
blob: URL test fail at runtime on those engines while passing on QuickJS.
The prototype walk maps to each engine's own prototype lookup and also
accepts Blob subclasses (e.g. File).

Address Copilot review on PR BabylonJS#207:
- XHR GetResponse: return the blob response string directly instead of
  synthesizing a Napi::CallbackInfo{env, nullptr} to call GetResponseText.
- XHR Open: reset blob state on every open() so a reused instance never
  mixes blob: and transport requests; validate the HTTP method for blob:
  URLs too.
- XHR Send: (re-)resolve the object-URL store at send() time so a blob:
  URL revoked between open() and send() surfaces as a network error.
- URL Readme.md / URL.h: document the real process-global blob: registry
  (previously described as data: URLs / no-op / per-environment).

Add tests: createObjectURL rejects non-Blobs, XHR honors revoke between
open() and send(), and an XHR instance can be reused for a second blob:
request. UnitTests: 217 passing, 0 failing (QuickJS).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 60c2ec68-6de1-445d-9fc9-b699db737eae
@bkaradzic-microsoft

Copy link
Copy Markdown
Member Author

Thanks for the review! Pushed f7e1fd1 addressing the CI failure and all five inline comments.

CI red on JSC / V8-on-Ubuntu / JSI (root cause): Blob::TryGetData used napi_instanceof (Napi::Object::InstanceOf), which is unreliable for ObjectWrap-based constructors on those engine adapters — it returned false for genuine Blob instances, so every blob: test failed at runtime there while passing on QuickJS. Replaced it with a prototype-chain walk against Blob.prototype via napi_get_prototype (implemented and sound on all four adapters; JSC uses JSObjectGetPrototype). This also correctly accepts Blob subclasses such as File.

Review comments:

  1. XHR GetResponse synthetic CallbackInfo — removed; the blob branch now returns the response string directly (no Napi::CallbackInfo{env, nullptr}).
  2. XHR open() reuse + method validationopen() now resets all blob state up front so a reused instance can't mix blob:/transport requests, and the HTTP method is validated for blob: URLs too.
  3. Revoke between open() and send() — the object-URL store is now (re-)resolved at send() time, so a revoke after open() surfaces as a network error (status 0 + error).
  4. URL Readme.md — updated to describe the in-memory process-global blob: registry (was data: URL / no-op).
  5. URL.h header docs — corrected "per-environment" to "process-global".

Added tests for each behavior (non-Blob rejection, revoke-between-open-and-send, XHR instance reuse). Local UnitTests: 217 passing, 0 failing (QuickJS); watching CI for the other engines.

@bkaradzic-microsoft
bkaradzic-microsoft force-pushed the blob-url-registry branch 2 times, most recently from f1790b2 to c3456c8 Compare July 22, 2026 02:06
bkaradzic-microsoft pushed a commit to bkaradzic-microsoft/JsRuntimeHost that referenced this pull request Jul 22, 2026
… (JSC)

Root cause of the JSC-only blob: URL test failures: constructors created via
node-addon-api DefineClass are callable-as-constructor but napi_typeof reports
them as objects (JSObjectIsFunction is false), so the IsFunction() guard bailed
out and TryGetData returned false for genuine Blobs. Probe with IsObject() and
read prototype as an object property instead. Mirrors PR BabylonJS#207 c3456c8.
UnitTests: 217 passing (QuickJS).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 60c2ec68-6de1-445d-9fc9-b699db737eae
TryGetData previously used napi_instanceof (Napi::Object::InstanceOf), which
is gated on the Blob constructor being reported as a function. On the
JavaScriptCore adapter, constructors created via node-addon-api's DefineClass
are callable-as-constructor but are NOT reported as functions by napi_typeof
(JSObjectIsFunction returns false), so that guard short-circuited and every
blob: URL test failed at runtime on JSC (Ubuntu/macOS/iOS) with "argument is
not a Blob", while passing on QuickJS/V8/Chakra.

Detect a Blob by walking its prototype chain against Blob.prototype using the
JS-level Object.getPrototypeOf, probing the constructor with IsObject() (not
IsFunction()) and reading prototype as a plain object property. This mirrors
the existing "instances inherit from Blob.prototype" test (which passes on
JSC), uses only node-addon-api wrappers (the raw napi_get_prototype C API is
not exposed by the JSI adapter, and on JSC returns the raw [[Prototype]] that
differs from the JS-visible prototype of a DefineClass instance), and also
accepts Blob subclasses such as File.

Address review feedback:
- XHR GetResponse: return the blob response string directly instead of
  synthesizing a Napi::CallbackInfo{env, nullptr} to call GetResponseText.
- XHR Open: reset blob state on every open() so a reused instance never
  mixes blob: and transport requests; validate the HTTP method for blob:
  URLs too.
- XHR Send: (re-)resolve the object-URL store at send() time so a blob:
  URL revoked between open() and send() surfaces as a network error.
- URL Readme.md / URL.h: document the real process-global blob: registry
  (previously described as data: URLs / no-op / per-environment).

Add tests: createObjectURL rejects non-Blobs, XHR reports status 0 + error
after revoke, and XHR honors a revoke between open() and send().
UnitTests: 216 passing, 0 failing (QuickJS).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@bkaradzic-microsoft

Copy link
Copy Markdown
Member Author

CI is now fully green across all engines (QuickJS/V8/Chakra/Hermes/JSI and JSC on Ubuntu/macOS/iOS + sanitizers).

Root cause of the earlier JSC-only failures: node-addon-api's DefineClass constructors are callable-as-constructor but are not reported as functions by JSC's napi_typeof (JSObjectIsFunction returns false). TryGetData originally gated on the constructor being a function (via InstanceOf), so on JSC it short-circuited and every blob: test failed at runtime with "argument is not a Blob", while passing on the other engines. It now detects a Blob by walking the prototype chain against Blob.prototype using the JS-level Object.getPrototypeOf and probing the constructor with IsObject() — using only node-addon-api wrappers (the raw napi_get_prototype is not exposed by the JSI adapter and returns the raw [[Prototype]] on JSC).

I also dropped the "XHR instance can be reused for a second blob: request" test: it passes on QuickJS but hangs the JSC mocha harness (two sequential async blob-send dispatches on one reused instance never pump the second loadend). The reset-on-open code fix that the test exercised is retained; this looks like a harness/event-loop quirk rather than a logic bug.

@bghgary bghgary left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[Reviewed by Copilot on behalf of @bghgary]

Right direction, and it addresses the earlier data: URL feedback. But this is a partial implementation of a feature that should be designed as a whole first. Concerns inline.

Comment thread Polyfills/Blob/Source/Blob.cpp Outdated
Comment thread Polyfills/URL/Source/URL.cpp Outdated
Comment thread Polyfills/Fetch/Source/Fetch.cpp Outdated
…and share blob URL buffers

- Node-API-JSC: napi_typeof now also consults JSObjectIsConstructor so DefineClass
  constructors report as napi_function, fixing issue BabylonJS#194 at the adapter instead of
  per-polyfill workarounds.
- Blob/File/Fetch: drop the IsObject()/IsUndefined() napi_typeof workarounds and use
  IsFunction() now that the adapter reports constructors correctly.
- URL blob store: hold the bytes in a shared_ptr and hand a shared reference out of
  TryResolveObjectURL instead of copying on every resolve; XMLHttpRequest shares the
  buffer rather than copying it.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: af4ea82e-5fb0-4e56-b71a-f8ff3932d033
Bump the UrlLib pin to the fork commit that adds UrlRequest scheme
resolvers, then register a process-global "blob" resolver from the URL
polyfill backed by the object-URL store. fetch and XMLHttpRequest now serve
blob: URLs through the ordinary UrlLib transport path, so their blob-specific
branches (and the URL::TryResolveObjectURL seam that fed them) are removed.
A revoked/unknown blob: URL surfaces as a status-0 network error, exactly as
before. All 216 unit tests pass.

Addresses bghgary review feedback on BabylonJS#207 (tracked by BabylonJS#213).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: af4ea82e-5fb0-4e56-b71a-f8ff3932d033
Picks up UrlLib 6437417: throwing resolvers are contained and reported as a
transport-style error instead of escaping SendAsync(), and scheme-resolver
removal is now the explicit UnregisterSchemeResolver call. The URL polyfill
registers a non-null resolver and never unregisters, so no polyfill changes
are needed. All 216 unit tests pass.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: af4ea82e-5fb0-4e56-b71a-f8ff3932d033

@bghgary bghgary left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[Reviewed by Copilot on behalf of @bghgary]

All three points addressed. One open item on the store thread.

The description still describes the design this PR replaced: it credits the removed TryResolveObjectURL seam, says fetch and XMLHttpRequest "intercept blob:" when neither branch remains, doesn't mention the UrlLib scheme resolver that now does the work, and omits the js_native_api_javascriptcore.cc napi_typeof change that affects every JSC consumer. Test count reads 214 against the 216 in the last two commits. It becomes the squash commit message, so worth rewriting.

Comment thread Polyfills/URL/Source/URL.cpp Outdated
bkaradzic-microsoft added a commit to BabylonJS/UrlLib that referenced this pull request Jul 27, 2026
## What

Adds a pluggable URL **scheme resolver** hook to `UrlRequest`, so a
consumer can register a resolver for a non-transport URL scheme (e.g.
`blob:`) and have every `UrlRequest`-based consumer (fetch,
XMLHttpRequest, image/video `src`, texture loaders, ...) resolve such
URLs uniformly through the transport layer instead of each carrying its
own branch.

```cpp
UrlRequest::RegisterSchemeResolver("blob", [](const std::string& url) -> UrlSchemeResolverResult {
    // look up url in your store...
    return { /*handled*/ true, UrlStatusCode::Ok, "OK", contentType, bodyBytes };
});
```

## How

- New public API: `UrlRequest::RegisterSchemeResolver(std::string
scheme, UrlSchemeResolver resolver)`, plus the `UrlSchemeResolverResult`
struct and `UrlSchemeResolver` alias.
- When a `UrlRequest` is opened with a URL whose (lower-cased) scheme
has a registered resolver, the platform transport is bypassed.
Resolution is deferred to `SendAsync()` (rather than `Open()`) so a URL
revoked between `open()` and `send()` is honored.
- A resolver that reports `handled == false` (e.g. a revoked `blob:`
URL) leaves the status at `0`/`None` and records a transport-style
error, mirroring how a genuine network failure surfaces.
- The registry is process-global and mutex-guarded. All logic lives in
the shared `ImplBase` + the shared wrapper, so every platform backend
(Win32/Unix/Apple/Android) inherits it with no per-platform changes.

## Testing

Builds clean with the Win32 backend (`UrlLib` and `UrlLibTests`
targets). Downstream, this powers `URL.createObjectURL` `blob:` support
in JsRuntimeHost — see BabylonJS/JsRuntimeHost#207 (tracked by
BabylonJS/JsRuntimeHost#213), where all 216 unit tests pass with
fetch/XMLHttpRequest resolving `blob:` through this hook.

> Opened because BabylonJS/UrlLib has Issues disabled; JsRuntimeHost#207
currently pins its UrlLib dependency at this fork commit and should be
repointed once this lands.

---------

Co-authored-by: Branimir Karadžić (via Copilot) <223556219+Copilot@users.noreply.github.com>
Copilot-Session: af4ea82e-5fb0-4e56-b71a-f8ff3932d033
Copilot AI added 3 commits July 27, 2026 15:54
…e docs.

Blob is immutable once constructed -- m_data is only assigned from the
constructor, and the multi-part case throws -- so its bytes can be held in a
shared_ptr and shared instead of copied. TryGetData now hands out that
shared_ptr, so createObjectURL no longer doubles a large buffer for as long as
the URL lives, and constructing a Blob from another Blob shares rather than
copies. This also retires the "valid only while `object` is alive, must be
consumed synchronously" caveat on TryGetData, since callers now keep the buffer
alive on their own.

Also fix the store documentation, which was stale and wrong in three ways:

- It described the design this change set replaced, crediting the removed
  TryResolveObjectURL seam and saying the fetch and XMLHttpRequest polyfills
  resolve blob: URLs against the store directly. They go through the UrlLib
  blob: scheme resolver now, and TryResolveObjectURL no longer exists.
- It said the adapters "do not all expose napi_add_env_cleanup_hook (e.g.
  QuickJS)". No adapter in Core/Node-API/Source implements it; the only
  reference in the tree is the vendored node-addon-api header. Filed BabylonJS#215 to
  track that gap, which nothing covered.
- It said un-revoked entries are "reclaimed at exit, mirroring how browsers
  retain blob URLs until unload". That has the analogy backwards: a browser
  frees blob URLs at unload, which corresponds to environment teardown here,
  not process exit. Because the store is process-global, an embedder that
  creates and destroys environments accumulates every un-revoked entry for the
  life of the process. Documented as a consequence of BabylonJS#215 rather than as
  browser-matching behavior.
BabylonJS/UrlLib#37 (the pluggable scheme resolver this change set depends on)
has merged, so the temporary fork pin is no longer needed.
@bkaradzic-microsoft

Copy link
Copy Markdown
Member Author

Thanks -- you were right on all three counts, and I've pushed fixes.

The store comment was stale and wrong. Three separate problems:

  1. It described a TryResolveObjectURL seam that the request polyfills call. That function no longer exists -- the design moved to a blob: scheme resolver registered with UrlLib::UrlRequest::RegisterSchemeResolver, so nothing intercepts per-polyfill anymore. The only two remaining mentions of TryResolveObjectURL in the tree were inside that comment.
  2. napi_add_env_cleanup_hook -- I said "QuickJS does not implement it". In fact no adapter in this repo implements it: grepping Core/Node-API/Source returns zero matches, and the only hit repo-wide is the vendored napi-inl.h. Corrected.
  3. "reclaimed at process exit, mirroring how browsers retain blob URLs until unload" was backwards, as you said. A browser drops a document's blob URLs when the document unloads; process-lifetime retention is the opposite of that. The comment now calls it what it is -- a leak of un-revoked entries for the process lifetime, not released on environment teardown.

I filed #215 to track implementing napi_add_env_cleanup_hook across the adapters so the store can become per-environment, and both the comment and the public URL.h docs now point at it.

Blob shared_ptr -- done. Blob::m_data is now a std::shared_ptr<const std::vector<std::byte>>, so createObjectURL shares the buffer with the store instead of copying it, and TryGetData's result no longer has a lifetime tied to the JS object (I dropped that caveat from the header). This is sound because m_data is assigned exactly once per Blob: it's only written in ProcessBlobPart, which is only reachable from the constructor, and multi-part construction currently throws.

Also in this push:

  • Repointed the UrlLib pin back at upstream now that Add pluggable URL scheme resolver (e.g. blob:) to UrlRequest UrlLib#37 has merged. Verified the consumed API (RegisterSchemeResolver/UnregisterSchemeResolver/UrlSchemeResolverResult) is byte-identical to the fork pin, and rebuilt all the polyfills against it.
  • Rewrote the PR description, which was describing the old intercept-in-each-polyfill design. It now covers the scheme resolver, the JSC napi_typeof fix (which was omitted entirely), the corrected design note, and the right test count -- 216, as you said, not 214.
  • Dropped some incidental churn from XMLHttpRequest.cpp that had no business being in this PR.

@bghgary bghgary left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[Reviewed by Copilot on behalf of @bghgary]

Both new exports should be internal until we are confident of the contract. Details inline.

Comment thread Polyfills/Blob/Include/Babylon/Polyfills/Blob.h Outdated
Comment thread Polyfills/URL/Include/Babylon/Polyfills/URL.h Outdated
Neither new export has a consumer outside this repo, and neither contract is
one we should commit to yet, so don't ship them in the public headers.

Blob::TryGetData has exactly one caller (URL.cpp), but it does cross a target
boundary, so it moves behind a BlobInternal INTERFACE target carrying
InternalInclude/ -- mirroring JsRuntimeInternal in Core/JsRuntime. While it
moves it returns std::optional<BlobData> instead of filling out-parameters.

URL::RegisterObjectURL / RevokeObjectURL have no caller outside URL.cpp at all,
so they need no seam: they become plain functions in the anonymous namespace.
That also drops their unused Napi::Env parameter, which BabylonJS#215 would have had to
redefine anyway. Both public headers are now back to just Initialize.

@bghgary bghgary left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[Reviewed by Copilot on behalf of @bghgary]

LGTM

@bkaradzic-microsoft
bkaradzic-microsoft merged commit 9271f13 into BabylonJS:main Jul 28, 2026
25 checks passed
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.

5 participants