2.5 KiB
2.5 KiB
complete-chunked.ts
Purpose
Internal back-end implementing the complete operation of FileUploadService. Extracted from the main service file so each module stays under the suaveplan 300-line budget. The pipeline is: assemble every chunk in [0, totalChunks) order → verify SHA-256 against the declared expected hash (or an explicit override) → write the assembled bytes to the canonical record key → save the UploadRecord → garbage-collect per-chunk storage entries → clear the in-flight session.
Features
- Single-pass assembly via the
assemblerhelper so chunk ordering and missing-chunk detection live in one place. - Override-on-complete lets clients adjust the declared hash if they recomputed mid-flight without rebuilding the entire session.
- Emits both the outcome counter (
upload.completes_total{outcome}) and the duration histogram (upload.complete_duration_ms{outcome}) on every code path so dashboards can correlate failure rate with latency. - Cleanup runs even on success (chunk-side storage entries are deleted) so the storage adapter never accumulates orphaned chunk keys.
Usage: Basic
import { runComplete } from "@suaveplan/api-plugin-file-upload";
const record = await runComplete(session, undefined, {
storage,
sessionStore,
clock: () => Date.now(),
});
Usage: Advanced
import { runComplete, FileUploadError } from "@suaveplan/api-plugin-file-upload";
try {
await runComplete(session, clientRecomputedHash, opts);
} catch (err) {
if (err instanceof FileUploadError) {
switch (err.uploadCode) {
case "UPLOAD.INCOMPLETE":
return c.json({ retry: true, reason: "missing-chunks" }, 409);
case "UPLOAD.HASH_MISMATCH":
return c.json({ retry: true, reason: "hash-mismatch" }, 422);
}
}
throw err;
}
API Reference
RunCompleteOptions—{ storage, sessionStore, clock }.runComplete(session, overrideSha256?, opts): Promise<UploadRecord>— see Purpose for pipeline order; throwsUPLOAD.INCOMPLETE,UPLOAD.HASH_MISMATCH, orUPLOAD.STORAGE_FAILURE.
Implementation Notes
- The chunk deletion loop runs sequentially. A parallel
Promise.allis tempting but most storage adapters (FileSystemUploadStoragein particular) prefer FIFO syscalls to avoid file-descriptor exhaustion on very large uploads. - The histogram is recorded INSIDE the
tryso even early failures (e.g. an assemble that throws on the second chunk) still contribute to the observed-failure-latency picture.