Problem: the hexagonal refactor churns the backend tree for nine more phases; the UI delivery stack (web/ SPA, cmd/desktop Wails wrapper, compose/web image) must move to its own repo first so doc/layout rewrites land once on a backend-only tree. Change: - New repo git.hubris.network/dtoro/oikos-web (v0.33.0): web/, desktop/ (updateURL repointed to oikos-web releases), compose/, own CI (web + desktop jobs), own deploy script (CI-green gate, TOCTOU guard, version-tagged images, prune-to-3), own webhook receiver on :9798 + launchd unit, own compose project publishing the same 8091:80. - Cutover executed on mac-mini in order: oikos stack's web service stopped+removed, oikos-web project brought up on 8091; outer Caddy untouched (targets the published port) — serving + Authentik flow + /wails 404 quirk verified post-cutover. - Stripped from oikos: web/, cmd/desktop/, compose/web/, desktop CI workflow, ci.yml web job, Makefile ui/desktop/desktop-package/install targets, the compose web service, oikos-web from deploy.sh's fallback prune list; wails + go-keyring dropped from go.mod, vendor synced. - README / CONTRIBUTING / AGENTS.md / .agents dev+operations docs now point at the new repo; mbse + mascot design docs carry a path note. Risk: production SPA serving depends on the new pipeline now; rollback is versioned-image re-up of the old web service from a pre-split checkout (port 8091). Desktop builds installed before the split still check dtoro/oikos releases — one manual reinstall, noted in the oikos-web release notes. Verification: go vet, make test (race), make generate-check, golangci (no new findings; baseline down 400→365); post-cutover curls — localhost:8091 200, /wails/runtime.js 404, outer Caddy 302 Authentik.
142 lines
3.1 KiB
Markdown
142 lines
3.1 KiB
Markdown
# `@humanfs/node`
|
|
|
|
by [Nicholas C. Zakas](https://humanwhocodes.com)
|
|
|
|
If you find this useful, please consider supporting my work with a [donation](https://humanwhocodes.com/donate) or [nominate me](https://stars.github.com/nominate/) for a GitHub Star.
|
|
|
|
## Description
|
|
|
|
The `hfs` bindings for use in Node.js and Node.js-compatible runtimes.
|
|
|
|
> [!WARNING]
|
|
> This project is **experimental** and may change significantly before v1.0.0. Use at your own caution and definitely not in production!
|
|
|
|
## Installation
|
|
|
|
Install using your favorite package manager:
|
|
|
|
```shell
|
|
npm install @humanfs/node
|
|
|
|
# or
|
|
|
|
pnpm install @humanfs/node
|
|
|
|
# or
|
|
|
|
yarn add @humanfs/node
|
|
|
|
# or
|
|
|
|
bun install @humanfs/node
|
|
```
|
|
|
|
## Usage
|
|
|
|
The easiest way to use hfs in your project is to import the `hfs` object:
|
|
|
|
```js
|
|
import { hfs } from "@humanfs/node";
|
|
```
|
|
|
|
Then, you can use the API methods:
|
|
|
|
```js
|
|
// 1. Files
|
|
|
|
// read from a text file
|
|
const text = await hfs.text("file.txt");
|
|
|
|
// read from a JSON file
|
|
const json = await hfs.json("file.json");
|
|
|
|
// read raw bytes from a text file
|
|
const arrayBuffer = await hfs.arrayBuffer("file.txt");
|
|
|
|
// write text to a file
|
|
await hfs.write("file.txt", "Hello world!");
|
|
|
|
// write bytes to a file
|
|
await hfs.write("file.txt", new TextEncoder().encode("Hello world!"));
|
|
|
|
// append text to a file
|
|
await hfs.append("file.txt", "Hello world!");
|
|
|
|
// append bytes to a file
|
|
await hfs.append("file.txt", new TextEncoder().encode("Hello world!"));
|
|
|
|
// does the file exist?
|
|
const found = await hfs.isFile("file.txt");
|
|
|
|
// how big is the file?
|
|
const size = await hfs.size("file.txt");
|
|
|
|
// when was the file modified?
|
|
const mtime = await hfs.lastModified("file.txt");
|
|
|
|
// copy a file from one location to another
|
|
await hfs.copy("file.txt", "file-copy.txt");
|
|
|
|
// move a file from one location to another
|
|
await hfs.move("file.txt", "renamed.txt");
|
|
|
|
// delete a file
|
|
await hfs.delete("file.txt");
|
|
|
|
// 2. Directories
|
|
|
|
// create a directory
|
|
await hfs.createDirectory("dir");
|
|
|
|
// create a directory recursively
|
|
await hfs.createDirectory("dir/subdir");
|
|
|
|
// does the directory exist?
|
|
const dirFound = await hfs.isDirectory("dir");
|
|
|
|
// copy the entire directory
|
|
hfs.copyAll("from-dir", "to-dir");
|
|
|
|
// move the entire directory
|
|
hfs.moveAll("from-dir", "to-dir");
|
|
|
|
// delete a directory
|
|
await hfs.delete("dir");
|
|
|
|
// delete a non-empty directory
|
|
await hfs.deleteAll("dir");
|
|
```
|
|
|
|
If you'd like to create your own instance, import the `NodeHfs` constructor:
|
|
|
|
```js
|
|
import { NodeHfs } from "@humanfs/node";
|
|
import fsp from "fs/promises";
|
|
|
|
const hfs = new NodeHfs();
|
|
|
|
// optionally specify the fs/promises object to use
|
|
const hfs = new NodeHfs({ fsp });
|
|
```
|
|
|
|
If you'd like to use just the impl, import the `NodeHfsImpl` constructor:
|
|
|
|
```js
|
|
import { NodeHfsImpl } from "@humanfs/node";
|
|
import fsp from "fs/promises";
|
|
|
|
const hfs = new NodeHfsImpl();
|
|
|
|
// optionally specify the fs/promises object to use
|
|
const hfs = new NodeHfsImpl({ fsp });
|
|
```
|
|
|
|
## Errors Handled
|
|
|
|
* `ENOENT` - in most cases, these errors are handled silently.
|
|
* `ENFILE` and `EMFILE` - calls that result in these errors are retried for up to 60 seconds before giving up for good.
|
|
|
|
## License
|
|
|
|
Apache 2.0
|