Skip to main content

Progress tracking

Pass an onProgress callback to upload() to track upload progress:
import { upload } from "@blindcast/uploader"

const result = await upload(segments, manifest, {
  contentId: "my-video-001",
  keyServerUrl: "https://keys.example.com/keys",
  presignUrl: "https://api.example.com/presign",
  auth: async () => getAccessToken(),
  onProgress: ({ completed, total, current }) => {
    const pct = Math.round((completed / total) * 100)
    updateProgressBar(pct)
    console.log(`[${pct}%] ${completed}/${total} — uploading ${current}`)
  },
})

Progress payload

FieldTypeDescription
completednumberNumber of segments uploaded so far
totalnumberTotal number of segments
currentstringFilename of the segment currently being uploaded
onProgress is called once per segment upload completion. It is not called for the encryption step or the manifest upload.

Abort uploads

Use an AbortController to cancel an in-flight upload:
const controller = new AbortController()

// Start upload
const uploadPromise = upload(segments, manifest, {
  contentId: "my-video-001",
  keyServerUrl: "https://keys.example.com/keys",
  presignUrl: "https://api.example.com/presign",
  auth: async () => getAccessToken(),
  signal: controller.signal,
})

// Cancel after 30 seconds
setTimeout(() => controller.abort(), 30_000)

// Or cancel on user action
cancelButton.addEventListener("click", () => controller.abort())

const result = await uploadPromise

if (!result.ok && result.error.code === "ABORTED") {
  console.log("Upload cancelled by user")
}
When aborted:
  • All in-flight S3 uploads are cancelled
  • The upload() promise resolves with { ok: false, error: { code: "ABORTED" } }
  • Already-uploaded segments remain in S3 (they are not cleaned up automatically)

Cleaning up partial uploads

If you need to clean up partially uploaded segments after an abort, use the segment URLs from the progress callback:
const uploadedSegments: string[] = []

const result = await upload(segments, manifest, {
  // ...
  onProgress: ({ current }) => {
    uploadedSegments.push(current)
  },
  signal: controller.signal,
})

if (!result.ok && result.error.code === "ABORTED") {
  // Clean up partial uploads via your API
  await fetch("/api/cleanup", {
    method: "POST",
    body: JSON.stringify({ segments: uploadedSegments }),
  })
}