Besides Node’s built-ins, the runtime provides its own modules for what a development environment needs on any device: bundling, installing packages, git, opening projects, tunnels and plugins. Like the Node modules, they are embedded in the core and resolved by the bundler, so nothing is installed from npm.
| Module | Import | What it does |
|---|---|---|
bundle |
fullstacked/bundle |
Bundle a project or a file with esbuild, inside the core |
packages |
fullstacked/packages |
Install, uninstall and audit npm packages, and resolve modules |
git |
fullstacked/git |
Clone, commit, pull, push, branch and more, with go-git |
run |
fullstacked/run |
Start another project in a new context and open it |
config |
fullstacked/config |
Per-project key/value settings |
tunnel |
fullstacked/tunnel |
Route connections through a tunnel hub |
plugin |
fullstacked/plugin |
Build plugins, git credentials, deep links |
auth |
fullstacked/auth |
Popup sign-in flow |
parentWindow |
fullstacked/parentWindow |
Remember and restore the window size |
fullstacked |
fullstacked |
The CLI as a function: execute("fullstacked -b ./app") |
fetch |
fullstacked/fetch |
The core’s fetch, also installed as globalThis.fetch (see Networking) |
websocket |
fullstacked/websocket |
The core’s WebSocket, also globalThis.WebSocket |
Each module can be imported three ways, all equivalent:
import git from "fullstacked/git"; // recommended
import git from "git";
import git from "node:git";
The bundler strips node: and fullstacked/, then looks the name up in its module table before node_modules. The fullstacked/ form is recommended because it says where the module comes from, and it’s the form the TypeScript declarations use. It also shows that an npm package with the same name (config, git, …) can’t be imported by its bare name in a FullStacked project. See How a built-in is resolved.
The fullstacked npm package ships the declarations. Add it as a dev dependency for editor support:
npm install --save-dev fullstacked
It declares fullstacked, fullstacked/auth, fullstacked/bundle, fullstacked/config, fullstacked/git, fullstacked/packages, fullstacked/parentWindow, fullstacked/plugin, fullstacked/run, fullstacked/test and fullstacked/tunnel. fullstacked/fetch and fullstacked/websocket resolve at bundle time but have no declared types (they have the same shapes as the global fetch and WebSocket).
Long operations return a stream rather than a single value. For example, git.clone returns the clone’s progress text, and packages.install returns progress events. They come in two shapes:
Duplex: a ReadableStream<Uint8Array> with on("data" | "close" | "error"), async iteration, promise() (all bytes), write() and end(). See Streams.EventEmitter: on(event, fn), off(event, fn), built on a Duplex that carries events.Streams start when you consume them. The core doesn’t run the operation until JavaScript opens the stream, which happens on the first listener, iteration or promise(). Awaiting the call alone only gets you the stream:
const stream = await git.clone("https://github.com/user/repo.git", "/repo");
// nothing has happened yet
for await (const chunk of stream) {
console.log(new TextDecoder().decode(chunk)); // progress lines
}
// cloned
A failure in the core rejects with Error("error from bridge: [<message>]"), or for a stream, fires error and rejects the iteration or promise(). bundle is the exception: it resolves with build errors in its result (see bundle).