Files
skills/plugins/document-navigator/docs/api-stack/api/api-plugin-file-upload/README.md
admin 9bf56a806b Move docs/ package mirror into document-navigator plugin
Relocate the ~6k-file docs tree from the repo root into
plugins/document-navigator/docs/ so the plugin is self-contained and
portable. docs/superpowers/ (specs and plans) stays at the repo root.

Moved via cp+rm rather than git mv because directory rename() fails with
EPERM on this WSL /mnt DrvFs mount; git rename-detection pairs the
identical-content files at commit time.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-30 01:10:00 +01:00

9.0 KiB

@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. assembleChunks pulls every chunk from a caller-su…
    • assembler — Owns the chunked-upload assembly + integrity-verification pipeline. assembleChunks pulls every chunk from a caller-su…
  • 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…
  • 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…
  • plugin — Authoritative createFileUploadPlugin factory. Wraps the resolved configuration in a `PluginDescriptor<FileUploadPlugi…
    • plugin — Authoritative createFileUploadPlugin factory. Wraps the resolved configuration in a `PluginDescriptor<FileUploadPlugi…
  • 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) and POST /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…
  • complete-chunked — Internal back-end implementing the complete operation of FileUploadService. 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 FileUploadService factory consumed by the plugin's route handlers and registered as the typed `fileUploadSe…
  • registry-augmentation — Augments the cross-package ServiceRegistry interface declared in @suaveplan/api-plugin/service-registry so consumer…
  • single-shot — Internal back-end implementing the singleShot operation of FileUploadService. Extracted from the main service file…
  • session-store — In-memory UploadSessionStore adapter. Tracks both in-flight UploadSession state (sessions Map) and completed `Uploa…
    • memory — In-memory UploadSessionStore adapter. Tracks both in-flight UploadSession state (sessions Map) and completed `Uploa…
  • file-system — Production-grade UploadStorage adapter backed by node:fs/promises. Stores bytes as flat files under a configurable…
  • memory — In-memory UploadStorage adapter. Stores raw bytes in a process-local Map<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…
  • mime — Cross-checks the declared Content-Type against 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