Mirage ships BoxResource in two runtimes:
@struktoai/mirage-node, uses client_id + client_secret + refresh token (rotated on each use)
@struktoai/mirage-browser, supports the same refresh token via PKCE (no client secret in the bundle)
Both runtimes hit the same Box v2 API endpoints
(/folders/{id}/items, /files/{id}/content, /search, plus multipart upload, folder
create, delete, rename/move, and copy for writes). Credentials are obtained the same way
in both runtimes, see Box Credentials.
Both READ and WRITE modes are supported (mount with { mode: MountMode.WRITE } to
enable tee/cp/mv/rm/mkdir/touch). Pass rootFolderId to mount a single Box
folder as the workspace root instead of the whole account; folder ids are stable across
renames and moves. The Python package ships the same backend, see
Box (Python).
Quick start: developer token
For exploration, skip the OAuth flow and use a developer token (one-button-click in the Box
app console, 60-minute lifetime). The BoxResource accepts an accessToken field that
short-circuits the refresh logic:
When the token expires (Box 401s with invalid_token), regenerate it in the console and
re-run. See Box Credentials -> Quick Start.
Service account (client credentials, no refresh token)
For headless server auth, skip OAuth and refresh tokens entirely. Create a Box app with the
Server Authentication (Client Credentials Grant) method, authorize it once in the Box
admin console (Apps -> Custom Apps Manager), and pass the enterprise ID:
Tokens are minted for the app’s service account and re-fetched automatically on expiry;
there is no refresh token to rotate or persist.
The service account is a separate Box user with its own (initially empty) root folder. To see
your content, share folders with the service account’s email address, shown under the app’s
General Settings in the developer console.
Node (server-side, long-running)
The BoxTokenManager caches the access token in memory (5-minute safety buffer before expiry)
and rotates the refresh token on every refresh. Without onRefreshTokenRotated, the rotation
is in-memory only and a process restart needs a fresh refresh token.
Browser (PKCE, no client secret)
Box requires the origin to be allowlisted on the app’s Allowed Origins config (see
setup). The bundled
examples/typescript/browser/src/box_pkce.ts
runs the full PKCE dance and persists the rotated refresh token to localStorage.
VFS mode (patchNodeFs)
Only fs.promises.* is patched, sync forms aren’t supported.
FUSE mode
Requires macFUSE on macOS or libfuse on Linux.
Path → ID resolution
Box uses numeric folder/file IDs internally (root folder is id 0). Mirage caches the path → ID
mapping in the RAMIndexCacheStore attached to the resource. The first time you ls /box/foo/bar/,
it walks the tree top-down (one API call per level) and caches each entry’s ID. Subsequent reads
of /box/foo/bar/anyfile.json hit the cache instead of re-walking.
The cache TTL defaults to 24h. To force re-resolution, recreate the BoxResource.
Box-native file types
Every Box item is served as its raw bytes, keeping its real name (no .json suffix).
Box has no API to edit these formats from a structured payload, so Mirage does not render
them, it hands back exactly what Box stores:
.boxnote / .boxcanvas, Box’s native Notes and Canvas, stored as ProseMirror-style
JSON. They are text, so cat foo.boxnote | jq . works if you want to poke at the structure.
.gdoc / .gsheet / .gslides, Box’s V2 Google-format files, stored as Office Open XML
zips (.docx / .xlsx / .pptx). These are opaque binary, like any other Office document
on a Mirage mount.
For a rich, editable view of Google-format documents, mount them through
Google Drive with Google credentials instead, the gws docs ...
commands operate on Google file IDs and do not apply to Box.
Available commands
BoxResource ships the same shell command set as GDriveResource and DropboxResource:
- Filesystem:
ls, cat, head, tail, nl, wc, stat, find, tree, du, file,
realpath, basename, dirname
- Writes (in
WRITE mode): tee, cp, mv, rm (-r), mkdir (-p), touch,
truncate
- Search/text:
grep, rg, awk, sed, sort, uniq, cut, diff, cmp, jq
- Encoding:
base64
- Format-aware:
cat_parquet, cat_feather, cat_hdf5, plus head_*/grep_*/ls_*/
stat_*/tail_*/wc_*/file_*/cut_* variants for .parquet, .feather, .hdf5/.h5,
.orc files
Examples
End-to-end runnable scripts are in
examples/typescript/box/:
box.ts, Workspace.execute('ls/stat/cat/tree …') shell demo
box_parquet.ts, parquet preview through cat
box_vfs.ts, patchNodeFs + native fs.promises.* calls
box_fuse.ts, FUSE mount with shell access in another terminal