Coverage
gossamer targets cross-runtime JavaScript APIs — both Web Platform and
ECMAScript. This includes APIs with no Gleam equivalent and native JS types that
complement Gleam’s standard library for interop. All APIs must work in Node.js,
Deno, Bun, and browsers.
Specs
- WinterTC Minimum Common API —
cross-runtime Web Platform baseline. Includes:
- Fetch Standard — fetch, Headers, Request,
Response
- URL Standard — URL, URLSearchParams
- Streams Standard — ReadableStream,
WritableStream, TransformStream
- Encoding Standard — TextDecoder,
TextDecoderStream, TextEncoderStream
- Web Crypto API — Crypto,
SubtleCrypto, CryptoKey
- File API — Blob, File
- Compression Streams —
CompressionStream, DecompressionStream
- DOM Standard — AbortController, AbortSignal
- XMLHttpRequest Standard — FormData
- Performance Timeline +
User Timing — Performance,
PerformanceEntry, PerformanceMark, PerformanceMeasure, PerformanceObserver
- WebSocket Standard — WebSocket (outside
WinterTC minimum)
- URL Pattern API — URLPattern (outside
WinterTC minimum)
- HTML Living Standard — Web Workers,
MessageChannel, MessagePort, BroadcastChannel (outside WinterTC minimum)
- ECMAScript (ECMA-262) — JavaScript language
built-ins
- ECMAScript Internationalization API (ECMA-402) —
Intl.* formatters and locale-aware operations
Web Platform APIs
Fetch & HTTP
Request, Response, and Headers come from
gleam_http. The underlying fetch call and
the FormData type come from gleam_fetch.
gossamer/fetch_extra adds the Fetch-spec
options as a FetchOptions builder, plus send variants that consume it.
Errors come from
gleam/fetch.FetchError;
inspect aborts via gossamer/abort_signal on the signal you passed to
set_signal.
gossamer/form_data_extra adds append_file
/ set_file for multipart file uploads.
URL
gleam/uri.Uri is the
canonical Gleam URL type. gossamer/url wraps the JS
URL constructor to validate a string as an absolute URL and return it in
WHATWG-canonical form (normalized host, ports, and encoding), optionally
resolving a relative input against a base — the canonicalization gleam/uri
doesn’t perform. URLSearchParams parsing is delegated to
gleam/uri.parse_query;
manipulate the resulting List(#(String, String)) with
gleam/list.
WebSocket
Workers & Messaging
Gleam worker scripts use
gossamer/worker_parent for post_message and
set_on_message; the parent spawns them with
worker.new("my_app/worker") |> worker.build. The FFI uses Node’s
worker_threads on Node and Web Workers on Deno, Bun, and browsers, so the same
script runs on all three.
gossamer/broadcast_channel sends messages
between every channel of the same name in the same agent — same-origin workers,
tabs, and iframes.
Streams
gossamer/stream is the family parent — it hosts
QueuingStrategy (collapsing the JS ByteLengthQueuingStrategy and
CountQueuingStrategy classes into variants) and StreamLifecycleError.
Compression
gossamer/compression hosts the shared
CompressionFormat.
Text Encoding
gossamer/encoding hosts the shared DecoderError.
TextEncoder is omitted in favor of
gleam/bit_array.from_string
/ <<s:utf8>>. For default UTF-8 decoding, use
gleam/bit_array.to_string;
text_decoder.decode requires an explicit encoding label.
Crypto
gossamer/crypto exposes random_uuid and hosts the
types shared across the submodules — KeyUsage, CryptoError, KeyKind, and
the algorithm types (AesAlgorithm, RsaAlgorithm, EcAlgorithm,
HashAlgorithm, NamedCurve, KeyAlgorithm).
For simple primitives (hashing, HMAC, random bytes, secure compare, message
signing), prefer gleam_crypto — it’s sync
and skips the key-import ceremony Web Crypto requires. Reach for
gossamer/crypto for the full Web Crypto API (key
generation, AES / RSA encryption, JSON Web Keys, key derivation).
Not bound: multi-prime RSA JWKs (the oth member — Web Crypto never produces
them and Deno and Bun reject them on import); custom-length HMAC keys (generate
raw bytes with gleam_crypto.strong_random_bytes and pass them to
subtle.import_key instead); the nullable derive_bits length (pass the
explicit bit count, e.g. 256 for an ECDH P-256 secret); and
SubtleCrypto.supports with the incubating modern-algorithms suite (SHA-3,
ML-KEM / ML-DSA, Argon2) — not yet in the W3C spec, and Bun ships none of it.
Data Types
Not bound: textStream (added to Blob and the fetch body mixin mid-2026) — no
runtime ships it yet.
Cancellation
Globals
reportError is not bound — runtime support is uneven and Gleam consumers have
no idiomatic use; log via console.error instead.
ECMAScript Built-ins
Native (no Gleam stdlib equivalent)
BigInt is the only ECMAScript built-in gossamer binds that has no Gleam
canonical — Gleam’s Int is fixed-width, so arbitrary-precision integers need a
dedicated type.
Extending Gleam stdlib
These bindings layer on top of an existing Gleam-canonical type — as transit
types (the JS native form, exposed for interop while the canonical Gleam type
stays preferred), as *_extra modules (gap-filling capabilities the Gleam
canonical doesn’t cover), or — in gossamer/json’s case — as a transparent
Gleam type that mirrors a JS namespace.
Transit types are JS native types exposed for interop with JS APIs that
return them while the canonical Gleam type stays preferred. ArrayBuffer /
Uint8Array bridge to BitArray; Iterator bridges to
gleam_yielder.Yielder; Map / Set
bridge to gleam/dict /
gleam/set; AsyncIterator
bridges to gossamer/async_yielder, gossamer’s
pure-Gleam async iteration type. The transit-type bindings expose
from_<source> / to_<source> bridges plus a draining each helper; the JS
iterator helper methods (map, filter, take, drop, reduce, etc.,
including Iterator.concat and Iterator.from) are not bound — bridge to the
Gleam-side type and use its operations. For the byte transit types, in-place
mutation (set, fill) and the base64/hex codec methods (toBase64,
fromBase64, toHex, fromHex) are not bound — transform via BitArray and
use gleam/bit_array’s
base64_encode / base16_encode; resizable and transferable ArrayBuffer
operations are likewise omitted.
Extras modules layer JS-specific capabilities on top of Gleam’s canonical
types (gleam/string,
gleam/int,
gleam/float,
gleam/time,
gleam/regexp,
gleam/javascript/symbol),
which already are the JS primitives under the hood. Number and Math split
across int_extra and float_extra mirroring gleam/int / gleam/float.
Number’s non-finite values (Infinity, -Infinity, NaN) have no binding,
since Gleam’s Float is always finite. Math.sumPrecise is likewise unbound
(absent on Node.js).
gossamer/json provides a transparent Json type for
inspecting or pattern-matching JSON of unknown structure. For typed
encode/decode pipelines, use gleam_json.
JSON.rawJSON / JSON.isRawJSON are not bound — Number(Float) deliberately
trades arbitrary-precision literals for a simple inspection surface.
Internationalization (ECMA-402)
gossamer/intl hosts shared types (LabelStyle,
LocaleMatcher, RangePartSource, HourCycle, CaseFirst) used across the
formatter submodules, plus canonical_locales (BCP 47 tag canonicalization) and
the per-category enumeration helpers calendars, collations, currencies,
numbering_systems, time_zones, and units.
Not bound: Intl.Locale.prototype.variants (absent on Node).
Delegated
Use the upstream bindings directly — gossamer doesn’t wrap them.
Out of Scope
| Category | Reason |
throwIfAborted and other throw-for-state-check APIs | Gleam returns Result; pattern-match on the relevant predicate (is_aborted, reason, etc.) instead |
| DOM APIs (document, window, Element, etc.) | Browser-only |
| Event, EventTarget, CustomEvent | Use a typed Gleam dispatcher; FFI for interop with JS-library targets |
ErrorEvent, on_error / on_message_error handlers | Gleam code uses Result instead of throwing; event handlers for JS throws don’t fit |
| MessageEvent | Receive handlers expose the payload directly; the event’s metadata (origin, ports, source) doesn’t apply here |
| PromiseRejectionEvent | Not exposed as a global on Node or Bun |
| structuredClone | Gleam values are immutable; the “break shared references” primitive doesn’t translate |
| WebAssembly | Warrants its own package |
| Temporal | Time is delegated to gleam/time; absent on Bun |
Web Locks (navigator.locks) | Absent on Bun; revisit when cross-runtime |
| Proxy, Reflect | Metaprogramming, not expressible in Gleam’s type system |
| SharedArrayBuffer, Atomics | Cross-thread shared memory; revisit when a concrete cross-runtime use case arrives |
| Generator, AsyncGenerator | Iterator creation via protocol is sufficient |
| ServiceWorker, SharedWorker | Browser-only with no cross-runtime equivalent |
| WeakMap, WeakSet, WeakRef, FinalizationRegistry | Revisit when a concrete use case arrives |
Typed arrays beyond Uint8Array (Int8Array/Float64Array/etc.) | Uint8Array covers byte data via the BitArray bridge |
| DataView | Bridge via Uint8Array for raw bytes |
| ReadableStreamBYOBReader, ReadableByteStreamController | Default reader and controller cover the cross-runtime use cases |
Several of these unbound APIs exist for JS-specific performance or memory
characteristics — WeakMap / WeakSet / WeakRef / FinalizationRegistry let
the GC collect referenced objects when nothing else holds them; typed arrays
beyond Uint8Array expose typed views (Float64Array, Int32Array) for
numeric data without boxing; DataView gives structured byte-level access for
binary protocols; ReadableStreamBYOBReader reuses buffers to avoid copies.
Gossamer prefers the simpler Gleam-canonical types (BitArray, gleam/dict,
gleam/set) until concrete cross-runtime needs surface. Reach into FFI directly
when you specifically need one of these characteristics.