first commit

This commit is contained in:
2026-05-29 08:20:56 +01:00
commit 949299f58d
6368 changed files with 527176 additions and 0 deletions

View File

@@ -0,0 +1,52 @@
# `file-system.ts`
## Purpose
Production-grade `UploadStorage` adapter backed by `node:fs/promises`. Stores bytes as flat files under a configurable `rootDir`. Every key is validated for path-traversal escape attempts BEFORE touching disk, so a malicious `../etc/passwd` key never reaches the filesystem syscall layer — it raises `FileUploadError(UPLOAD.STORAGE_FAILURE)` from the resolver.
## Features
- Path-traversal hardening: rejects keys containing `/`, `\`, or NUL bytes; resolves keys via `path.resolve` and verifies the result is inside `rootDir`.
- Lazy `mkdir -p rootDir` on first `put` so callers can construct the adapter before the directory exists.
- Atomic `writeFile` on POSIX so partial writes never leave half-files visible to a parallel reader.
- `delete` uses `rm({ force: true })` so absent files do not raise — matching the abort route's idempotent semantics.
- `exists` swallows `stat` errors and returns `false` rather than leaking the underlying syscall error code.
## Usage: Basic
```ts
import { FileSystemUploadStorage } from "@suaveplan/api-plugin-file-upload/storage/file-system";
const storage = new FileSystemUploadStorage({
rootDir: "/var/lib/suaveplan/uploads",
});
await storage.put("upload-001", new Uint8Array([0xff]));
```
## Usage: Advanced
```ts
import { FileSystemUploadStorage, FileUploadError } from "@suaveplan/api-plugin-file-upload";
const storage = new FileSystemUploadStorage({ rootDir: "/tmp/uploads" });
try {
await storage.put("../etc/passwd", new Uint8Array([0]));
} catch (err) {
if (err instanceof FileUploadError && err.uploadCode === "UPLOAD.STORAGE_FAILURE") {
console.warn("path-traversal rejected:", err.message);
}
}
```
## API Reference
- `FileSystemUploadStorageOptions` — `{ rootDir: string }`.
- `class FileSystemUploadStorage implements UploadStorage` — constructor `(options: FileSystemUploadStorageOptions)`.
- `put(key, bytes)` / `get(key)` / `delete(key)` / `exists(key)` — same shape as `UploadStorage`.
## Implementation Notes
- The path-traversal check rejects ANY separator in the raw key, then resolves and re-verifies the resolved path is inside `rootDir`. The double check defends against both crafted strings AND quirky platform path normalisation.
- `readFile` returns a `Buffer`; the wrapper re-wraps as `Uint8Array` so callers see a tier-neutral byte view.
- Storage failures preserve the underlying `cause` so operators can trace EACCES / ENOSPC at the OTel log layer without losing context.