What is missing
A native screen's JavaScript context has the language intrinsics plus what the
runtime assigns (fetch, craft, the timer shims). It does not have
URL, URLSearchParams or TextEncoder, and nothing shims them.
Why it matters
These are the APIs you reach for when building a request, and reaching for one
fails in the worst possible way: silently, at runtime, inside a try that an
app has for other reasons.
Ours cost a screen that made no request at all while every test passed. A shared module built its query the obvious way:
// shared by the web page and the native screen
export function leaderboardQuery(...): string {
const params = new URLSearchParams()
...
return params.toString()
}In the browser: fine. On a native screen: URLSearchParams is not defined, the
load path aborts, the screen renders its empty state, and nothing anywhere says
why. Type-checking is happy — URLSearchParams is in the ambient DOM lib — and
so is the linter.
It is not a one-off. Every query string in our shared modules is now hand-built
with encodeURIComponent, and each one carries a comment explaining why,
because the next person's instinct will be to tidy it back:
// Built by hand rather than with `URLSearchParams`: a native screen has
// none, and the failure is a screen that issues no request at all.
let path = `/api/territories/map?limit=${TERRITORY_LIMIT}`We eventually wrote a repo gate that walks every module a native screen imports
and fails the build on URLSearchParams, new URL(, TextEncoder,
localStorage and friends. That gate is pure overhead that exists because the
runtime cannot answer for itself.
What would help
Either of these would do, in order of preference:
- Provide them.
URLandURLSearchParamsare self-contained and implementable in JS over the intrinsics;TextEncoderis a small amount of UTF-8. Injecting them besidefetchwould make shared browser/native code portable by default. - Fail loudly. If they are deliberately out of scope, a stub that throws
URLSearchParams is not available on a native screen — build the query with encodeURIComponentwould turn a silent dead screen into a one-line fix. At present the ReferenceError surfaces wherever the caller happens to catch.
A documented list of exactly what a native context provides would help either way. We established ours empirically, by running code in a bare JS context and seeing what threw.
Versions
craft-native 0.0.237, @stacksjs/stx 0.2.563, iOS 26.5 simulator.