@sanity/eventsource

A meta-package that auto-selects the right EventSource polyfill for Node.js or the browser behind one import.

Library
npm
v5.0.4
2stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
44/100Fair
Development Activity64
Maintenance44
Community12
Maturity56
Momentum0

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
54/100Fair
Architecture58
Code Quality62
Innovation65
Learning Curve30

@sanity/eventsource solves a small but recurring cross-runtime problem: the EventSource API used for Server-Sent Events isn’t implemented consistently across JavaScript environments. Node.js has no native EventSource at all, and the browsers that do support it can’t attach custom headers such as Authorization tokens, which real-time APIs typically require for authentication.

Rather than reimplementing EventSource, the package re-exports the eventsource npm package for Node.js and event-source-polyfill for browsers behind a single import, using package.json exports conditions (node, browser, deno, edge-light, worker, react-native) to route to the correct implementation automatically. Consumers can also force a specific implementation via /browser or /node subpath imports, which matters for bundlers that don’t fully honor conditional exports. Maintained by Sanity.io to power real-time streaming connections in their own SDKs, it now sees well over a million weekly npm downloads as a general-purpose EventSource compatibility shim.

What You Get

  • Automatic runtime detection via package.json exports conditions (node, browser, deno, edge-light, worker, react-native)
  • Auth-header support for EventSource connections, which the native browser EventSource spec doesn’t allow
  • Explicit /browser and /node subpath imports for forcing an implementation when a bundler doesn’t respect conditional exports
  • Full TypeScript typings re-exported from both the Node (eventsource) and browser (event-source-polyfill) implementations
  • Both CommonJS (.js) and ESM (.mjs) entry points for the browser build

Common Use Cases

  • Real-time API client SDKs - Library authors who need Server-Sent Events with auth headers import one package instead of branching on runtime themselves.
  • Isomorphic applications - Teams shipping the same data-fetching code to Node.js (SSR) and the browser avoid maintaining two separate EventSource code paths.
  • Bundler compatibility fixes - Projects whose bundler mishandles conditional exports import the /browser or /node subpath directly to guarantee the intended implementation ships.
  • Sanity.io real-time features - Sanity’s own SDKs (e.g. its client and live content APIs) use this package under the hood to stream document updates to subscribers.

Under The Hood

Architecture The package has almost no logic of its own - the delegation happens entirely through package.json’s exports map rather than in code. node.js requires the upstream eventsource package, browser.js requires event-source-polyfill, browser.mjs re-exports browser.js as an ESM default for bundlers that resolve the import condition, and the paired .d.ts/.d.mts files re-declare the corresponding upstream module’s type shape. Because the abstraction boundary is a conditional-exports map rather than a wrapper function, there is effectively nothing to break internally; the only real change surface is a version bump of one of the two upstream implementations.

Tech Stack Dependencies are exactly the two runtime implementations it selects between - eventsource and event-source-polyfill - plus their @types packages for typings. TypeScript 5.4 and a prepublishOnly: tsc script generate declaration output at publish time; there is no bundler, since the package ships its handful of files as-is. CI runs on GitHub Actions: release-please handles versioned, provenance-signed npm publishes, a Renovate config auto-bumps the two upstream dependencies, and a scheduled workflow rebuilds the .d.ts files and runs Prettier automatically.

Code Quality There is no behavioral test suite - the test script only runs tsc --noEmit --emitDeclarationOnly false, a type-check rather than a runtime test. Given the entire package is a static re-export map with no conditional logic, that lower bar is a reasonable tradeoff rather than obvious neglect. Code style is enforced automatically via a Prettier config embedded in package.json and a bot-driven formatting workflow, and dependency freshness is enforced by Renovate rather than manual review.

API Design Consumer-facing API surface is a single default import (import polyfilledEventSource from '@sanity/eventsource') that resolves correctly for the calling runtime with zero configuration, plus two explicit escape-hatch subpaths (/browser, /node) for bundlers that don’t fully honor conditional exports. The README documents both paths directly. The one DX wrinkle is that the escape hatch exists at all - needing it signals that conditional-exports resolution isn’t universally reliable across the JS tooling ecosystem, which is outside this package’s control but still surfaces as friction for consumers.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search