Initial Commit

This commit is contained in:
2026-05-27 23:29:53 +01:00
commit fbc70f96e6
10000 changed files with 1102152 additions and 0 deletions

View File

@@ -0,0 +1,112 @@
# Proposal: complete-drive — fill VFS-core gaps in @suaveplan/drive
- **Change ID**: `complete-drive`
- **Capability**: `drive`
- **Package**: `@suaveplan/drive`
- **Status**: PROPOSED
- **Design**: ./design.md
- **Spec delta**: ./specs/drive/spec.md
- **Companions** (parallel, share surface, scope-disjoint): `complete-drive-uri`, `complete-types-drive-promotion`
## Why
The current genesis `@suaveplan/drive` ships the VFS spine (constructor overloads,
init/dispose FSM, plugin slot, middleware chain for read/write/delete/stat/list,
template hydration via `hydrateFrom`/`getKeyStatus`/`getPresence`, `DRIVE_*` codes)
but several capabilities implied by the package's identity as a **file-VFS core** are
either partial or missing. They block downstream packages (`drive-mesh`,
`drive-sharing`, `drive-react-sharing`, `drive-plugin-cache`) from composing against
a stable surface.
## What
### Audit findings (genesis vs. upstream + CLAUDE.md identity)
| # | Gap | Today | Required |
|---|---|---|---|
| 1 | `createReadStream` signature | `(path, signal?)` positional | overload `(path, options?: { offset?; length?; signal? })` so range reads and aborts cohabit |
| 2 | `createWriteStream` signature | `(path, signal?)` positional | overload `(path, options?: { signal? })` for parity, no behaviour drift |
| 3 | `Drive.copy(src, dst, opts?)` | missing | atomic copy via middleware chain, emits `drive:copy:before/after` |
| 4 | `Drive.move(src, dst, opts?)` | missing | rename = copy+delete on storages without native rename; middleware-wrapped |
| 5 | Op-set width for `delete`/`stat` | `signal?` positional | accept `{ signal? }` options bundle (matches `read`/`write`) |
| 6 | `Drive.list` return type | typed `unknown` | typed `AsyncIterable<DriveEntry>` + page result; respect `recursive`/`limit`/`cursor` |
| 7 | `Drive.watch(path, opts?)` | missing | EventBus-backed change subscription returning `AsyncIterable<DriveChangeEvent>` + `unsubscribe()` |
| 8 | Hydration progress events | callback only | also emit `drive:hydrate:progress` on the EventBus (delivery to multiple subscribers) |
| 9 | Middleware coverage | read/write/delete/stat/list | add `copy`, `move`, `watch` middleware slots so plugins can wrap every op |
| 10 | Plugin lifecycle API | install + dispose-on-drive-dispose | `unloadPlugin(name)`, `listPlugins()`, `findPlugin(name)`, ordered handle map, idempotent unload |
| 11 | Quota / usage | absent | `Drive.usage()` aggregating per-storage byte counts; `drive:quota:exceeded` event when caller-configured soft/hard caps trip |
| 12 | Sharing integration hook | absent | `DriveShareLike` interface in drive (no drive-sharing dep) + `drive.shareHook?: DriveShareLike` slot |
| 13 | `DRIVE_CODES` registry | 11 codes | add `COPY_FAILED`, `MOVE_FAILED`, `WATCH_FAILED`, `QUOTA_EXCEEDED`, `OPERATION_ABORTED`, `STORAGE_READONLY` |
| 14 | Snapshot/transaction API | upstream has `cow`, `journal`, `snapshots` siblings | **OUT OF SCOPE** — handled by future `drive-snapshot` / `drive-journal` plugin packages; we land only the middleware seam they will plug into |
| 15 | OTEL spans on every op | partial | spans per public entrypoint (`drive.read`, `drive.write`, `drive.copy`, …) named `drive.<op>` with `drive.storage.id` attribute |
| 16 | 100% coverage | currently below 100% | hard gate at 100/100/100/100 (statements/branches/functions/lines), istanbul |
### Out of scope
- **Sharing-specific UX** — owned by `@suaveplan/drive-sharing` and
`@suaveplan/drive-react-sharing`. We expose only the `DriveShareLike` interface
(no runtime dep on either package).
- **Mesh transport details** — owned by `@suaveplan/drive-mesh-protocol`,
`@suaveplan/drive-mesh`, `@suaveplan/drive-transport-https`,
`@suaveplan/drive-transport-webrtc`, `@suaveplan/drive-webrtc`. We expose only
the plugin slot + middleware seam they consume.
- **Template signing / nonce verification** — owned by `@suaveplan/drive-template`.
We continue to invoke its pipeline from `hydrateFrom`; no signing logic moves into
drive itself.
- **URI / locator** — owned by `@suaveplan/drive-uri` (covered by sibling change
`complete-drive-uri`).
- **Shared cross-package types** — promoted into `@suaveplan/types` by sibling
change `complete-types-drive-promotion`; this change imports them once they land
but does not block on the promotion (the local types stay valid until then).
- **Encryption / chunking / dedup / journal / extents / snapshots / transforms /
metadata-store** — every one of these is a sibling package today
(`drive-plugin-chunks`, future `drive-plugin-*`); not a drive-core responsibility.
## Impact
### Affected dependents
Run `bunx turbo ls --filter=...@suaveplan/drive` to enumerate. For each dependent:
- `@suaveplan/drive-template` — [x] tests run / [x] docs reviewed / [ ] no action needed — consumes `hydrateFrom` + nonce LRU; new progress events are additive, no breakage.
- `@suaveplan/drive-plugin-chunks` — [x] tests run / [x] docs reviewed / [ ] no action needed — plugin/middleware contract widens (additive); existing plugin keeps working.
- `@suaveplan/drive-plugin-cache` — [x] tests run / [x] docs reviewed / [ ] no action needed — new `copy`/`move` middleware slots are opt-in.
- `@suaveplan/drive-mesh-protocol` — [ ] tests run / [ ] docs reviewed / [x] no action needed (reason: pure wire-protocol, does not touch Drive surface).
- `@suaveplan/drive-mesh` — [x] tests run / [x] docs reviewed / [ ] no action needed — adopts widened plugin lifecycle (`unloadPlugin`).
- `@suaveplan/drive-transport-https` — [x] tests run / [x] docs reviewed / [ ] no action needed — passes through middleware, no API impact.
- `@suaveplan/drive-transport-webrtc` — [x] tests run / [x] docs reviewed / [ ] no action needed.
- `@suaveplan/drive-webrtc` — [x] tests run / [x] docs reviewed / [ ] no action needed.
- `@suaveplan/drive-sharing` — [x] tests run / [x] docs reviewed / [ ] no action needed — gains optional `DriveShareLike` integration; legacy path unchanged.
- `@suaveplan/drive-react-sharing` — [ ] tests run / [ ] docs reviewed / [x] no action needed (reason: re-exports drive-sharing types only).
## Migration
- **Old**: `drive.createReadStream(path, signal)` / `createWriteStream(path, signal)` — positional `signal`.
- **New**: `drive.createReadStream(path, { offset?, length?, signal? })` / `createWriteStream(path, { signal? })` — options bundle.
- **Compatibility**: both forms accepted via overload; positional-`signal` form remains valid for one minor cycle, then becomes a TypeScript error in `0.1.0`.
- **Search command for consumers**: `grep -rn "createReadStream\|createWriteStream" packages/ | grep -v "/dist/\|/coverage/"`
- **Recommended replacement**: always pass the options bundle.
- **Old**: `drive.delete(path, signal)` / `drive.stat(path, signal)` positional.
- **New**: `drive.delete(path, { signal? })` / `drive.stat(path, { signal? })` options bundle (positional kept as overload for one cycle).
- **Search**: `grep -rn "drive\.\(delete\|stat\)(" packages/ | grep -v "/dist/"`.
## Parity Checklist
| Capability | Upstream (`main`) | Genesis after this change | Notes |
|---|---|---|---|
| POSIX `open/close/read/write/lseek/fsync` file-descriptor model | ✅ | 🚫 | Scoped out: genesis Drive is a high-level VFS, not POSIX FD emulation. The upstream FD API is unused in any genesis dependent and superseded by `read`/`write` + streams. |
| `readFile`/`writeFile`/`appendFile` | ✅ | ⬆️ | Renamed to `read`/`write`; `append` via streams. |
| `copyFile`/`rename`/`truncate` | ✅ | ⬆️ | Becomes `copy`/`move`; `truncate` via streams or future plugin. |
| `mkdir`/`rmdir`/`rm`/`readdir`/`readdirWithTypes` | ✅ | 🚫 | Scoped out: genesis storage substrate is key-value (no real directories). `list(prefix)` covers the use case; directories are a sibling-plugin concern. |
| `stat`/`lstat`/`access`/`exists`/`chmod`/`chown`/`utimes` | ✅ | ⬆️ | `stat` with options bundle stays; permissions/ownership are sibling-plugin concerns (no POSIX permission model in genesis universal tier). |
| `symlink`/`readlink`/`realpath` | ✅ | 🚫 | Scoped out: symlinks belong to a future `drive-plugin-symlinks` if needed. |
| `cd`/`pwd` cwd model | ✅ | 🚫 | Scoped out: genesis Drive forbids relative paths (path validator rejects `..` and leading `/`); cwd has no meaning. |
| `createReadStream`/`createWriteStream` | ✅ | ⬆️ | Options-bundle overload; range reads via `{ offset, length }`. |
| Plugin manager (add/remove/list) | ✅ | ⬆️ | `usePlugin` + new `unloadPlugin`/`listPlugins`/`findPlugin`. |
| Storage failover | ✅ | 🚫 | Scoped out: failover belongs to `drive-mesh` server-fallback path or a future `drive-plugin-failover`. |
| `chunks` / `cow` / `dedup` / `encryption` / `extents` / `journal` / `metadata-store` / `snapshots` / `transforms` subsystems | ✅ | 🚫 | Each is or will be a sibling package (`drive-plugin-chunks` already ships). VFS core only exposes the plugin/middleware seam. |
| Template hydration (`hydrateFrom`/`getKeyStatus`/`getPresence`) | 🚫 | ⬆️ | Genesis-original capability, added by `drive-template`. |
| EventBus integration | ✅ (direct emitter) | ⬆️ | Genesis uses injectable `EventBusLike` from `@suaveplan/types`; same contract, no upstream coupling. |
| Quota / usage | 🚫 | ⬆️ | New: aggregates per-storage usage + emits soft/hard threshold events. |
| Sharing-integration hook | 🚫 | ⬆️ | New: `DriveShareLike` interface (drive owns the contract; `drive-sharing` implements). |