Web APIs
Web APIs are globals, so there is nothing to import. Write the code you would write in a browser:
const response = await fetch('https://api.example.com/data');const data = await response.json();
const socket = new WebSocket('wss://echo.example.com');socket.addEventListener('message', (event) => console.log(event.data));
const digest = await crypto.subtle.digest('SHA-256', new TextEncoder().encode('hi'));An --app gjs build scans the bundled output, works out which globals your code actually reaches, and registers only those: fetch becomes a Soup.Session call, WebSocket a Soup.WebsocketConnection, crypto.subtle a GLib-backed implementation. An --app browser build uses the browser’s own versions of the same source, and an --app node build leaves the ones Node, Bun and Deno already define to the runtime.
Import a class explicitly
Section titled “Import a class explicitly”Sometimes you want the constructor as a value: to subclass it, to pass it around, or to keep a module free of globals. Every package exports its classes, and importing a package root has no side effects.
import fetch, { Headers, Request, Response, FormData } from '@gjsify/fetch';import { WebSocket } from '@gjsify/websocket';import { localStorage } from '@gjsify/webstorage';These specifiers only resolve in a GJSify build, so prefer the globals in code that also has to run on Node.js or in a browser.
A global is missing at runtime
Section titled “A global is missing at runtime”If a bundle dies with ReferenceError: X is not defined, the detector could not see X, usually because a library reads it through a stored globalThis reference. Keep auto detection on and name the identifier:
gjsify build src/index.ts -o dist/index.js --globals auto,matchMediaGroups work too (--globals auto,dom). The full identifier and group list is in the CLI Reference.
What is implemented
Section titled “What is implemented”Web Platform Coverage
34 of 59 web standards
Coverage of relevant W3C and WHATWG standards, including 10 APIs that are explicitly out of scope for desktop GTK apps (Service Worker, FS Access, Web Bluetooth, …).
| Package | Backed by | What you get |
|---|---|---|
@gjsify/abort-controller | pure TS | AbortController, AbortSignal incl. .abort, .timeout, .any |
@gjsify/compression-streams | Gio | CompressionStream, DecompressionStream (gzip, deflate, deflate-raw). Routed through node:zlib, which is Gio.ZlibCompressor on GJS |
@gjsify/dom-events | pure TS | Event, CustomEvent, EventTarget, UIEvent, MouseEvent, PointerEvent, KeyboardEvent, WheelEvent, FocusEvent |
@gjsify/dom-exception | pure TS | DOMException per WebIDL |
@gjsify/domparser | pure TS | DOMParser.parseFromString over a minimal DOM. text/html runs an HTML5 tokenizer and tree builder, the XML types run the XML scanner, and an unsupported type throws rather than guessing. Subpaths /html, /selectors (CSS Selectors 4: querySelector, matches, closest) and /entities |
@gjsify/eventsource | Soup 3.0 | EventSource (Server-Sent Events), TextLineStream |
@gjsify/fetch | Soup 3.0, Gio, GLib | fetch(), Request, Response, Headers, redirects, file:// and data: URIs |
@gjsify/formdata | pure TS | FormData, File, multipart encoding |
@gjsify/gamepad | Manette 0.2 (Linux), SDL3 via @gjsify/gamepad-native (macOS, Windows) | Gamepad, GamepadButton, GamepadEvent, GamepadHapticActuator (dual rumble) |
@gjsify/message-channel | pure TS | MessageChannel, MessagePort. Also the transport behind iframe messaging and worker IPC |
@gjsify/web-streams | pure TS | ReadableStream (incl. byte streams), WritableStream, TransformStream, TextEncoderStream, TextDecoderStream |
@gjsify/web-globals | pure TS | Named re-exports of the common Web classes in one place. Its /register subpath sets them all on globalThis |
@gjsify/webassembly | pure TS | WebAssembly.compile, instantiate, validate and the streaming variants, wrapping SpiderMonkey’s synchronous constructors |
@gjsify/webaudio | Gst 1.0, GstApp 1.0 | AudioContext over a GStreamer decodebin and playback chain, AudioBufferSourceNode, GainNode, AudioParam |
@gjsify/webcrypto | GLib, Gio | SubtleCrypto (AES, AES-KW, RSA-OAEP, RSA-PSS, ECDSA, HMAC, PBKDF2, HKDF, ECDH), CryptoKey, getRandomValues, randomUUID. The algorithms come from node:crypto, entropy from /dev/urandom |
@gjsify/webrtc | Gst 1.0, GstWebRTC 1.0, GstSDP 1.0 | RTCPeerConnection, RTCDataChannel, RTCRtpSender / Receiver / Transceiver, MediaStream, getUserMedia, RTCDTMFSender, RTCCertificate. WebRTC & Media Capture walks through a data channel, how a capture device gets picked, and the limits worth knowing |
@gjsify/webrtc-native | Gst 1.0, GstWebRTC 1.0 | Prebuilt signal bridge that @gjsify/webrtc uses. You never import it directly |
@gjsify/websocket | Soup 3.0 | WebSocket, MessageEvent, CloseEvent, with NUL-safe text frames |
@gjsify/webstorage | pure TS | Storage, localStorage, sessionStorage. Import only, they are not injected as globals, and both are in memory, so nothing survives a restart yet |
@gjsify/xmlhttprequest | Soup 3.0, GLib | XMLHttpRequest with responseType arraybuffer, blob, json, text and document |
Fifteen further standards are tracked as planned but not built yet, and ten are marked out of scope because they make no sense in a desktop GTK app. The dashboard above names each one.
The Adwaita widgets for --app browser builds are custom elements rather than a
standard, and they are documented in the Adwaita gallery.
Where each API also runs
Section titled “Where each API also runs”Every package declares the runtimes it supports, in a gjsify.runtimes field, and the answer differs per standard. fetch, WebSocket, crypto.subtle, FormData, WebAssembly and the compression streams are native on Node, Bun and Deno, so a build for those runtimes polyfills nothing. EventSource, DOMParser, localStorage and the DOM event classes carry a polyfill for them as well, and most of the pure TypeScript packages run in the browser and under NativeScript too. The GStreamer-backed AudioContext and RTCPeerConnection, and XMLHttpRequest, are declared for GJS and the browser only.
More than 50 packages across the Node, Web and DOM pillars ship a browser test suite that CI runs against real Firefox with Playwright. Runtimes has the full picture.