Files
skills/docs/api-stack/api/api-plugin-file-upload/src/routes/handlers.md
2026-05-29 08:20:56 +01:00

2.6 KiB

handlers.ts

Purpose

Per-route Hono handler implementations consumed by buildUploadRoutes. Each handler reads the auth principal from c.get("user"), optionally narrows to a tenant via c.get("tenant"), parses the request body / params with the per-route Zod schemas, delegates to FileUploadService, and projects the service's UploadSession/UploadRecord return value onto the wire response shape.

Features

  • Single readScope(c) helper produces a PrincipalScope from the augmented Hono context. Missing principal raises UPLOAD.INVALID_INPUT (the sibling requireAuth() middleware should have already replied 401, so reaching this path indicates plugin misconfiguration).
  • toStatus projects either an UploadSession (in-progress) or an UploadRecord (complete) onto the uniform UploadStatusResponse shape so the GET route serves both phases through a single schema.
  • Multipart parsing for POST /uploads reads via c.req.parseBody(); chunk PUT reads via c.req.raw.arrayBuffer() so binary payloads are preserved byte-for-byte.

Usage: Basic

import { buildHandlers } from "@suaveplan/api-plugin-file-upload";

const handlers = buildHandlers(service);
// `handlers.singleShot`, `handlers.initiate`, …, `handlers.status`

Usage: Advanced

import { buildHandlers, FileUploadError } from "@suaveplan/api-plugin-file-upload";

const handlers = buildHandlers(service);
app.post("/uploads", async (c) => {
    try {
        return await handlers.singleShot(c);
    } catch (err) {
        if (err instanceof FileUploadError && err.uploadCode === "UPLOAD.TOO_LARGE") {
            return c.json({ retry: false }, 413);
        }
        throw err;
    }
});

API Reference

  • buildHandlers(service: FileUploadService): { singleShot, initiate, chunk, complete, abort, status } — each value is a (c: Context) => Promise<Response>.

Implementation Notes

  • The readScope helper checks for null and undefined so the same code runs whether or not the host installed api-plugin-auth (e.g. for integration tests that synthesise a principal directly).
  • parseBody may throw if the client did not send multipart — we translate that to UPLOAD.INVALID_INPUT (400) rather than letting a raw runtime error escape.
  • The chunk PUT handler does NOT cap chunk size at the handler layer because the assembler+service already enforce the session's chunkSize on complete time (a mismatched chunk would fail hash verification).
  • The abort handler returns a static state: "complete" response shape for idempotency — calling abort twice returns success both times.