Skip to content

fix: strip client selector from request options (breaks Deno / edge runtimes) - #9

Merged
Ooscaar merged 2 commits into
mainfrom
fix/deno-request-init
Aug 10, 2026
Merged

Ooscaar merged 2 commits into
mainfrom
fix/deno-request-init

Conversation

@Ooscaar

@Ooscaar Ooscaar commented Aug 10, 2026

Copy link
Copy Markdown
Member

Why

Every SDK call throws on Deno-based runtimes (Supabase Edge Functions, Deno Deploy) before any network I/O:

TypeError: Failed to construct 'Request': Argument 2 `client` must be a Deno.HttpClient

_bind injects the per-instance client into each operation's options under the client key, and @hey-api/client-fetch spreads that whole options object into the fetch RequestInit. Node's undici silently ignores the unknown field (which is why the Node-only suite never caught it), but Deno defines its own client init option (a Deno.HttpClient) and validates it, so new Request(...) throws. The SDK is effectively unusable on those runtimes.

This was reported with an excellent diagnosis in #8 (thanks @henrikra!). This PR lands the same fix with two changes:

  • Regeneration safety: src/client.ts is generated by scripts/generate-client.ts, so a fix applied only to client.ts (as in fix: stop leaking the client selector into RequestInit (breaks Deno / edge runtimes) #8) would be silently wiped on the next npm run generate. This PR applies the fix in the generator template as well.
  • No monkey-patching: instead of reassigning methods on the hey-api client object in place, _bind injects a thin wrapper that leaves the third-party object untouched.

Upstream tracking: this is a known hey-api bug (hey-api/hey-api#4177) with an unmerged fix (hey-api/hey-api#4178). No released version of @hey-api/client-fetch (deprecated at 0.13.1) or the bundled-client architecture fixes it, so a downstream workaround is currently the only option. A TODO marks it for removal once upstream ships.

What

  • Added _stripClientSelector() + _dispatchClient to src/client.ts: a wrapper around the per-instance client that delegates everything to it but strips the client selector from request options before hey-api builds the Request; _bind now injects the wrapper. Config and interceptors stay on the real client, per-instance isolation is unchanged.
  • Applied the identical change to the template in scripts/generate-client.ts so regeneration preserves the fix.
  • Added tests/request-init.test.ts: captures the RequestInit at new Request time (the only way to observe this on Node), asserts the selector never leaks, and verifies auth-header routing and two-instance isolation. Fails on main, passes with this change.

Verification:

  • Full suite: 178/178 passing; tsc --noEmit and eslint clean.
  • Real Deno 2.9.5 with stubbed fetch: the main build reproduces the exact TypeError; this build succeeds with the auth header intact.
  • Live end-to-end on both Node and Deno: accounts.listAccounts and profiles.listProfiles return 200 with byte-identical payloads.

Closes #8 (supersedes it — see regeneration note above; happy to defer to it instead if preferred).

Follow-ups

🤖 Generated with Claude Code

Ooscaar and others added 2 commits August 10, 2026 17:37
…untimes)

_bind injects the per-instance client into operation options under the
`client` key, and @hey-api/client-fetch spreads the whole options object
into the fetch RequestInit. Deno defines its own `client` RequestInit
option (a Deno.HttpClient) and validates it, so new Request(...) threw
and every SDK call failed on Deno, Deno Deploy, and Supabase Edge
Functions. Node's undici silently ignores the stray key, which is why
the suite never caught it.

Operations now dispatch through a wrapper client whose HTTP methods
strip the selector before hey-api builds the request; the real client
(config, interceptors) is untouched. Applied in both src/client.ts and
the generate-client.ts template so regeneration preserves the fix.

Workaround for hey-api/hey-api#4177 — remove
once the upstream fix ships and the dependency can be upgraded.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Deno and other WinterCG runtimes validate RequestInit strictly, so bugs
that leak internal SDK fields into new Request(...) are invisible to the
Node-only suite but break every call on Deno Deploy / Supabase Edge
Functions. The new CI job builds the bundle and runs a real SDK call
under Deno against a stubbed fetch (no network, no credentials); the
tests fail on the pre-fix build and pass with the fix.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@Ooscaar
Ooscaar merged commit 61e8d64 into main Aug 10, 2026
2 checks passed
Ooscaar added a commit that referenced this pull request Aug 10, 2026
Sync main with the manually dispatched publish of 0.2.544 (Deno /
edge-runtime fix, #9) so the next auto-release bumps cleanly.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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.

1 participant