Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/app/layout.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import 'nextra-theme-docs/style.css'
import './globals.css'

export const metadata = {
metadataBase: new URL('https://github.com/vooyajs/fs'),
metadataBase: new URL('https://rush-fs-docs.vercel.app'),
title: { template: '%s | Vooya FS' },
description:
'Native batch filesystem operations for Node.js, powered by Rust and measured at explicit workload boundaries.',
Expand Down
29 changes: 17 additions & 12 deletions docs/content/api/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@ marketing. Core batch APIs accept string, Buffer and file URL paths. A public
compatibility layer uses Node for options outside the measured native path. Other
exports retain their documented subsets; callback API forms remain absent.

See the [Node compatibility backlog](/api/compatibility) for remaining API and behavioral gaps.
This page describes main, including unreleased changes. See [Quick Start](/guide/quick-start)
for the release boundary and installation instructions.

See the [Node compatibility policy](/api/compatibility) for remaining API and behavioral gaps.

## Batch extensions

Expand All @@ -28,7 +31,7 @@ See the [Node compatibility backlog](/api/compatibility) for remaining API and b
| -------------------------------------------- | ------ | ----------------------------------------------------------------------------------- |
| `readdir` | ✅ | `withFileTypes`, `recursive`; adds `concurrency` |
| `glob` | ✅ | rooted patterns, `cwd`, `exclude`, `withFileTypes`; adds `concurrency`, `gitIgnore` |
| `readFile` / `writeFile` / `appendFile` | ✅ | string paths, documented encodings and flags |
| `readFile` / `writeFile` / `appendFile` | ✅ | `readFile` supports core path/options routing; writes retain documented subsets |
| `copyFile` / `cp` | ✅ | recursive copy options; `cp` adds `concurrency` |
| `mkdir` / `rm` / `rmdir` | ✅ | recursive options; `rm` adds `concurrency` |
| `stat` / `lstat` | ✅ | `Stats` dates and type methods |
Expand All @@ -38,20 +41,22 @@ See the [Node compatibility backlog](/api/compatibility) for remaining API and b
| `chmod` / `chown` / `utimes` | ✅ | platform filesystem semantics |
| `mkdtemp` | ✅ | string prefix |

`exists` is a Vooya Promise extension; Node has no Promise `exists` method.

All APIs above provide promise and sync variants, for example `readdir` and
`readdirSync`. Async calls run their Rust task away from the JavaScript event-loop
thread; sync calls block like their Node counterparts.
`readdirSync`. Native async routes run Rust work away from the JavaScript event-loop
thread; other routes use Node. Sync calls block like their Node counterparts.

## Deliberately not implemented

| Surface | Reason / current alternative |
| -------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- |
| `open`, `close`, `read`, `write`, `fstat`, `ftruncate` | A safe cross-boundary file-descriptor lifecycle is a separate design problem. Use `node:fs` for fd workflows. |
| `opendir` | Native directory iterator lifetime and backpressure are not part of the current batch surface. Use `readdir`. |
| `watch`, `watchFile` | Cross-platform event delivery needs a long-lived event bridge. Use Node watchers. |
| `createReadStream`, `createWriteStream` | Streams require Node-native backpressure and piping semantics. Use Node streams. |
| callback APIs | The current library is promise-first plus synchronous APIs. |
| `URL` / `Buffer` paths outside core batches outside the core batch surface | Check each operation; core batch APIs support these through the public entry. |
| Surface | Reason / current alternative |
| ------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------- |
| `open`, `close`, `read`, `write`, `fstat`, `ftruncate` | A safe cross-boundary file-descriptor lifecycle is a separate design problem. Use `node:fs` for fd workflows. |
| `opendir` | Native directory iterator lifetime and backpressure are not part of the current batch surface. Use `readdir`. |
| `watch`, `watchFile` | Cross-platform event delivery needs a long-lived event bridge. Use Node watchers. |
| `createReadStream`, `createWriteStream` | Streams require Node-native backpressure and piping semantics. Use Node streams. |
| callback APIs | The current library is promise-first plus synchronous APIs. |
| `URL` / `Buffer` paths outside the core batch surface | Check each operation; core batch APIs support these through the public entry. |

The SDDs in `test/conformance` record the precise oracle, functional matrix, known
gaps, and documentation obligations for each supported API.
13 changes: 13 additions & 0 deletions docs/content/benchmarks.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,19 @@ on each evidence page and include every sample, runtime/library versions, fixtur
options, CPU/memory observations and source/native-binary identity. Evidence is a
snapshot of the recorded revision and configuration, not a universal speed claim.

## Find an API table

Open the table for the operation you use. On narrow screens, swipe horizontally
inside a table to reach the remaining implementations; the times are milliseconds
for a complete workload, and lower is better. Keep the runtime, mode, options and
execution route matched when comparing rows.

- Discovery: [readdir](/guide/all-api-evidence#readdir), [glob](/guide/all-api-evidence#glob), [scan](/guide/all-api-evidence#scan).
- File contents: [readFile](/guide/all-api-evidence#readfile), [writeFile](/guide/all-api-evidence#writefile), [appendFile](/guide/all-api-evidence#appendfile), [truncate](/guide/all-api-evidence#truncate).
- Copy and removal: [copyFile](/guide/all-api-evidence#copyfile), [cp](/guide/all-api-evidence#cp), [rm](/guide/all-api-evidence#rm), [rmdir](/guide/all-api-evidence#rmdir), [unlink](/guide/all-api-evidence#unlink).
- Paths and directories: [mkdir](/guide/all-api-evidence#mkdir), [mkdtemp](/guide/all-api-evidence#mkdtemp), [rename](/guide/all-api-evidence#rename), [realpath](/guide/all-api-evidence#realpath), [readlink](/guide/all-api-evidence#readlink), [link](/guide/all-api-evidence#link), [symlink](/guide/all-api-evidence#symlink).
- Metadata: [stat](/guide/all-api-evidence#stat), [lstat](/guide/all-api-evidence#lstat), [access](/guide/all-api-evidence#access), [exists](/guide/all-api-evidence#exists), [chmod](/guide/all-api-evidence#chmod), [chown](/guide/all-api-evidence#chown), [utimes](/guide/all-api-evidence#utimes).

## Reproduce the complete matrix

From a fresh checkout, install the locked dependencies and build the release
Expand Down
3 changes: 2 additions & 1 deletion docs/content/guide/_meta.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
export default {
'quick-start': 'Quick Start',
'use-cases': 'Choose an API',
troubleshooting: 'Troubleshooting & FAQ',
'what-is-vooya-fs': 'What is Vooya FS',
'execution-model': 'Execution Model',
'batch-evidence': 'Batch Evidence',
'native-overheads': 'Native Overhead Evidence',
'competitor-evidence': 'Competitor Evidence',
'all-api-evidence': 'All API Comparisons',
'use-cases': 'Use Cases',
migration: 'Migration from Rush-FS',
}
42 changes: 28 additions & 14 deletions docs/content/guide/migration.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -3,34 +3,48 @@
The project and repository are now **Vooya FS**. The canonical npm package is
`@vooya/fs`.

## Planned import change
## Change the dependency and import

```diff
- import { glob, readdir } from '@rush-fs/core'
+ import { glob, readdir } from '@vooya/fs'
```

The Rust crate becomes `vooya_fs`, and the native binary basename becomes
`vooya-fs`. Repository and documentation links move to
Require Node.js 22 or newer, install `@vooya/fs`, and remove the legacy dependency
once your application tests pass. Update imports from `rush-fs` in the same way.
See [Quick Start](/guide/quick-start) to choose the published release or main.

The Rust crate is `vooya_fs`, and the native binary basename is
`vooya-fs`. The canonical repository is
`https://github.com/vooyajs/fs`.

## Package transition
## Release boundary

1. Publish `@vooya/fs` only after CI, conformance, package installation, and
platform artifact checks pass.
2. Verify fresh installs of the published package before changing legacy package
metadata.
3. Mark `@rush-fs/core` and `rush-fs` deprecated with a direct migration message,
while keeping every existing version installable.
`@vooya/fs@0.1.0` is published. This site follows main and also documents newer,
unreleased compatibility fixes. Do not assume those fixes are present in 0.1.0;
check the [release source](https://github.com/vooyajs/fs/tree/fs-v0.1.0).

npm deprecation displays a warning; it does not redirect one package name to
another. We do not publish a compatibility wrapper because the legacy packages
support Node.js 18 while `@vooya/fs` requires Node.js 22 or newer. A wrapper would
silently change the runtime requirement for users who update the old package.
Legacy versions remain separate packages. npm deprecation, if applied, displays a
warning; it does not redirect imports or install a replacement. The old packages
support Node.js 18, while Vooya FS requires Node.js 22 or newer.

## Behavioral review

The intended API surface remains familiar, but migration is not a promise of total
Node `fs` parity. Review the [API overview](/api), especially the per-operation path support,
missing callback/file-descriptor/stream APIs, and Vooya-only options such as
`concurrency`, `gitIgnore`, `lines`, and `scan`.

## Validate the migration

1. Replace selected imports, without aliasing or patching `node:fs` globally.
2. Run application tests for path forms, encodings, errors, symlinks and mutation
options you actually use. Consult the per-API contract rather than assuming
complete Node compatibility.
3. Measure the same workload and options before and after the change. Check small
inputs as well as production scale, memory cost and application responsiveness.
4. Keep the original Node implementation for operations where it performs better.

Promise methods are direct exports. `glob` on main is awaitable and async iterable,
but materializes a full result array. Code relying on Node's incremental iterator
memory behavior should keep Node's implementation. Callback APIs are not provided.
110 changes: 74 additions & 36 deletions docs/content/guide/quick-start.mdx
Original file line number Diff line number Diff line change
@@ -1,54 +1,92 @@
# Quick Start

The published package is `@vooya/fs@0.1.0`. This checkout's compatibility iteration
is not yet published. To test it, use the working tree or review branch containing
these changes and build locally:
This site documents **main, including changes not yet released to npm**. The
published package is [`@vooya/fs@0.1.0`](https://www.npmjs.com/package/@vooya/fs).
Its [release source](https://github.com/vooyajs/fs/tree/fs-v0.1.0) is the reference
for that version. The current compatibility policy and benchmark tables describe
the newer checkout; installing 0.1.0 does not install those changes.

```bash
git clone https://github.com/vooyajs/fs.git
cd fs
corepack pnpm install --frozen-lockfile
corepack pnpm build
## Requirements

Use Node.js **22 or newer**; the current conformance matrix checks Node 22 and 24.
Prebuilt 0.1.0 packages cover macOS arm64/x64, Linux x64 with glibc, and Windows
x64. Rust is needed to build a checkout, not to use a supported prebuilt package.
Linux arm64 and Alpine/musl do not have published binaries in this release.

## Install the published release

```sh
npm install @vooya/fs@0.1.0
# Or: pnpm add @vooya/fs@0.1.0
```

## Choose the right side of the boundary
Keep optional dependencies enabled: the package manager selects the native binary
for your platform. See [installation troubleshooting](/guide/troubleshooting) if
the module cannot load.

## Run your first scan

Keep tiny, isolated operations in `node:fs`:
Save this as `scan.mjs` in the project where you installed the package. This
string-path example works with 0.1.0 and the current checkout:

```ts
import { existsSync } from 'node:fs'
```js
import { scan } from '@vooya/fs'

if (existsSync('./package.json')) {
// The native bridge would add work here, not remove it.
try {
const entries = await scan('.', {
include: ['**/*.{js,ts,rs}'],
exclude: ['**/node_modules/**', '**/dist/**'],
skipHidden: true,
concurrency: 4,
})
console.table(entries.slice(0, 10))
console.log(`${entries.length} matching entries`)
} catch (error) {
console.error(error)
process.exitCode = 1
}
```

Use Vooya FS when one call represents substantial or combined work:
```sh
node scan.mjs
```

```ts
import { glob, readdir, scan } from '@vooya/fs'
`scan` returns an array of metadata objects sorted by relative path. An empty
array is valid when no files match. It is a Vooya extension, not a Node API.
Four workers are an explicit starting point for this example, not a universal
optimum; tiny trees can be slower than Node. Read the [scan contract](/api/scan)
and [workload guide](/guide/use-cases) before applying it to a hot path.

const entries = await readdir('./node_modules', { recursive: true })
const manifests = await glob('**/package.json', { cwd: './node_modules' })
const sources = await scan('./packages', {
include: ['**/*.{js,ts,rs}'],
exclude: ['**/dist/**'],
})
```
For CommonJS, use `const { scan } = require('@vooya/fs')` and call it inside an
async function or with `.then()`. Promise methods are exported directly from
`@vooya/fs`; there is no `@vooya/fs/promises` entry. Synchronous variants such as
`scanSync` block the JavaScript thread.

Every supported operation also has a synchronous variant such as `scanSync` or
`readdirSync`. Prefer async APIs in servers and interactive applications so native
work does not block the JavaScript thread.
## Try the current source

## Verify a local checkout
To use the compatibility fixes and reproduce the published benchmark evidence,
install Git, Rust stable and pnpm 9, then build a release binding:

```bash
corepack pnpm typecheck
corepack pnpm lint
cargo clippy --all-targets --all-features -- -D warnings
corepack pnpm test
corepack pnpm doc:build
```sh
git clone https://github.com/vooyajs/fs.git
cd fs
pnpm install --frozen-lockfile
pnpm build
node --input-type=module -e "import { scan } from '@vooya/fs'; console.log((await scan('src')).length)"
```

Continue with the [execution model](/guide/execution-model) before selecting
operations solely from headline benchmark ratios.
Run that command from the repository root: the package's self-reference resolves
the local public entry. Record `git rev-parse HEAD` when comparing results. The
checkout still carries version 0.1.0 until the next release, so the version string
alone does not identify its behavior.

## Adopt one operation at a time

Keep Node streams, watchers and fd workflows in `node:fs`. For each candidate,
check its [supported options and execution route](/api/compatibility), verify your
application's outputs/errors, then measure an equivalent workload. Importing Vooya
FS does not patch Node or replace filesystem calls made by your dependencies.

Continue with [use cases](/guide/use-cases), [migration](/guide/migration), or the
[reproducible benchmark matrix](/benchmarks). Contributor checks are documented in
[CONTRIBUTING.md](https://github.com/vooyajs/fs/blob/main/CONTRIBUTING.md).
66 changes: 66 additions & 0 deletions docs/content/guide/troubleshooting.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Troubleshooting and FAQ

## Which version does this site describe?

The site follows main. npm currently provides `@vooya/fs@0.1.0`; main includes
additional compatibility fixes and newer measurements. Use the
[release source](https://github.com/vooyajs/fs/tree/fs-v0.1.0) for 0.1.0 and the
[checkout instructions](/guide/quick-start#try-the-current-source) to try main.

## Cannot find the native binding

Check the runtime, architecture and installed package from your application:

```sh
node -p "process.version + ' ' + process.platform + '/' + process.arch"
npm ls @vooya/fs
```

Version 0.1.0 ships binaries for macOS arm64/x64, Linux x64 glibc and Windows x64.
The architecture is that of the Node process, which can differ from the host under
emulation. Ensure your package manager installs optional dependencies and install
on the target platform; copying `node_modules` from a different OS is not portable.

There is no WASM fallback or automatic Node-only fallback when the addon is missing.
For a source checkout, run `pnpm install --frozen-lockfile` and `pnpm build` with
Rust stable installed. Source builds on other targets are not a promise of support.

## Can I replace every Node fs import?

Adopt supported operations individually. There is no global patch, callback API,
`@vooya/fs/promises` entry, or replacement for streams/watchers/fd lifecycle.
[Core methods](/api/compatibility) support more path and option combinations than
some of the smaller exports; check the specific API page. `exists` is an async
extension, while Node provides `existsSync` and a legacy callback `exists`.

## Why is Rust slower on my workload?

Native scheduling, argument conversion and result construction are part of the
cost. Tiny calls may not do enough work to recover that cost. More workers can
increase startup and contention. Compare the same output, options and side effects
using a release build, and measure both the default and explicit worker counts.
The [per-API tables](/guide/all-api-evidence) include losses, and
[Benchmarks](/benchmarks) provides repeatable commands and raw samples.

## Does async mean streaming or bounded memory?

No. Promise operations return complete results. In particular, main's `glob`
iterator still materializes the full array; `scan` returns sorted metadata for all
matches. Prefer Node streams or iterators when incremental consumption and
backpressure are the requirement. Async native work runs off the JavaScript
thread, but conversion and consumption of a large result can still affect it.

## Why does a supported option use Node?

The public entry selects Node for combinations outside a native fast path, such
as copy filters or some glob patterns. This preserves the documented behavior.
On main, `cpSync` and `rmSync` always use Node. A successful call or a speed ratio
alone is not proof of Rust acceleration; consult the
[execution policy](/api/compatibility).

## Report a mismatch or performance regression

Open an [issue](https://github.com/vooyajs/fs/issues) with Node/package versions,
OS/architecture, checkout commit if applicable, exact options, a minimal fixture,
and expected versus actual results. For performance, include release-build raw
samples, workload sizes, worker count and the equivalent Node/peer baseline.
Loading
Loading