2.4 KiB
2.4 KiB
single-shot.ts
Purpose
Internal back-end implementing the singleShot operation of FileUploadService. Extracted from the main service file to keep each implementation file under the suaveplan 300-line budget while still keeping the responsibility cohesive: size limit → MIME validation (with sniff cross-check) → storage persistence → record save → OTel emission.
Features
- Encapsulates the full single-shot validation pipeline so the public
FileUploadService.singleShotis a single function call. - Reads the first 4 KiB into the MIME sniffer so spoofed Content-Types are rejected without buffering the whole payload twice.
- Counts outcomes (
success/rejected/error) ontoupload.singleshot_totaland bytes ontoupload.bytes_totalso dashboards reflect every code path. - Generic in the id generator and clock so
createFileUploadServicecan plug in its own deterministic values for tests.
Usage: Basic
import { runSingleShot } from "@suaveplan/api-plugin-file-upload";
const record = await runSingleShot(
{ principalId: "alice", fileName: "hello.txt", bytes, declaredMimeType: "text/plain" },
{ config, storage, sessionStore, idGenerator: () => "u1", clock: () => Date.now() }
);
Usage: Advanced
import { runSingleShot, FileUploadError } from "@suaveplan/api-plugin-file-upload";
try {
await runSingleShot(input, opts);
} catch (err) {
if (err instanceof FileUploadError && err.uploadCode === "UPLOAD.MIME_REJECTED") {
// spoof or denied — render UI-friendly 415 page
}
throw err;
}
API Reference
SingleShotInput—{ principalId, tenantId?, fileName, bytes, declaredMimeType }.RunSingleShotOptions—{ config, storage, sessionStore, idGenerator, clock }.runSingleShot(input, opts): Promise<UploadRecord>— see Purpose for pipeline order; throwsUPLOAD.TOO_LARGE,UPLOAD.MIME_REJECTED, orUPLOAD.STORAGE_FAILUREdepending on which guard fires.
Implementation Notes
- The sniff sample is capped at 4 KiB because every magic-bytes signature the
@suaveplan/mimeregistry ships fits well inside that window; sniffing more wastes CPU on tiny files and offers no additional confidence. - Outcomes distinguish
rejected(validation-side failure,FileUploadError) fromerror(storage/store-side failure, any other Error) so on-call rotations can alert onerrorwithout being paged for legitimate user rejections.