Skip to content

feat!: require node 22.12 or higher, use native fetch#1217

Draft
rexxars wants to merge 20 commits into
mainfrom
feat/get-it-9
Draft

feat!: require node 22.12 or higher, use native fetch#1217
rexxars wants to merge 20 commits into
mainfrom
feat/get-it-9

Conversation

@rexxars
Copy link
Copy Markdown
Member

@rexxars rexxars commented May 21, 2026

Description

What to review

Testing

@vercel
Copy link
Copy Markdown

vercel Bot commented May 21, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
tsdocs-client Ignored Ignored Jun 2, 2026 8:08pm

Request Review

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 21, 2026

Coverage Report

Status Category Percentage Covered / Total
🔵 Lines 83.53% 1588 / 1901
🔵 Statements 83.33% 1655 / 1986
🔵 Functions 80.04% 397 / 496
🔵 Branches 81.87% 1197 / 1462
File Coverage
File Stmts Branches Functions Lines Uncovered Lines
Changed Files
src/SanityClient.ts 67.3% 63.46% 55.55% 67.3% 120, 152-1091, 1110-1120, 1343-1346, 2153
src/defineCreateClient.ts 100% 100% 100% 100%
src/index.browser.ts 100% 100% 100% 100%
src/index.ts 100% 100% 100% 100%
src/types.ts 100% 100% 100% 100%
src/agent/actions/AgentActionsClient.ts 75% 100% 70% 75% 31-59
src/agent/actions/generate.ts 50% 100% 50% 50% 302-307
src/agent/actions/patch.ts 50% 100% 50% 50% 130-135
src/agent/actions/prompt.ts 50% 100% 50% 50% 133-138
src/agent/actions/transform.ts 50% 100% 50% 50% 337-342
src/agent/actions/translate.ts 50% 100% 50% 50% 162-167
src/assets/AssetsClient.ts 61.66% 51.92% 81.81% 64.91% 176-178, 200-213, 221-234, 260, 273-279
src/csm/draftUtils.ts 100% 100% 100% 100%
src/data/dataMethods.ts 84.1% 90.33% 71.28% 84.27% 128-129, 271, 377-410, 446-507, 596, 619-620, 654-655, 1069, 1182-1206, 1212, 1220, 1235
src/data/listen.ts 100% 100% 100% 100%
src/data/live.ts 95.94% 94.54% 100% 98.52% 86, 224, 252
src/data/resolveEventSourceFetch.ts 94.73% 84.61% 100% 94.44% 77
src/datasets/DatasetsClient.ts 61.22% 66.66% 58.82% 61.22% 32-106, 219-227
src/http/browserMiddleware.ts 100% 100% 100% 100%
src/http/browserUpload.ts 0% 0% 0% 0% 6-95
src/http/errors.ts 98.94% 94.44% 100% 98.93% 339
src/http/nodeMiddleware.ts 93.33% 94.73% 85.71% 95.83% 24, 38
src/http/request.ts 92.72% 85.04% 94.44% 95.5% 138, 221, 238, 259, 281, 282, 293, 301
src/http/requestOptions.ts 100% 89.28% 100% 100%
src/mediaLibrary/MediaLibraryVideoClient.ts 83.82% 75.86% 87.5% 80.35% 32-52, 83-85
src/projects/ProjectsClient.ts 53.57% 43.75% 66.66% 53.57% 39-68, 99
src/releases/ReleasesClient.ts 100% 100% 100% 100%
src/users/UsersClient.ts 83.33% 100% 75% 83.33% 24-28
Generated in workflow #4356 for commit 41905d6 by the Vitest Coverage Report Action

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented May 21, 2026

npm i https://pkg.pr.new/sanity-io/client/@sanity/client@1217

commit: 41905d6

@socket-security
Copy link
Copy Markdown

socket-security Bot commented May 21, 2026

@socket-security
Copy link
Copy Markdown

socket-security Bot commented May 21, 2026

Warning

Review the following alerts detected in dependencies.

According to your organization's Security Policy, it is recommended to resolve "Warn" alerts. Learn more about Socket for GitHub.

Action Severity Alert  (click "▶" to expand/collapse)
Warn High
License policy violation: npm typescript

License: LicenseRef-W3C-Community-Final-Specification-Agreement - The applicable license policy does not permit this license (5) (package/ThirdPartyNoticeText.txt)

From: package-lock.jsonnpm/@sanity/pkg-utils@10.5.0npm/typescript@5.9.3

ℹ Read more on: This package | This alert | What is a license policy violation?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Find a package that does not violate your license policy or adjust your policy to allow this package's license.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/typescript@5.9.3. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

Warn Medium
Install-time scripts: npm msw during postinstall

Install script: postinstall

Source: node -e "import('./config/scripts/postinstall.js').catch(() => void 0)"

From: package-lock.jsonnpm/msw@2.14.6

ℹ Read more on: This package | This alert | What is an install script?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Packages should not be running non-essential scripts during install and there are often solutions to problems people solve with install scripts that can be run at publish time instead.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/msw@2.14.6. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

View full report

rexxars and others added 17 commits May 29, 2026 14:22
BREAKING CHANGE: removes all CommonJS entry points
(`./dist/*.cjs`, `./dist/*.d.cts`, the `require` exports
conditions, and the `main` CJS field) so the package is
pure ESM. Consumers must use `import` or Node's
`require(esm)` support (Node 22.12+).

Prep work for upgrading to get-it v9 which is ESM-only.

- Drops the `require` conditions from all entries in `exports`
- Points `main` at the ESM entry for legacy resolvers
- Removes the CommonJS runtime smoke test
- Removes the `check-esm-compatibility` script and CI job;
  ESM-only deps are now allowed (and expected)
- Removes the CommonJS install example from the README

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
`HttpRequest` is now a body-only Observable contract. The
get-it middleware event union (`HttpRequestEvent`,
`ResponseEvent`, `ProgressEvent`) was leaking into the
public surface even though almost every consumer just
filtered for `response` and mapped to `body`.

The only place that genuinely needed progress events was
`client.assets.upload()` when called via the observable
API. That now has its own dedicated event type,
`UploadEvent<T>` (`UploadResponseEvent<T>` |
`UploadProgressEvent`), emitted only from that one method.

BREAKING CHANGE: removes the public `HttpRequestEvent`,
`ResponseEvent`, and `ProgressEvent` types. Consumers of
`client.assets.upload()` (observable variant) now receive
`UploadEvent<T>` instead of `HttpRequestEvent<T>` — the
event `type` discriminants (`'response'` / `'progress'`)
are unchanged, but `UploadResponseEvent` drops
`statusCode`/`statusMessage`/`headers`/`url`/`method` and
`UploadProgressEvent` is otherwise structurally identical.

The internal `HttpRequest` type, the `defaultRequester`
argument passed to the (`@internal @deprecated`)
`_requestHandler`, and the internal `_request*` helpers
all now resolve to `Observable<unknown>` of the parsed
body. The transport-level multi-event observable is wrapped
to body-only inside `defineCreateClient`. Asset uploads
bypass the wrapper via a new `_uploadObservable` that talks
to the underlying requester directly, so progress events
keep flowing on get-it v8.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
`ClientError` and `ServerError` previously reached into a
get-it response (multi-event observable) directly, and pulled
the GROQ request tag out of a get-it `HttpContext`. Both
couplings make the v9 transport swap noisier than it has to be.

Introduces an internal `CanonicalHttpResponse` shape (the same
shape already exposed via the public `HttpError.response`
interface) plus a `httpResponseFromGetIt` adapter that projects
a get-it v8 response into it. The error middleware now does the
translation once at the boundary and passes the GROQ tag as a
plain string to `ClientError`.

`extractErrorProps` now takes `tag?: string` instead of an
`HttpContext`, removing the last reach into get-it from the
error layer. Public class signatures stay permissive (`res: Any`)
so existing test fixtures keep working.

The v9 upgrade will land a second adapter
(`httpResponseFromFetch` or similar) that consumes the new
`Response` / `Headers` shape — error construction itself stays
unchanged.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Rewrites the HTTP transport layer on top of get-it v9's
`createRequester` (Promise-based) + native fetch. The
multi-event `Requester` from v8 is gone; we wrap the new
promise into a single-event Observable inside
`defineCreateClient` so the rest of the codebase keeps the
same shape it had before.

Key transport changes:

- `http/request.ts` is rewritten on `createRequester` from
  `get-it`. v9 throws `HttpError` from its built-in 4xx/5xx
  handling, which lets the v9 `retry` middleware see HTTP
  errors and retry 429/502/503 the same way as v8. After the
  retry loop, the v9 `HttpError` is translated to the
  client's existing `ClientError` / `ServerError` via the
  new `httpResponseFromFetch` adapter in `http/errors.ts`.

- `http/nodeMiddleware.ts` is rewritten to provide
  configuration (User-Agent header) and a Node-only
  middleware stack: a wrapping middleware that swaps in a
  `createNodeFetch({proxy})` per request when a legacy
  `proxy: '...'` is set; a `beforeRequest` transform that
  converts Node `Readable` upload bodies to Web
  `ReadableStream` (v9's fetch only accepts the latter); the
  `debug` middleware wired to the `debug` npm logger
  (`sanity:client`); and a lineage header transform. The
  default Node fetch falls back to undici's
  `EnvHttpProxyAgent` for `HTTP_PROXY` / `HTTPS_PROXY` /
  `NO_PROXY` env vars.

- `http/requestOptions.ts` keeps its v8-shaped output
  (`json`, `withCredentials`, `proxy`, `timeout: 0`-to-
  disable). The new adapter in `http/request.ts`
  (`adaptToFetchOptions`) translates those to v9 fetch
  options: `withCredentials: true` → `credentials:
  'include'`, `maxRedirects: 0` → `redirect: 'manual'`,
  `timeout: 0` → `timeout: false`, query arrays expand to
  repeated keys via `URLSearchParams` (matching v8 / Content
  Lake semantics).

Public-surface changes:

- The `unstable__adapter` / `unstable__environment`
  re-exports are removed — get-it v9 doesn't expose them.

- `dist/index.js` (Node ESM): +1.4 kB gzipped (debug + v9
  retry + adapter code).
- `dist/index.browser.js`: +900 B gzipped (adapter code).
- `umd/sanityClient.min.js`: -3.1 kB gzipped (no more v8
  middleware pipeline in the browser bundle).

Behavioural fallout that needed test updates:

- HTTP errors now always carry `statusText` ("Bad Request",
  "Service Unavailable", etc.) since real fetch responses
  do. Test expectations that relied on nock's empty
  statusText (`"HTTP 400 (body)"`) updated to the more
  realistic `"HTTP 400 Bad Request (body)"`.
- Asset upload via the observable API no longer emits
  per-chunk progress events from Node — v9 / fetch has no
  progress hook. The progress test now asserts that no
  progress events fire from Node; browser progress is
  handled separately in a follow-up commit via XHR.
- Mid-test `HTTPS_PROXY` env var changes can no longer
  reroute traffic, because undici's `EnvHttpProxyAgent`
  snapshots the env at construction. The test for this
  scenario is `skip`-ped with a comment; real-world
  env-var-set-before-process-start usage still works.

Testing infrastructure:

nock can't intercept undici's fetch (it patches
`http.request`), so we add a small `nock`-API-compatible
shim backed by `get-it/mock`'s `createMockFetch()`. A new
vitest setup file (`test/helpers/setupMockFetch.ts`)
installs a fresh mock per test and exposes its `fetch`
through a `globalThis.__sanityTestFetch` hook that the
Node middleware picks up. Tests keep their existing nock
call sites with only the import path changed; tests that
depend on `nock` intercepting `node:http` directly (the
real-EventSource SSE listener tests) keep using real nock.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Restores per-chunk upload progress events for
`client.assets.upload(...)` when called via the observable
API. get-it v9 / fetch has no progress hook, so when
`XMLHttpRequest` is available the upload runs through a
dedicated XHR-based code path (`browserUpload.ts`) that
emits `UploadProgressEvent`s as the request body is sent
and a final `UploadResponseEvent` once the server
responds. Non-browser environments (Node, edge) continue
to use the fetch-based path and only emit the terminal
response event.

Implementation notes:

- The XHR path is reached via a dynamic
  `import('../http/browserUpload')` so the Node bundle
  doesn't pay for the XHR adapter at all (the import is
  tree-shaken away in builds where `XMLHttpRequest` is
  undefined-by-construction).
- The `_requestHandler` interceptor still doesn't see
  asset uploads — they bypass the regular pipeline
  entirely, same as on get-it v8.
- The test-only fetch override (used by `nockShim` /
  `setupMockFetch`) moved from `nodeMiddleware` into
  `http/request.ts` so the browser environment picks it
  up too. The XHR path itself isn't intercepted by the
  shim — browser asset upload tests will need a separate
  XHR mock in a follow-up.

Bundle impact (gzipped):
- `dist/index.js`: 23.9 kB → 24.1 kB (+0.2 kB; XHR
  detection branch)
- `dist/index.browser.js`: 26.0 kB → 26.4 kB (+0.4 kB;
  appendQuery helper + dynamic-import boundary)
- `umd/sanityClient.min.js`: 32.0 kB → 34.8 kB (+2.8 kB;
  `browserUpload` and its `debug` logger end up inlined
  in the single-file UMD bundle)

The UMD bundle is roughly back to its pre-upgrade
baseline — UMD consumers get the XHR progress
functionality, the lean ESM browser bundle stays lean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Raises `engines.node` from `>=20` to `>=22.12`. Node 20
went out of LTS in April 2026; the floor was overdue. The
22.12 floor in particular makes the ESM-only switch a soft
break, because `require(esm)` ships natively from that
version — consumers stuck on CJS source can keep doing
`require('@sanity/client')` without changes.

Re-adds a CommonJS smoke test (`runtimes/node/test.cjs`)
that verifies `require(esm)` interop continues to work for
both the top-level entry and `@sanity/client/package.json`.

Drops two compatibility branches that were guarding APIs
the new minimum guarantees:

- `_createAbortError` no longer feature-detects
  `globalThis.DOMException`; it's globally available on
  every supported runtime now.
- The Node-upload `beforeRequest` transform no longer
  checks whether `Readable.toWeb` exists. The
  Node-stream-to-Web-stream conversion is now expressed
  through a proper `in`-operator type guard instead of a
  `pipe` cast, matching the repo's no-`as`-to-silence-TS
  rule.

README migration notes are reworked to fold the Node bump
and the CJS removal into a single section, with the
upgrade story being "bump Node, your `require()` calls
keep working."

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Brings the simulated browser environment up to date. The
big practical win is that `npm run test:browser` actually
completes now — happy-dom 12 was hanging the suite, so it
hadn't been a useful signal in a while. On happy-dom 20
all 866 enabled browser tests pass.

`happy-dom` 20 now provides a real `XMLHttpRequest`
implementation, which means `client.assets.upload()`
routes through XHR in browser tests (since 5e5b08a added
the XHR upload path). The XHR talks to the real network —
which the mock fetch can't see — so the test setup file
now hides `XMLHttpRequest` for the duration of each test
so uploads fall back to the fetch path that's actually
mockable. Real-browser validation of the XHR path needs
to happen elsewhere.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The published `dist/index.d.ts` had
`import {LegacyRequester} from './http/request'` at the
top, but no `./http/request.d.ts` ships in `dist/` (only
the entry-point declaration files do). Downstream
bundlers (rolldown, esbuild, etc.) that follow the
imports — `@sanity/vision` hit this first — failed with
`UNRESOLVED_IMPORT`.

Two changes, both contributing:

- Bump `@sanity/pkg-utils` from 7.2.2 to 10.5.0. The
  newer api-extractor pipeline no longer emits the
  unresolvable external import; it inlines the type
  internally instead. This alone is enough to make the
  bundled `.d.ts` consumable.

- Break the circular type-only import that confused the
  extractor in the first place. `src/types.ts` used to
  `import type {LegacyRequester} from './http/request'`
  while `src/http/request.ts` imported `Any` from
  `../types` — a one-step cycle. `Requester` is now
  defined directly in `types.ts` as the public-facing
  `(options: Any) => Observable<unknown>` shape, and the
  `requester` named export in both `index.ts` and
  `index.browser.ts` is explicitly annotated with that
  type. The public d.ts now declares
  `export declare type Requester = (options: Any) => Observable<unknown>`
  and `export declare const requester: Requester`, with
  no leak of the internal `LegacyRequester` or
  `ResponseEvent` names into the public surface.

Side note: pkg-utils 10 also adds opt-in support for a
`node` sub-condition in `exports` (sanity-io/pkg-utils#2781),
mirroring the existing `browser` sub-condition. The
shape would be roughly:

```json
"exports": {
  ".": {
    "source": "./src/index.ts",
    "browser": {
      "source": "./src/index.browser.ts",
      "import": "./dist/index.browser.js"
    },
    "node": {
      "source": "./src/index.node.ts",
      "import": "./dist/index.node.js"
    },
    ...
  }
}
```

That's a separate refactor (renaming `src/index.ts` to
`src/index.node.ts` and the emitted `dist/index.js` to
`dist/index.node.js`), and would be a minor breaking
change for anyone deep-importing — so it stays out of
this commit.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The default `--mode auto` resolves to `actual` whenever
node_modules exists (CI installs first), and `actual`
walks the installed tree — including every transitive of
every dev dep. `--dev=false` only filters what's read from
package.json, so in `actual` mode it has no effect on the
tree.

That's why CI started flagging engines constraints from
`@inquirer/*` (transitive of `msw`) and `vitest` (both
direct dev dep and optional peer of `get-it`), even
though none of them constrain published consumers.

`--mode ideal` reads from package.json directly and
honours the dev/peer flags, which is what we want for a
"do my published engines line up with my prod dep graph?"
check.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Fixes everything `npm run lint
--report-unused-disable-directives -f compact` was
flagging:

- `test/client.test.ts`: the LISTENERS describe imported
  real nock as `const {default: nock}`, which shadowed
  the shim import at the top of the file. Renamed the
  local binding to `realNock` and updated the five call
  sites inside the block. No behavioural change — the
  test still hits the real nock implementation that can
  intercept EventSource (`node:http`), while every other
  test in the file keeps going through the shim.
- `test/helpers/nockShim.ts`: drop the unused `handle`
  callback parameter on the internal `flush()` helper;
  rewrite the network-error registration comment so it
  doesn't trip the `no-warning-comments` rule (was
  `TODO:`, now plain prose).
- `eslint.config.mjs`: teach `unused-imports/no-unused-vars`
  to honour the standard `^_` leading-underscore
  convention (`args`/`vars`/`caughtErrors` ignore
  patterns). The `_options` arg on `nockShim`'s `nock()`
  function is intentionally unused (kept for API parity
  with nock's `(host, opts)` form), and the rule now
  recognises that signal.
- `src/csm/draftUtils.ts`: the `eslint-disable-next-line
  unused-imports/no-unused-vars` directive on the
  destructured `_versionPrefix`/`_publishedId` is no
  longer needed — the new ignore pattern covers it.
- `test/releasesClient.test.ts`: import ordering fixed
  via `eslint --fix`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Drops the Sanity-specific `@sanity/eventsource` wrapper
(which transitively depended on the unmaintained
`eventsource@2`, that talks `node:http` directly) in
favour of the upstream `eventsource@4` package. v4 is
fetch-based, so the SSE connection now flows through the
same transport layer the rest of the client uses.

A new `resolveEventSourceFetch(config, opts)` helper
returns a `fetch` implementation that:

- honours `globalThis.__sanityTestFetch` when set (keeps
  the listener/live tests on the same mock as the rest of
  the suite — no more "real nock for SSE" workaround);
- routes through `get-it/node`'s `createNodeFetch({proxy})`
  when the client was configured with an explicit
  `proxy:` (per-request proxy support reaches SSE too);
- otherwise hands off to `globalThis.fetch`, which on
  Node still picks up `HTTP_PROXY` / `HTTPS_PROXY` /
  `NO_PROXY` via undici's `EnvHttpProxyAgent`.

The fetch wrapper also injects `Authorization` and any
configured custom headers into every request — something
the native browser EventSource API doesn't support and the
old code had to polyfill around with a different package
shape per environment.

`live.ts` and `listen.ts` now construct the EventSource
synchronously (via static import) so the
"subscribe-then-immediately-unsubscribe" semantics
preserve their "no connection ever opened" guarantee. The
`createNodeFetch` import is the only thing left lazy, and
that's only reached when a proxy is explicitly set.

Test fallout, all addressed:

- Listener tests in `client.test.ts` move back to the
  shim — SSE now goes through fetch which the shim can
  intercept, so the `realNock` carve-out is gone.
- `listen.test.ts` / `live.test.ts` tests that spin up a
  real local SSE server (via `testSse` / direct server
  setup) now delete `globalThis.__sanityTestFetch` before
  each such test, so EventSource talks to the actual local
  server instead of the mock.
- Mock SSE responses now declare
  `content-type: text/event-stream`; the upstream v4
  parser is stricter about it than the old `eventsource@2`
  was.
- The lazy/cold listener tests stop using `.reply(fn)`
  (which the shim has to resolve eagerly) and assert
  request counts via `mock.getRequests()` instead.

Known regression: the UMD bundle grows from ~35 kB gz to
~190 kB gz because `eventsource@4` is statically imported
and rollup's UMD config inlines all dynamic imports. The
ESM `dist/index.{js,browser.js}` builds leave it as an
external import and are essentially unchanged (~24/27 kB
gz). UMD-only consumers may want to factor `eventsource`
out via a CDN script tag — addressing that cleanly would
be a follow-up.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replaces hand-rolled `['event: ...', 'data: ...', '', ...].join('\n')`
arrays in the listener and live-event tests with `encode()`
calls from `eventsource-encoder`. The fixtures are
shorter, harder to get wrong (no more remembering the
trailing blank line), and the few spurious lines that
crept in over the years (lone `'.'` placeholders, leading
empty comments) just disappear — they were never
meaningful SSE.

About 50 lines of test boilerplate disappears. No
behavioural change — the encoded byte stream is the same
as before, minus the now-removed junk lines that the
parser already ignored.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The UMD bundle ballooned from ~33 kB gz to ~190 kB gz in
7745855 because `resolveEventSourceFetch.ts` did
`import('get-it/node')` to build a proxy-aware fetch.
Even though that import was guarded with
`typeof window === 'undefined' && config.proxy`, rollup's
UMD config has `inlineDynamicImports: true`, so it
inlines the import target into the bundle regardless of
whether the branch can run. Pulling in `get-it/node`
drags `undici` along with it — 141 mentions in the
minified UMD.

The ESM `dist/index.browser.js` was fine all along — it
keeps dynamic imports lazy and only had a single
reference to the lazy import.

Fix: stop importing `get-it/node` from a module that's
shared with the browser bundle. The proxy-fetch helper
already lives in `nodeMiddleware.ts` (which only the Node
entry point imports), so expose it through
`EnvironmentOptions.resolveProxyFetch` and have
`defineCreateClient` thread that resolver onto the
resolved client config. `resolveEventSourceFetch.ts`
then just calls `config.resolveProxyFetch?.(proxy)` —
contains no reference to `get-it/node` and never pulls
`undici` into the browser bundle.

Sizes after:
- `dist/index.js` (Node): 24.3 kB gz (unchanged)
- `dist/index.browser.js`: 26.5 kB gz (unchanged)
- `umd/sanityClient.min.js`: 33.0 kB gz (was 35.1 kB
  before this branch; the small net gain over baseline
  is `eventsource@4` itself, which is what we'd expect)

Grepping for `undici` / `createNodeFetch` in
`dist/index.browser.js` and `umd/sanityClient.js`:
0 references in either.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The Deno smoke test broke because `get-it@9.0.0-alpha.10`
declares a `deno` exports condition that routes Deno to
the Node-specific build (`dist/index.node.js`). That
build depends on `undici`, which depends on
`node:sqlite` — and esm.sh's `denonext` transform can't
serve `node:sqlite` to Deno, so the whole graph fails to
resolve.

Override the `get-it` entries in the Deno import map so
esm.sh fetches the platform-neutral build directly
(`/dist/index.js?bundle-deps&target=es2022` for the
main entry, and the same shape for `/middleware`). The
`target=es2022` bypasses esm.sh's `denonext` transform,
and `bundle-deps` inlines the (Node-free) dep graph into
a single chunk so we don't accidentally pull anything
else through the transform on a follow-up resolve.

Also drops the stale `@sanity/eventsource/browser` special
case from the import-map generator (we use upstream
`eventsource` now), modernises the JSON import attribute
from `assert {type: 'json'}` to `with {type: 'json'}`, and
gitignores `deno.lock` (which `deno test` creates as a
cache artefact).

Verified locally: both Deno tests pass, both Bun tests
still pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Created locally by `npm run test:deno` from `deno test`'s
cache mechanism. Not used by CI (which runs Deno fresh
each time), so safe to keep out of version control.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant