# @suaveplan/api-plugin-file-upload - Hono plugin for @suaveplan/api: multipart and chunked file uploads with size + MIME validation, SHA-256 hash verification, resumable sessions, per-principal isolation, pluggable UploadStorage + UploadSessionStore, 11 UPLOAD_* error codes, OpenTelemetry counters/histogram, and 6 typed OpenAPI routes. Builds on @suaveplan/api-plugin-auth so every route is requireAuth-gated and scoped to the current principal (and optional tenant). Ships MemoryUploadStorage (test-only) and FileSystemUploadStorage (production) adapters out of the box. Multipart and chunked file-upload plugin for `@suaveplan/api`. Ships six OpenAPI-typed Hono routes, a pluggable storage + session-store contract, SHA-256 hash verification, MIME spoof detection via `@suaveplan/mime`, eleven stable error codes, and full OpenTelemetry instrumentation. Every route is `requireAuth()`-gated through `@suaveplan/api-plugin-auth` and scoped to the calling principal (and optional tenant) so cross-user enumeration is impossible — foreign upload IDs return 404. ## Documentation tree - [assembler](./src/assembler/assembler.md) — Owns the chunked-upload assembly + integrity-verification pipeline. `assembleChunks` pulls every chunk from a caller-su… - [assembler](./src/assembler/assembler.md) — Owns the chunked-upload assembly + integrity-verification pipeline. `assembleChunks` pulls every chunk from a caller-su… - [error-codes](./src/error-codes/error-codes.md) — Defines the stable error-code registry for `@suaveplan/api-plugin-file-upload`. Each failure path in the plugin throws… - [error-codes](./src/error-codes/error-codes.md) — Defines the stable error-code registry for `@suaveplan/api-plugin-file-upload`. Each failure path in the plugin throws… - [otel](./src/otel/instruments.md) — Owns the OpenTelemetry instrument bundle for `@suaveplan/api-plugin-file-upload`: four counters and one histogram. Ever… - [instruments](./src/otel/instruments.md) — Owns the OpenTelemetry instrument bundle for `@suaveplan/api-plugin-file-upload`: four counters and one histogram. Ever… - [plugin](./src/plugin/plugin.md) — Authoritative `createFileUploadPlugin` factory. Wraps the resolved configuration in a `PluginDescriptor` for fast unit tests an… - [types](./src/types/types.md) — Defines the public TypeScript surface of `@suaveplan/api-plugin-file-upload`: the caller-facing `FileUploadPluginOption… - [types](./src/types/types.md) — Defines the public TypeScript surface of `@suaveplan/api-plugin-file-upload`: the caller-facing `FileUploadPluginOption… - [mime](./src/validators/mime.md) — Cross-checks the declared `Content-Type` against the plugin's configured allow/deny lists AND (optionally) against the… - [size](./src/validators/size.md) — Tiny but central pair of helpers that enforce upload size limits and compute chunked-upload geometry. `enforceSizeLimit… ## Install ```sh bun add @suaveplan/api-plugin-file-upload ``` ## Quick start ```ts import { createApi } from "@suaveplan/api"; import { createAuthPlugin } from "@suaveplan/api-plugin-auth"; import { createFileUploadPlugin, FileSystemUploadStorage, } from "@suaveplan/api-plugin-file-upload"; const api = createApi({ port: 3000 }); await api.registry.register(createAuthPlugin({ betterAuth: { /* … */ } })); await api.registry.register( createFileUploadPlugin({ basePath: "/uploads", singleShotLimitBytes: 32 * 1024 * 1024, maxFileSizeBytes: 4 * 1024 * 1024 * 1024, storage: new FileSystemUploadStorage({ rootDir: "/var/lib/uploads" }), }) ); await api.start(); ``` ## Routes | Method | Path | Description | |--------|---------------------------------------|--------------------------------------| | POST | `/uploads` | Single-shot multipart upload | | POST | `/uploads/initiate` | Begin a chunked session | | PUT | `/uploads/{uploadId}/chunks/{index}` | Upload a single chunk | | POST | `/uploads/{uploadId}/complete` | Assemble + verify + finalise | | DELETE | `/uploads/{uploadId}` | Abort and reclaim partial state | | GET | `/uploads/{uploadId}` | Status / resume | ## Modules - [`plugin/plugin`](./src/plugin/plugin.md) — `createFileUploadPlugin` factory + lifecycle. - [`error-codes/error-codes`](./src/error-codes/error-codes.md) — 11 `UPLOAD_*` codes + `FileUploadError`. - [`otel/instruments`](./src/otel/instruments.md) — 4 counters + 1 histogram. - [`storage/memory`](./src/storage/memory.md) — test-only `UploadStorage`. - [`storage/file-system`](./src/storage/file-system.md) — production filesystem-backed `UploadStorage`. - [`session-store/memory`](./src/session-store/memory.md) — default `UploadSessionStore`. - [`services/file-upload-service`](./src/services/file-upload-service.md) — `FileUploadService` factory. - [`services/file-upload-helpers`](./src/services/file-upload-helpers.md) — ownership / key helpers. - [`services/single-shot`](./src/services/single-shot.md) — single-shot back-end. - [`services/complete-chunked`](./src/services/complete-chunked.md) — chunked-complete back-end. - [`assembler/assembler`](./src/assembler/assembler.md) — chunk concat + SHA-256. - [`validators/mime`](./src/validators/mime.md) — allow/deny + sniff cross-check. - [`validators/size`](./src/validators/size.md) — size limits + chunk math. - [`routes/build-routes`](./src/routes/build-routes.md) — 6-route OpenAPI builder. - [`routes/handlers`](./src/routes/handlers.md) — per-route Hono handlers. - [`schemas/options`](./src/schemas/options.md) — plugin options schema. - [`schemas/routes/single-shot`](./src/schemas/routes/single-shot.md) — `SingleShotResponseSchema`. - [`schemas/routes/initiate`](./src/schemas/routes/initiate.md) — chunked-init request/response. - [`schemas/routes/status`](./src/schemas/routes/status.md) — chunk / complete / status / abort schemas. - [`types/types`](./src/types/types.md) — public data model.