# snapdir for Node.js
The `@snapdir/snapdir` package wraps the same Rust core (`snapdir-api →
snapdir-core`) that powers the CLI, so the manifests and snapshot IDs it
produces are bit-identical to `snapdir id`, `snapdir push`, and every other
binding. The surface is idiomatic Node.js: synchronous helpers plus
`Promise`-returning `async` operations that never block the event loop.
## Install
```sh
npm install @snapdir/snapdir
```
**Prebuilt, zero build tools.** The package ships precompiled native binaries
for Linux (glibc + musl) and macOS on x64 and arm64. There is no source build:
no Rust toolchain, no C compiler, no post-install step. The loader selects the
correct `.node` binary for your platform, so it runs on Alpine/musl out of the
box.
## Usage
The store URI is always an **argument**, never an environment variable — use
`file://$PWD/store` for a no-setup local store, or `gs://bucket/prefix` for
Google Cloud Storage.
```js
import { id, manifest, push, pull, fetch, diff, SnapdirError } from '@snapdir/snapdir'
const store = `file://${process.cwd()}/store`
// Snapshot ID — pure and deterministic, no store touched.
const snapshotId = await id('./my-dir')
console.log(snapshotId) // 64-char lowercase hex
// Full manifest: per-entry path, checksum, and size. size is always bigint.
const m = await manifest('./my-dir')
for (const entry of m.entries) {
console.log(entry.path, entry.size) // size: bigint (u64)
}
// Push to the store; returns the same 64-hex ID.
const sid = await push('./my-dir', store)
// Fetch into the local cache, or pull + materialize into a directory.
await fetch(sid, store)
await pull(sid, store, './restored')
// Diff two stores: { from, to } are arrays of store URIs.
// A pinned snapshot reference uses the store@id convention — the last '@'
// splits the store URI from the 64-hex snapshot ID.
const entries = await diff({ from: [store], to: [`${store}-next`] })
for (const e of entries) {
console.log(`${e.status}\t${e.path}`) // A / D / M / = — byte-identical to the CLI
}
```
For Google Cloud, swap the store URI for a `gs://` URL:
```js
const sid = await push('./my-dir', 'gs://my-bucket/snapshots')
```
## Errors
Every failure is a `SnapdirError` (extends `Error`) whose `.code` is one of the
eight stable `SCREAMING_SNAKE_CASE` codes shared across all bindings and the
CLI.
```js
import { push, SnapdirError } from '@snapdir/snapdir'
try {
await push('./missing', 'file://$PWD/store')
} catch (err) {
if (err instanceof SnapdirError) {
switch (err.code) {
case 'IO_ERROR': break // filesystem read/write failure
case 'HASH_MISMATCH': break // content did not match its expected checksum
case 'STORE_ERROR': break // object-store transport/backend failure
case 'IN_FLUX': break // a file changed while being read
case 'CATALOG_ERROR': break // manifest/catalog could not be parsed
case 'INVALID_ID': break // snapshot ID is not 64-hex
case 'INVALID_STORE': break // store URI is malformed or unsupported
case 'CONFLICT': break // a concurrent write conflicted
}
console.error(err.code, err.message)
}
}
```
## Platform support
Every binding is CI-verified against its live public registry (npm) before
release.
| Platform | Supported |
| --- | --- |
| Linux glibc (x64 + arm64) | yes |
| Linux musl / Alpine (x64 + arm64) | yes |
| macOS | yes |
| Windows | no |
The Node.js binding runs on both glibc and musl. The only binding-wide
exception to musl support is **Java**, which is glibc-only today (musl planned
for 1.11.1); the Node.js binding has no such caveat. Windows is unsupported —
snapdir is Unix-only.