Last 12 weeks Β· 5 commits
4 of 6 standards met
Summary When a response has an empty body (for example a with ), never fires with . The documented guarantee is that always reports completion, but for empty bodies the final event is skipped. Root cause In , the transform stream's only emits the final progress event inside an block. For an empty body no chunk is ever read, so stays and the final event is never emitted. Reproduction Proposed fix Move the final progress emission out of the guard so it always fires on flush, using an empty when the body was empty: I have a branch ready with the fix and a redβgreen test (18/18 passing): . Happy to open a PR if you'd like.
Closes https://github.com/sindresorhus/ky/issues/876 This PR aims to give users the ability to handle empty bodies gracefully. Previously, the option would be ignored if the body were empty. Now it is called, allowing it to replace an empty body with any desired value. Since there were negative tests for this specific scenario, strictly speaking this is semver major. However, it is intended to be an opt-in feature that enables 1.x-like behavior, without having an opinionated default of doing so as we did in Ky 1.x. The default is still to match and throw if the user tries to use to parse an empty body, for example.
Version: 2.0.2 Browser: Chrome (Brave) Hi! I am currently facing an issue when my server responds with a while simultaneously sending , which results in "Unexpected end of JSON input" error. From #732 my understanding is that Ky is supposed to shortcut on 204 and empty responses to avoid calling unnecessary json decoding. However, since that issue and subsequent PR, some changes were introduced and now empty JSON responses are handled with (if no is passed): I believe that at the end there should be return (, or whatever). _OR_ a check for custom which would handle the case.
Disclaimer: I used Fable 5 to debug and fix this issue. The title and description is also written by Claude. As a developer, I can confirm that this is a real issue and verified the fix myself. I have experienced this issue in two of my browser extensions in Firefox. Summary ky is currently unusable inside Firefox WebExtension content scripts: every request throws synchronously during request construction, before is ever called β even with zero headers or options configured. Chrome extensions are unaffected. Regressions like this are easy to miss because the throw happens inside the caller (e.g. a TanStack Query ), which often swallows it β the visible symptom is just "no requests are made, no errors anywhere". ky: 2.0.2 Firefox Developer Edition: 153.0b13 (manifest v3 extension, content script declared via in the manifest) Bundler: esbuild (no transforms relevant here β the shipped code contains the same iteration) Root cause In Firefox, content scripts see page DOM objects through Xray vision. Xray wrappers expose string-keyed WebIDL methods (, , , β¦) but filter out symbol-keyed properties β which means the pair-iteration protocol (, and the iterator objects returned by ) does not work on , , or in a content script. A two-line content script demonstrates it with no ky involved: does exactly this on every request β it runs unconditionally in the constructor (), constructing a even when both sources are empty, then pair-iterating it: https://github.com/sindresorhus/ky/blob/v2.0.2/source/utils/merge.ts#L64-L77 Chrome is unaffected because its content-script isolated worlds get their own native copies of these classes rather than wrappers, so iteration works there. All affected sites (request path) Fixing alone just moves the crash to the next iteration site. These are all of them in v2.0.2: 1. β , (the crash above; hit by every request) 2. β , (hit when is a ) 3. β string branch, 4. β searchParamsβURL merge, (hit by every request using ) 5. β , over Repro Full runnable repro: https://github.com/timche/ky-firefox-content-script-repro It's a prebuilt manifest v3 extension β no build step needed: 1. Firefox β β Load Temporary Add-onβ¦ β select . 2. Open https://example.com and its DevTools console. 3. Both parts throw: the two-line pair-iteration demonstration (no ky involved), and the ky request, which dies synchronously in before β nothing appears in the Network tab. Loading the same folder in Chrome (steps in the README) shows the contrast: iteration works and the ky request reaches the network. The essence, for reference, is just a content script doing: Suggested fix Replace pair iteration with at the five sites β is a string-keyed WebIDL method that works through Xray wrappers, is supported everywhere is, and the change is semantics-preserving (same visitation order): I've verified this fix end-to-end: patched this way in our extension (via ), and all requests work in a test that simulates the Xray condition (strip / from the native classes) across plain GETs, records, with repeated keys, and JSON POSTs β plus in the real extension in Firefox. Workaround for anyone hitting this Patch the five sites to with your package manager's patch mechanism ( / ), or use a different HTTP client in Firefox content scripts.
Problem accepts a number as shorthand for (per the docs: "If is a number, it will be used as and other defaults will remain in place."). However, when a numeric is set on a parent instance and then extended with an object, the numeric limit is silently dropped and falls back to the default (): The reverse direction (object on the parent, number on the child) and the all-object case both work correctly β only the number β object merge loses data. Cause In , is merged like any other nested object. When the parent value is the numeric shorthand () and the incoming value is an object, the recursion ends up as . A non-object source is skipped entirely by , so the is discarded and only survives β the limit is lost. Fix Expand the numeric shorthand to before the deep merge, so extending it with an object preserves the limit. This mirrors the documented shorthand semantics and leaves every other case (object β object, object β number replacement, ) unchanged. Test Added a test in that sets on a parent, extends it with , and asserts the request is attempted times. It fails on (3 attempts) and passes with the fix (4 attempts).
Repository: sindresorhus/ky. Description: π³ Tiny & elegant JavaScript HTTP client based on the Fetch API Stars: 17042, Forks: 488. Primary language: TypeScript. Languages: TypeScript (100%). License: MIT. Topics: fetch, http-client, http-request, javascript, js, json, npm-package, request, rest, tiny, whatwg-fetch. Latest release: v2.0.2 (4mo ago). Open PRs: 1, open issues: 2. Last activity: 1mo ago. Community health: 85%. Top contributors: sindresorhus, sholladay, szmarczak, whitecrownclown, clicktodev, mgcrea, jabuj, poppinlp, joaovieira, cristobal and others.