Skip to content
A chip, the program, with a line to each place it runs, Node, a browser, a test and a dry run.

wtf platform

Pass your program its platform instead of reaching for globals, so it runs the same in Node, in a browser, in a test and in a dry run.

A program that calls setTimeout, crypto, fetch or process.env directly is tied to the place it runs. To test it, you patch globals and hope that nothing else reads them.

With @wtf/platform, your program takes a Platform as a parameter instead: its timers, crypto, console, locks, channels, workers, fetch, file system, environment, paths, folders, terminal, a way to open a URL and, where the platform has one, a way to start a process. Your code never reads a global. A test gives it doubles, and gets the same result every time.

import type { Platform } from '@wtf/platform'
import { testPlatform } from '@wtf/platform/test'
import { sleep } from '@wtf/platform/timers'
const program = async ({ platform, signal }: { platform: Platform; signal: AbortSignal }) => {
platform.console.log('Running on %s', platform.dirs.os)
await sleep(1000, platform, signal)
}
// In a test, time moves only when you say so.
const platform = testPlatform()
const running = program({ platform, signal: new AbortController().signal })
await platform.timers.advance(1000)
await running
platform.console.records // each line it logged
Where your program runsIts platform
NodenodePlatform({ fetch, storage }), or runMain(program, { fetch, storage })
A pagebrowserPlatform({ window })
A testtestPlatform(), with fake timers and a seeded crypto
A dry runmemoryPlatform(), with each process answered by your script

Where a web standard defines a member, the platform uses the standard’s own name and signature: setTimeout, performance, crypto, console, navigator.locks, navigator.storage, BroadcastChannel, MessageChannel, Worker and fetch. So a browser’s window and Node’s own objects fit as they are. Where no standard exists, the platform adds its own members: env, path, dirs, terminal and open.

The file system is the browser’s own file system API, the WHATWG File System Standard. Your code takes a folder handle and works with any handle it gets. A browser gives you one already. The fs packages give you one anywhere else, and helpers that work on any of them.

No globals

No package reads globalThis. Each helper asks only for the members it uses, so you can pass the whole platform or only those members.

A double for each member

Fake timers, a seeded crypto, a console that records, a fetch that your handler answers, and processes that your script answers.

Held to the standards

The Web Platform Tests run against the doubles and against Node’s own objects, so each one behaves as its standard says, errors included.

Errors you can match

A member that no standard defines throws a PlatformError. A member from a web standard throws what the standard says, a DOMException.