(
url: string,
{ file, files, XHRImpl, ...options }: UploadFileOptions<TRoute>,
)
| 391 | * @internal |
| 392 | */ |
| 393 | export function uploadFile<TRoute extends AnyFileRoute>( |
| 394 | url: string, |
| 395 | { file, files, XHRImpl, ...options }: UploadFileOptions<TRoute>, |
| 396 | ): Micro.Micro<UploadedFile<TRoute> | FailedFile<TRoute>, never, FetchContext> { |
| 397 | return fetchEff(url, { method: "HEAD", headers: options.traceHeaders }).pipe( |
| 398 | Micro.map(({ headers }) => |
| 399 | Number.parseInt(headers.get("x-ut-range-start") ?? "0"), |
| 400 | ), |
| 401 | Micro.map((rangeStart) => transitionToUploading(file, rangeStart)), |
| 402 | Micro.tap((uploadingFile) => { |
| 403 | options.onEvent({ |
| 404 | type: "upload-started", |
| 405 | file: uploadingFile, |
| 406 | files, |
| 407 | }); |
| 408 | }), |
| 409 | Micro.flatMap((uploadingFile) => |
| 410 | Micro.async<UploadedFile<TRoute>, XHRError | UTStorageError>((resume) => { |
| 411 | const xhr = new XHRImpl(); |
| 412 | xhr.open("PUT", url, true); |
| 413 | |
| 414 | const rangeStart = uploadingFile.sent; |
| 415 | xhr.setRequestHeader("Range", `bytes=${rangeStart}-`); |
| 416 | xhr.setRequestHeader("x-uploadthing-version", version); |
| 417 | xhr.setRequestHeader("b3", options.traceHeaders.b3); |
| 418 | xhr.setRequestHeader("traceparent", options.traceHeaders.traceparent); |
| 419 | xhr.responseType = "json"; |
| 420 | |
| 421 | xhr.upload.addEventListener("progress", (ev) => { |
| 422 | uploadingFile.sent = rangeStart + ev.loaded; |
| 423 | options.onEvent({ |
| 424 | type: "upload-progress", |
| 425 | file: uploadingFile, |
| 426 | files, |
| 427 | }); |
| 428 | }); |
| 429 | xhr.addEventListener("load", () => { |
| 430 | if ( |
| 431 | xhr.status > 299 || |
| 432 | Predicate.hasProperty(xhr.response, "error") |
| 433 | ) { |
| 434 | resume( |
| 435 | new UTStorageError({ |
| 436 | // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access |
| 437 | message: String(xhr.response.error), |
| 438 | response: xhr.response, |
| 439 | }), |
| 440 | ); |
| 441 | } else { |
| 442 | const uploadedFile = transitionToUploaded<TRoute>( |
| 443 | uploadingFile, |
| 444 | xhr.response as UploadPutResult, |
| 445 | ); |
| 446 | options.onEvent({ |
| 447 | type: "upload-completed", |
| 448 | file: uploadedFile, |
| 449 | files, |
| 450 | }); |
no test coverage detected