@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 — Owns the chunked-upload assembly + integrity-verification pipeline.
assembleChunkspulls every chunk from a caller-su…- assembler — Owns the chunked-upload assembly + integrity-verification pipeline.
assembleChunkspulls every chunk from a caller-su…
- assembler — Owns the chunked-upload assembly + integrity-verification pipeline.
- error-codes — Defines the stable error-code registry for
@suaveplan/api-plugin-file-upload. Each failure path in the plugin throws…- error-codes — Defines the stable error-code registry for
@suaveplan/api-plugin-file-upload. Each failure path in the plugin throws…
- error-codes — Defines the stable error-code registry for
- otel — Owns the OpenTelemetry instrument bundle for
@suaveplan/api-plugin-file-upload: four counters and one histogram. Ever…- instruments — Owns the OpenTelemetry instrument bundle for
@suaveplan/api-plugin-file-upload: four counters and one histogram. Ever…
- instruments — Owns the OpenTelemetry instrument bundle for
- plugin — Authoritative
createFileUploadPluginfactory. Wraps the resolved configuration in a `PluginDescriptor<FileUploadPlugi…- plugin — Authoritative
createFileUploadPluginfactory. Wraps the resolved configuration in a `PluginDescriptor<FileUploadPlugi…
- plugin — Authoritative
- build-routes — Builds the 6 OpenAPI route entries the plugin mounts on the host Hono app: single-shot
POST /, chunked-init `POST /in… - handlers — Per-route Hono handler implementations consumed by
buildUploadRoutes. Each handler reads the auth principal from `c.g… - schemas — Defines the Zod schema validating caller-supplied
FileUploadPluginOptions. Invalid input — wrong type, malformed `bas…- initiate — Defines the request body and response shape for
POST /uploads/initiate, the chunked upload bootstrap endpoint. The cl… - single-shot — Defines the typed JSON response returned by both
POST /uploads(single-shot) andPOST /uploads/{uploadId}/complete… - status — Defines the path-parameter and response shapes for the remaining chunked-upload routes: `PUT /uploads/{uploadId}/chunks…
- options — Defines the Zod schema validating caller-supplied
FileUploadPluginOptions. Invalid input — wrong type, malformed `bas…
- initiate — Defines the request body and response shape for
- complete-chunked — Internal back-end implementing the
completeoperation ofFileUploadService. Extracted from the main service file so… - file-upload-helpers — Internal helpers shared by
file-upload-service.ts: the storage-key naming convention (CHUNK_KEY,RECORD_KEY) and… - file-upload-service — Canonical
FileUploadServicefactory consumed by the plugin's route handlers and registered as the typed `fileUploadSe… - registry-augmentation — Augments the cross-package
ServiceRegistryinterface declared in@suaveplan/api-plugin/service-registryso consumer… - single-shot — Internal back-end implementing the
singleShotoperation ofFileUploadService. Extracted from the main service file… - session-store — In-memory
UploadSessionStoreadapter. Tracks both in-flightUploadSessionstate (sessions Map) and completed `Uploa…- memory — In-memory
UploadSessionStoreadapter. Tracks both in-flightUploadSessionstate (sessions Map) and completed `Uploa…
- memory — In-memory
- file-system — Production-grade
UploadStorageadapter backed bynode:fs/promises. Stores bytes as flat files under a configurable… - memory — In-memory
UploadStorageadapter. Stores raw bytes in a process-localMap<string, Uint8Array>for fast unit tests an… - types — Defines the public TypeScript surface of
@suaveplan/api-plugin-file-upload: the caller-facing `FileUploadPluginOption…- types — Defines the public TypeScript surface of
@suaveplan/api-plugin-file-upload: the caller-facing `FileUploadPluginOption…
- types — Defines the public TypeScript surface of
- mime — Cross-checks the declared
Content-Typeagainst the plugin's configured allow/deny lists AND (optionally) against the… - size — Tiny but central pair of helpers that enforce upload size limits and compute chunked-upload geometry. `enforceSizeLimit…
Install
bun add @suaveplan/api-plugin-file-upload
Quick start
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—createFileUploadPluginfactory + lifecycle.error-codes/error-codes— 11UPLOAD_*codes +FileUploadError.otel/instruments— 4 counters + 1 histogram.storage/memory— test-onlyUploadStorage.storage/file-system— production filesystem-backedUploadStorage.session-store/memory— defaultUploadSessionStore.services/file-upload-service—FileUploadServicefactory.services/file-upload-helpers— ownership / key helpers.services/single-shot— single-shot back-end.services/complete-chunked— chunked-complete back-end.assembler/assembler— chunk concat + SHA-256.validators/mime— allow/deny + sniff cross-check.validators/size— size limits + chunk math.routes/build-routes— 6-route OpenAPI builder.routes/handlers— per-route Hono handlers.schemas/options— plugin options schema.schemas/routes/single-shot—SingleShotResponseSchema.schemas/routes/initiate— chunked-init request/response.schemas/routes/status— chunk / complete / status / abort schemas.types/types— public data model.