createUploader

An upload-tool factory compatible with the legacy backend's upload endpoints. Returns four methods — { uploadImage, uploadVideo, uploadFile, queryVideo } — covering single-shot image upload, concurrent chunked video upload with transcode polling, and generic file (PDF / docs / zip) chunked upload.

📌 Business code should prefer the useUploader composable or the SwUploadImage / SwUploadVideo / SwUploadFile components — a framework plugin already instantiates createUploader with systemInfo / userId wired up. Calling createUploader directly is mainly for custom-injection scenarios (e.g. non-standard store sources).

How It Works

  1. The factory takes system config and userId as getters (getSystemInfo / getUserId), evaluated at call time to avoid stale closures.
  2. uploadImage: validates the byte size locally first (images use upload_image_max_length, falling back to upload_file_max_length when unset); single POST whose response file_info (e.g. "1280x720") is parsed into width / height.
  3. uploadVideo: each File gets its own chunk uploader instance, running concurrently without blocking each other; defaults to 2MB chunks and 3 retries per chunk.
  4. uploadFile: shares the chunk endpoint with video but has no transcode phase (never calls queryVideo) — the final chunk response already contains the accessible URL, returned as a Promise.
  5. queryVideo: polls the transcode result every 3 seconds until file_m3u8 is available or retries are exhausted (default 20 ≈ 60 seconds).

Endpoint URLs (upload_image_url etc.) come from systemInfo with common params already attached; upload timeout follows uploadTimeout in the request block of swift.config.json (default 600s).

API

const uploader = createUploader({
  getSystemInfo: () => useSystemStore().info as SystemInfo,
  getUserId: () => useUserStore().id,
})
MethodSignatureNotes
uploadImage(file: File, thumbnail: boolean) => Promise<{ id, value, width, height }>Single-shot image upload; thumbnail requests a thumbnail; value is the file URL
uploadVideo(files: File[], options?) => voidConcurrent chunked video upload; results via onProcess / onSuccess / onError callbacks
uploadFile(file: File, options?) => Promise<{ id, value, file_md5 }>Chunked generic-file upload, no transcoding; value is the access URL
queryVideo(id: string, retries = 20) => Promise<VideoQueryResult>Polls transcode result; returns { id, file_m3u8, file_duration, file_preview_m3u8, file_status, width, height }

Options for uploadVideo / uploadFile: chunkSize (default 2MB) / retries (default 3) / onProcess (progress { processed_num, chunk_total }) / onBefore; uploadVideo additionally takes onSuccess / onError, uploadFile additionally takes concurrency (concurrent chunks, default 6).

Examples

// Upload an image and fill the form
const { id, value, width, height } = await uploader.uploadImage(file, false)
form.cover = { id, url: value, w: width, h: height }

// Chunked video upload + progress + transcode query
uploader.uploadVideo([videoFile], {
  onProcess: ({ processed_num, chunk_total }) => (progress.value = processed_num / chunk_total),
  onSuccess: async ({ id }) => {
    form.video = await uploader.queryVideo(id)
  },
  onError: (e) => console.error('upload failed', e),
})

// Generic file (Promise style, no transcode phase)
const { value: fileUrl } = await uploader.uploadFile(pdfFile, {
  onProcess: ({ processed_num, chunk_total }) => (progress.value = processed_num / chunk_total),
})

Caveats

queryVideo throws after ~60 seconds by default (UUP-001, warning)

Default polling is 20 attempts × 3s, then it throws Error('查询重试次数已用尽'). With a slow / broken transcoder the flow stalls for 60s and then throws — always try/catch with UI feedback, or raise the retry count:

onSuccess: async ({ id }) => {
  try {
    form.video = await uploader.queryVideo(id)
  } catch {
    useToast().info('Video still processing — check your drafts later') // or queryVideo(id, 40)
  }
}

Others

  • Browser only (depends on File / FormData / Blob) — never call during SSR.
  • uploadImage throws Error('文件超出大小') when exceeding upload_file_max_length; failed file_info / file_quality dimension parsing also throws explicit errors.
  • uploadVideo silently retries each failed chunk until retries is exhausted, only then invoking onError.