_250import type { APIRoute } from "astro";_250import { API } from "../../utils/api";_250_250interface MultipartUploadRequest {_250 key: string;_250 contentType?: string;_250}_250_250interface CompleteMultipartRequest {_250 uploadId: string;_250 key: string;_250 parts: R2UploadedPart[];_250}_250_250// Creates and completes a new multipart upload session_250export const POST: APIRoute = async ({ request, locals }) => {_250 // Set the origin for the API_250 API.init(locals.runtime.env.ORIGIN);_250_250 // Handle CORS preflight requests_250 if (request.method === "OPTIONS") {_250 console.log("CORS preflight request from:", request.headers.get("Origin"));_250 return API.cors(request);_250 }_250_250 try {_250 // Check if bucket is available_250 const bucket = locals.runtime.env.CLOUD_FILES;_250 if (!bucket) {_250 return API.error("Cloud storage not configured", request, 500);_250 }_250_250 const url = new URL(request.url);_250 const action = url.searchParams.get("action");_250_250 if (!action) {_250 return API.error("Missing action parameter", request, 400);_250 }_250_250 switch (action) {_250 case "create": {_250 // Create a new multipart upload_250 const body: MultipartUploadRequest = await request.json();_250_250 if (!body.key) {_250 return API.error("Missing key parameter", request, 400);_250 }_250_250 try {_250 const multipartUpload = await bucket.createMultipartUpload(body.key, {_250 httpMetadata: body.contentType_250 ? {_250 contentType: body.contentType,_250 }_250 : undefined,_250 });_250_250 return API.success(_250 {_250 success: true,_250 key: multipartUpload.key,_250 uploadId: multipartUpload.uploadId,_250 },_250 request_250 );_250 } catch (error) {_250 console.error("Failed to create multipart upload:", error);_250 return API.error("Failed to create multipart upload", request, 500);_250 }_250 }_250_250 case "complete": {_250 // Complete a multipart upload_250 const body: CompleteMultipartRequest = await request.json();_250_250 if (!body.uploadId || !body.key || !body.parts) {_250 return API.error("Missing required parameters", request, 400);_250 }_250_250 try {_250 const multipartUpload = bucket.resumeMultipartUpload(_250 body.key,_250 body.uploadId_250 );_250_250 // Parts are already in R2UploadedPart format_250 const r2Parts = body.parts;_250_250 const object = await multipartUpload.complete(r2Parts);_250_250 return API.success(_250 {_250 success: true,_250 key: object.key,_250 etag: object.httpEtag,_250 size: object.size,_250 },_250 request_250 );_250 } catch (error: any) {_250 console.error("Failed to complete multipart upload:", error);_250 return API.error(_250 error.message || "Failed to complete multipart upload",_250 request,_250 400_250 );_250 }_250 }_250_250 default:_250 return API.error(`Unknown action: ${action}`, request, 400);_250 }_250 } catch (error) {_250 console.error("Multipart upload error:", error);_250 return API.error("Multipart upload failed", request, 500);_250 }_250};_250_250// Uploads individual parts of a multipart upload_250export const PUT: APIRoute = async ({ request, locals }) => {_250 // Set the origin for the API_250 API.init(locals.runtime.env.ORIGIN);_250_250 // Handle CORS preflight requests_250 if (request.method === "OPTIONS") {_250 console.log("CORS preflight request from:", request.headers.get("Origin"));_250 return API.cors(request);_250 }_250_250 try {_250 // Check if bucket is available_250 const bucket = locals.runtime.env.CLOUD_FILES;_250 if (!bucket) {_250 return API.error("Cloud storage not configured", request, 500);_250 }_250_250 const url = new URL(request.url);_250 const action = url.searchParams.get("action");_250_250 if (action !== "upload-part") {_250 return API.error(`Unknown action: ${action}`, request, 400);_250 }_250_250 const uploadId = url.searchParams.get("uploadId");_250 const partNumberStr = url.searchParams.get("partNumber");_250 const key = url.searchParams.get("key");_250_250 if (!uploadId || !partNumberStr || !key) {_250 return API.error("Missing uploadId, partNumber, or key", request, 400);_250 }_250_250 const partNumber = parseInt(partNumberStr);_250 if (isNaN(partNumber) || partNumber < 1) {_250 return API.error("Invalid part number", request, 400);_250 }_250_250 if (!request.body) {_250 return API.error("Missing request body", request, 400);_250 }_250_250 try {_250 const multipartUpload = bucket.resumeMultipartUpload(key, uploadId);_250_250 // Convert request body to ArrayBuffer to get known length_250 const arrayBuffer = await request.arrayBuffer();_250 const uploadedPart = await multipartUpload.uploadPart(_250 partNumber,_250 arrayBuffer_250 );_250_250 return API.success(_250 {_250 success: true,_250 partNumber: uploadedPart.partNumber,_250 etag: uploadedPart.etag,_250 },_250 request_250 );_250 } catch (error: any) {_250 console.error("Failed to upload part:", error);_250 return API.error(error.message || "Failed to upload part", request, 400);_250 }_250 } catch (error) {_250 console.error("Upload part error:", error);_250 return API.error("Upload part failed", request, 500);_250 }_250};_250_250// Aborts a multipart upload_250export const DELETE: APIRoute = async ({ request, locals }) => {_250 // Set the origin for the API_250 API.init(locals.runtime.env.ORIGIN);_250_250 // Handle CORS preflight requests_250 if (request.method === "OPTIONS") {_250 console.log("CORS preflight request from:", request.headers.get("Origin"));_250 return API.cors(request);_250 }_250_250 try {_250 // Check if bucket is available_250 const bucket = locals.runtime.env.CLOUD_FILES;_250 if (!bucket) {_250 return API.error("Cloud storage not configured", request, 500);_250 }_250_250 const url = new URL(request.url);_250 const action = url.searchParams.get("action");_250_250 if (action !== "abort") {_250 return API.error(`Unknown action: ${action}`, request, 400);_250 }_250_250 const uploadId = url.searchParams.get("uploadId");_250 const key = url.searchParams.get("key");_250_250 if (!uploadId || !key) {_250 return API.error("Missing uploadId or key", request, 400);_250 }_250_250 try {_250 const multipartUpload = bucket.resumeMultipartUpload(key, uploadId);_250 await multipartUpload.abort();_250_250 return API.success(_250 {_250 success: true,_250 message: "Multipart upload aborted successfully",_250 },_250 request_250 );_250 } catch (error: any) {_250 console.error("Failed to abort multipart upload:", error);_250 return API.error(_250 error.message || "Failed to abort multipart upload",_250 request,_250 400_250 );_250 }_250 } catch (error) {_250 console.error("Abort multipart upload error:", error);_250 return API.error("Abort multipart upload failed", request, 500);_250 }_250};_250_250export const OPTIONS: APIRoute = async ({ request, locals }) => {_250 // Set the origin for the API_250 API.init(locals.runtime.env.ORIGIN);_250 return API.cors(request);_250};
Create the PUT Endpoint
The PUT endpoint handles uploading individual file parts. Each part is uploaded as a separate request, allowing browsers to upload multiple parts concurrently for better performance.
Include the locals parameter, and set up CORS preflight requests.
Access your Object Storage bucket
_250import type { APIRoute } from "astro";_250import { API } from "../../utils/api";_250_250interface MultipartUploadRequest {_250 key: string;_250 contentType?: string;_250}_250_250interface CompleteMultipartRequest {_250 uploadId: string;_250 key: string;_250 parts: R2UploadedPart[];_250}_250_250// Creates and completes a new multipart upload session_250export const POST: APIRoute = async ({ request, locals }) => {_250 // Set the origin for the API_250 API.init(locals.runtime.env.ORIGIN);_250_250 // Handle CORS preflight requests_250 if (request.method === "OPTIONS") {_250 console.log("CORS preflight request from:", request.headers.get("Origin"));_250 return API.cors(request);_250 }_250_250 try {_250 // Check if bucket is available_250 const bucket = locals.runtime.env.CLOUD_FILES;_250 if (!bucket) {_250 return API.error("Cloud storage not configured", request, 500);_250 }_250_250 const url = new URL(request.url);_250 const action = url.searchParams.get("action");_250_250 if (!action) {_250 return API.error("Missing action parameter", request, 400);_250 }_250_250 switch (action) {_250 case "create": {_250 // Create a new multipart upload_250 const body: MultipartUploadRequest = await request.json();_250_250 if (!body.key) {_250 return API.error("Missing key parameter", request, 400);_250 }_250_250 try {_250 const multipartUpload = await bucket.createMultipartUpload(body.key, {_250 httpMetadata: body.contentType_250 ? {_250 contentType: body.contentType,_250 }_250 : undefined,_250 });_250_250 return API.success(_250 {_250 success: true,_250 key: multipartUpload.key,_250 uploadId: multipartUpload.uploadId,_250 },_250 request_250 );_250 } catch (error) {_250 console.error("Failed to create multipart upload:", error);_250 return API.error("Failed to create multipart upload", request, 500);_250 }_250 }_250_250 case "complete": {_250 // Complete a multipart upload_250 const body: CompleteMultipartRequest = await request.json();_250_250 if (!body.uploadId || !body.key || !body.parts) {_250 return API.error("Missing required parameters", request, 400);_250 }_250_250 try {_250 const multipartUpload = bucket.resumeMultipartUpload(_250 body.key,_250 body.uploadId_250 );_250_250 // Parts are already in R2UploadedPart format_250 const r2Parts = body.parts;_250_250 const object = await multipartUpload.complete(r2Parts);_250_250 return API.success(_250 {_250 success: true,_250 key: object.key,_250 etag: object.httpEtag,_250 size: object.size,_250 },_250 request_250 );_250 } catch (error: any) {_250 console.error("Failed to complete multipart upload:", error);_250 return API.error(_250 error.message || "Failed to complete multipart upload",_250 request,_250 400_250 );_250 }_250 }_250_250 default:_250 return API.error(`Unknown action: ${action}`, request, 400);_250 }_250 } catch (error) {_250 console.error("Multipart upload error:", error);_250 return API.error("Multipart upload failed", request, 500);_250 }_250};_250_250// Uploads individual parts of a multipart upload_250export const PUT: APIRoute = async ({ request, locals }) => {_250 // Set the origin for the API_250 API.init(locals.runtime.env.ORIGIN);_250_250 // Handle CORS preflight requests_250 if (request.method === "OPTIONS") {_250 console.log("CORS preflight request from:", request.headers.get("Origin"));_250 return API.cors(request);_250 }_250_250 try {_250 // Check if bucket is available_250 const bucket = locals.runtime.env.CLOUD_FILES;_250 if (!bucket) {_250 return API.error("Cloud storage not configured", request, 500);_250 }_250_250 const url = new URL(request.url);_250 const action = url.searchParams.get("action");_250_250 if (action !== "upload-part") {_250 return API.error(`Unknown action: ${action}`, request, 400);_250 }_250_250 const uploadId = url.searchParams.get("uploadId");_250 const partNumberStr = url.searchParams.get("partNumber");_250 const key = url.searchParams.get("key");_250_250 if (!uploadId || !partNumberStr || !key) {_250 return API.error("Missing uploadId, partNumber, or key", request, 400);_250 }_250_250 const partNumber = parseInt(partNumberStr);_250 if (isNaN(partNumber) || partNumber < 1) {_250 return API.error("Invalid part number", request, 400);_250 }_250_250 if (!request.body) {_250 return API.error("Missing request body", request, 400);_250 }_250_250 try {_250 const multipartUpload = bucket.resumeMultipartUpload(key, uploadId);_250_250 // Convert request body to ArrayBuffer to get known length_250 const arrayBuffer = await request.arrayBuffer();_250 const uploadedPart = await multipartUpload.uploadPart(_250 partNumber,_250 arrayBuffer_250 );_250_250 return API.success(_250 {_250 success: true,_250 partNumber: uploadedPart.partNumber,_250 etag: uploadedPart.etag,_250 },_250 request_250 );_250 } catch (error: any) {_250 console.error("Failed to upload part:", error);_250 return API.error(error.message || "Failed to upload part", request, 400);_250 }_250 } catch (error) {_250 console.error("Upload part error:", error);_250 return API.error("Upload part failed", request, 500);_250 }_250};_250_250// Aborts a multipart upload_250export const DELETE: APIRoute = async ({ request, locals }) => {_250 // Set the origin for the API_250 API.init(locals.runtime.env.ORIGIN);_250_250 // Handle CORS preflight requests_250 if (request.method === "OPTIONS") {_250 console.log("CORS preflight request from:", request.headers.get("Origin"));_250 return API.cors(request);_250 }_250_250 try {_250 // Check if bucket is available_250 const bucket = locals.runtime.env.CLOUD_FILES;_250 if (!bucket) {_250 return API.error("Cloud storage not configured", request, 500);_250 }_250_250 const url = new URL(request.url);_250 const action = url.searchParams.get("action");_250_250 if (action !== "abort") {_250 return API.error(`Unknown action: ${action}`, request, 400);_250 }_250_250 const uploadId = url.searchParams.get("uploadId");_250 const key = url.searchParams.get("key");_250_250 if (!uploadId || !key) {_250 return API.error("Missing uploadId or key", request, 400);_250 }_250_250 try {_250 const multipartUpload = bucket.resumeMultipartUpload(key, uploadId);_250 await multipartUpload.abort();_250_250 return API.success(_250 {_250 success: true,_250 message: "Multipart upload aborted successfully",_250 },_250 request_250 );_250 } catch (error: any) {_250 console.error("Failed to abort multipart upload:", error);_250 return API.error(_250 error.message || "Failed to abort multipart upload",_250 request,_250 400_250 );_250 }_250 } catch (error) {_250 console.error("Abort multipart upload error:", error);_250 return API.error("Abort multipart upload failed", request, 500);_250 }_250};_250_250export const OPTIONS: APIRoute = async ({ request, locals }) => {_250 // Set the origin for the API_250 API.init(locals.runtime.env.ORIGIN);_250 return API.cors(request);_250};
Retrieve the CLOUD_FILES binding that provides access to your Object Storage bucket. This binding contains all the multipart upload methods you'll need throughout the upload process.
Get Action Parameter
_250import type { APIRoute } from "astro";_250import { API } from "../../utils/api";_250_250interface MultipartUploadRequest {_250 key: string;_250 contentType?: string;_250}_250_250interface CompleteMultipartRequest {_250 uploadId: string;_250 key: string;_250 parts: R2UploadedPart[];_250}_250_250// Creates and completes a new multipart upload session_250export const POST: APIRoute = async ({ request, locals }) => {_250 // Set the origin for the API_250 API.init(locals.runtime.env.ORIGIN);_250_250 // Handle CORS preflight requests_250 if (request.method === "OPTIONS") {_250 console.log("CORS preflight request from:", request.headers.get("Origin"));_250 return API.cors(request);_250 }_250_250 try {_250 // Check if bucket is available_250 const bucket = locals.runtime.env.CLOUD_FILES;_250 if (!bucket) {_250 return API.error("Cloud storage not configured", request, 500);_250 }_250_250 const url = new URL(request.url);_250 const action = url.searchParams.get("action");_250_250 if (!action) {_250 return API.error("Missing action parameter", request, 400);_250 }_250_250 switch (action) {_250 case "create": {_250 // Create a new multipart upload_250 const body: MultipartUploadRequest = await request.json();_250_250 if (!body.key) {_250 return API.error("Missing key parameter", request, 400);_250 }_250_250 try {_250 const multipartUpload = await bucket.createMultipartUpload(body.key, {_250 httpMetadata: body.contentType_250 ? {_250 contentType: body.contentType,_250 }_250 : undefined,_250 });_250_250 return API.success(_250 {_250 success: true,_250 key: multipartUpload.key,_250 uploadId: multipartUpload.uploadId,_250 },_250 request_250 );_250 } catch (error) {_250 console.error("Failed to create multipart upload:", error);_250 return API.error("Failed to create multipart upload", request, 500);_250 }_250 }_250_250 case "complete": {_250 // Complete a multipart upload_250 const body: CompleteMultipartRequest = await request.json();_250_250 if (!body.uploadId || !body.key || !body.parts) {_250 return API.error("Missing required parameters", request, 400);_250 }_250_250 try {_250 const multipartUpload = bucket.resumeMultipartUpload(_250 body.key,_250 body.uploadId_250 );_250_250 // Parts are already in R2UploadedPart format_250 const r2Parts = body.parts;_250_250 const object = await multipartUpload.complete(r2Parts);_250_250 return API.success(_250 {_250 success: true,_250 key: object.key,_250 etag: object.httpEtag,_250 size: object.size,_250 },_250 request_250 );_250 } catch (error: any) {_250 console.error("Failed to complete multipart upload:", error);_250 return API.error(_250 error.message || "Failed to complete multipart upload",_250 request,_250 400_250 );_250 }_250 }_250_250 default:_250 return API.error(`Unknown action: ${action}`, request, 400);_250 }_250 } catch (error) {_250 console.error("Multipart upload error:", error);_250 return API.error("Multipart upload failed", request, 500);_250 }_250};_250_250// Uploads individual parts of a multipart upload_250export const PUT: APIRoute = async ({ request, locals }) => {_250 // Set the origin for the API_250 API.init(locals.runtime.env.ORIGIN);_250_250 // Handle CORS preflight requests_250 if (request.method === "OPTIONS") {_250 console.log("CORS preflight request from:", request.headers.get("Origin"));_250 return API.cors(request);_250 }_250_250 try {_250 // Check if bucket is available_250 const bucket = locals.runtime.env.CLOUD_FILES;_250 if (!bucket) {_250 return API.error("Cloud storage not configured", request, 500);_250 }_250_250 const url = new URL(request.url);_250 const action = url.searchParams.get("action");_250_250 if (action !== "upload-part") {_250 return API.error(`Unknown action: ${action}`, request, 400);_250 }_250_250 const uploadId = url.searchParams.get("uploadId");_250 const partNumberStr = url.searchParams.get("partNumber");_250 const key = url.searchParams.get("key");_250_250 if (!uploadId || !partNumberStr || !key) {_250 return API.error("Missing uploadId, partNumber, or key", request, 400);_250 }_250_250 const partNumber = parseInt(partNumberStr);_250 if (isNaN(partNumber) || partNumber < 1) {_250 return API.error("Invalid part number", request, 400);_250 }_250_250 if (!request.body) {_250 return API.error("Missing request body", request, 400);_250 }_250_250 try {_250 const multipartUpload = bucket.resumeMultipartUpload(key, uploadId);_250_250 // Convert request body to ArrayBuffer to get known length_250 const arrayBuffer = await request.arrayBuffer();_250 const uploadedPart = await multipartUpload.uploadPart(_250 partNumber,_250 arrayBuffer_250 );_250_250 return API.success(_250 {_250 success: true,_250 partNumber: uploadedPart.partNumber,_250 etag: uploadedPart.etag,_250 },_250 request_250 );_250 } catch (error: any) {_250 console.error("Failed to upload part:", error);_250 return API.error(error.message || "Failed to upload part", request, 400);_250 }_250 } catch (error) {_250 console.error("Upload part error:", error);_250 return API.error("Upload part failed", request, 500);_250 }_250};_250_250// Aborts a multipart upload_250export const DELETE: APIRoute = async ({ request, locals }) => {_250 // Set the origin for the API_250 API.init(locals.runtime.env.ORIGIN);_250_250 // Handle CORS preflight requests_250 if (request.method === "OPTIONS") {_250 console.log("CORS preflight request from:", request.headers.get("Origin"));_250 return API.cors(request);_250 }_250_250 try {_250 // Check if bucket is available_250 const bucket = locals.runtime.env.CLOUD_FILES;_250 if (!bucket) {_250 return API.error("Cloud storage not configured", request, 500);_250 }_250_250 const url = new URL(request.url);_250 const action = url.searchParams.get("action");_250_250 if (action !== "abort") {_250 return API.error(`Unknown action: ${action}`, request, 400);_250 }_250_250 const uploadId = url.searchParams.get("uploadId");_250 const key = url.searchParams.get("key");_250_250 if (!uploadId || !key) {_250 return API.error("Missing uploadId or key", request, 400);_250 }_250_250 try {_250 const multipartUpload = bucket.resumeMultipartUpload(key, uploadId);_250 await multipartUpload.abort();_250_250 return API.success(_250 {_250 success: true,_250 message: "Multipart upload aborted successfully",_250 },_250 request_250 );_250 } catch (error: any) {_250 console.error("Failed to abort multipart upload:", error);_250 return API.error(_250 error.message || "Failed to abort multipart upload",_250 request,_250 400_250 );_250 }_250 } catch (error) {_250 console.error("Abort multipart upload error:", error);_250 return API.error("Abort multipart upload failed", request, 500);_250 }_250};_250_250export const OPTIONS: APIRoute = async ({ request, locals }) => {_250 // Set the origin for the API_250 API.init(locals.runtime.env.ORIGIN);_250 return API.cors(request);_250};
Parse the action query parameter. The PUT endpoint only supports the upload-part action. If the action isn't upload-part, the endpoint returns an error.
Validate part upload parameters
_250import type { APIRoute } from "astro";_250import { API } from "../../utils/api";_250_250interface MultipartUploadRequest {_250 key: string;_250 contentType?: string;_250}_250_250interface CompleteMultipartRequest {_250 uploadId: string;_250 key: string;_250 parts: R2UploadedPart[];_250}_250_250// Creates and completes a new multipart upload session_250export const POST: APIRoute = async ({ request, locals }) => {_250 // Set the origin for the API_250 API.init(locals.runtime.env.ORIGIN);_250_250 // Handle CORS preflight requests_250 if (request.method === "OPTIONS") {_250 console.log("CORS preflight request from:", request.headers.get("Origin"));_250 return API.cors(request);_250 }_250_250 try {_250 // Check if bucket is available_250 const bucket = locals.runtime.env.CLOUD_FILES;_250 if (!bucket) {_250 return API.error("Cloud storage not configured", request, 500);_250 }_250_250 const url = new URL(request.url);_250 const action = url.searchParams.get("action");_250_250 if (!action) {_250 return API.error("Missing action parameter", request, 400);_250 }_250_250 switch (action) {_250 case "create": {_250 // Create a new multipart upload_250 const body: MultipartUploadRequest = await request.json();_250_250 if (!body.key) {_250 return API.error("Missing key parameter", request, 400);_250 }_250_250 try {_250 const multipartUpload = await bucket.createMultipartUpload(body.key, {_250 httpMetadata: body.contentType_250 ? {_250 contentType: body.contentType,_250 }_250 : undefined,_250 });_250_250 return API.success(_250 {_250 success: true,_250 key: multipartUpload.key,_250 uploadId: multipartUpload.uploadId,_250 },_250 request_250 );_250 } catch (error) {_250 console.error("Failed to create multipart upload:", error);_250 return API.error("Failed to create multipart upload", request, 500);_250 }_250 }_250_250 case "complete": {_250 // Complete a multipart upload_250 const body: CompleteMultipartRequest = await request.json();_250_250 if (!body.uploadId || !body.key || !body.parts) {_250 return API.error("Missing required parameters", request, 400);_250 }_250_250 try {_250 const multipartUpload = bucket.resumeMultipartUpload(_250 body.key,_250 body.uploadId_250 );_250_250 // Parts are already in R2UploadedPart format_250 const r2Parts = body.parts;_250_250 const object = await multipartUpload.complete(r2Parts);_250_250 return API.success(_250 {_250 success: true,_250 key: object.key,_250 etag: object.httpEtag,_250 size: object.size,_250 },_250 request_250 );_250 } catch (error: any) {_250 console.error("Failed to complete multipart upload:", error);_250 return API.error(_250 error.message || "Failed to complete multipart upload",_250 request,_250 400_250 );_250 }_250 }_250_250 default:_250 return API.error(`Unknown action: ${action}`, request, 400);_250 }_250 } catch (error) {_250 console.error("Multipart upload error:", error);_250 return API.error("Multipart upload failed", request, 500);_250 }_250};_250_250// Uploads individual parts of a multipart upload_250export const PUT: APIRoute = async ({ request, locals }) => {_250 // Set the origin for the API_250 API.init(locals.runtime.env.ORIGIN);_250_250 // Handle CORS preflight requests_250 if (request.method === "OPTIONS") {_250 console.log("CORS preflight request from:", request.headers.get("Origin"));_250 return API.cors(request);_250 }_250_250 try {_250 // Check if bucket is available_250 const bucket = locals.runtime.env.CLOUD_FILES;_250 if (!bucket) {_250 return API.error("Cloud storage not configured", request, 500);_250 }_250_250 const url = new URL(request.url);_250 const action = url.searchParams.get("action");_250_250 if (action !== "upload-part") {_250 return API.error(`Unknown action: ${action}`, request, 400);_250 }_250_250 const uploadId = url.searchParams.get("uploadId");_250 const partNumberStr = url.searchParams.get("partNumber");_250 const key = url.searchParams.get("key");_250_250 if (!uploadId || !partNumberStr || !key) {_250 return API.error("Missing uploadId, partNumber, or key", request, 400);_250 }_250_250 const partNumber = parseInt(partNumberStr);_250 if (isNaN(partNumber) || partNumber < 1) {_250 return API.error("Invalid part number", request, 400);_250 }_250_250 if (!request.body) {_250 return API.error("Missing request body", request, 400);_250 }_250_250 try {_250 const multipartUpload = bucket.resumeMultipartUpload(key, uploadId);_250_250 // Convert request body to ArrayBuffer to get known length_250 const arrayBuffer = await request.arrayBuffer();_250 const uploadedPart = await multipartUpload.uploadPart(_250 partNumber,_250 arrayBuffer_250 );_250_250 return API.success(_250 {_250 success: true,_250 partNumber: uploadedPart.partNumber,_250 etag: uploadedPart.etag,_250 },_250 request_250 );_250 } catch (error: any) {_250 console.error("Failed to upload part:", error);_250 return API.error(error.message || "Failed to upload part", request, 400);_250 }_250 } catch (error) {_250 console.error("Upload part error:", error);_250 return API.error("Upload part failed", request, 500);_250 }_250};_250_250// Aborts a multipart upload_250export const DELETE: APIRoute = async ({ request, locals }) => {_250 // Set the origin for the API_250 API.init(locals.runtime.env.ORIGIN);_250_250 // Handle CORS preflight requests_250 if (request.method === "OPTIONS") {_250 console.log("CORS preflight request from:", request.headers.get("Origin"));_250 return API.cors(request);_250 }_250_250 try {_250 // Check if bucket is available_250 const bucket = locals.runtime.env.CLOUD_FILES;_250 if (!bucket) {_250 return API.error("Cloud storage not configured", request, 500);_250 }_250_250 const url = new URL(request.url);_250 const action = url.searchParams.get("action");_250_250 if (action !== "abort") {_250 return API.error(`Unknown action: ${action}`, request, 400);_250 }_250_250 const uploadId = url.searchParams.get("uploadId");_250 const key = url.searchParams.get("key");_250_250 if (!uploadId || !key) {_250 return API.error("Missing uploadId or key", request, 400);_250 }_250_250 try {_250 const multipartUpload = bucket.resumeMultipartUpload(key, uploadId);_250 await multipartUpload.abort();_250_250 return API.success(_250 {_250 success: true,_250 message: "Multipart upload aborted successfully",_250 },_250 request_250 );_250 } catch (error: any) {_250 console.error("Failed to abort multipart upload:", error);_250 return API.error(_250 error.message || "Failed to abort multipart upload",_250 request,_250 400_250 );_250 }_250 } catch (error) {_250 console.error("Abort multipart upload error:", error);_250 return API.error("Abort multipart upload failed", request, 500);_250 }_250};_250_250export const OPTIONS: APIRoute = async ({ request, locals }) => {_250 // Set the origin for the API_250 API.init(locals.runtime.env.ORIGIN);_250 return API.cors(request);_250};
Extract and validate the required parameters for part uploads, including the uploadId, partNumber, and key. Each part must have a unique number starting from 1, and all parts must be associated with the same upload session.
The client will send the correct uploadId, partNumber, and key for each part.
Upload individual part
_250import type { APIRoute } from "astro";_250import { API } from "../../utils/api";_250_250interface MultipartUploadRequest {_250 key: string;_250 contentType?: string;_250}_250_250interface CompleteMultipartRequest {_250 uploadId: string;_250 key: string;_250 parts: R2UploadedPart[];_250}_250_250// Creates and completes a new multipart upload session_250export const POST: APIRoute = async ({ request, locals }) => {_250 // Set the origin for the API_250 API.init(locals.runtime.env.ORIGIN);_250_250 // Handle CORS preflight requests_250 if (request.method === "OPTIONS") {_250 console.log("CORS preflight request from:", request.headers.get("Origin"));_250 return API.cors(request);_250 }_250_250 try {_250 // Check if bucket is available_250 const bucket = locals.runtime.env.CLOUD_FILES;_250 if (!bucket) {_250 return API.error("Cloud storage not configured", request, 500);_250 }_250_250 const url = new URL(request.url);_250 const action = url.searchParams.get("action");_250_250 if (!action) {_250 return API.error("Missing action parameter", request, 400);_250 }_250_250 switch (action) {_250 case "create": {_250 // Create a new multipart upload_250 const body: MultipartUploadRequest = await request.json();_250_250 if (!body.key) {_250 return API.error("Missing key parameter", request, 400);_250 }_250_250 try {_250 const multipartUpload = await bucket.createMultipartUpload(body.key, {_250 httpMetadata: body.contentType_250 ? {_250 contentType: body.contentType,_250 }_250 : undefined,_250 });_250_250 return API.success(_250 {_250 success: true,_250 key: multipartUpload.key,_250 uploadId: multipartUpload.uploadId,_250 },_250 request_250 );_250 } catch (error) {_250 console.error("Failed to create multipart upload:", error);_250 return API.error("Failed to create multipart upload", request, 500);_250 }_250 }_250_250 case "complete": {_250 // Complete a multipart upload_250 const body: CompleteMultipartRequest = await request.json();_250_250 if (!body.uploadId || !body.key || !body.parts) {_250 return API.error("Missing required parameters", request, 400);_250 }_250_250 try {_250 const multipartUpload = bucket.resumeMultipartUpload(_250 body.key,_250 body.uploadId_250 );_250_250 // Parts are already in R2UploadedPart format_250 const r2Parts = body.parts;_250_250 const object = await multipartUpload.complete(r2Parts);_250_250 return API.success(_250 {_250 success: true,_250 key: object.key,_250 etag: object.httpEtag,_250 size: object.size,_250 },_250 request_250 );_250 } catch (error: any) {_250 console.error("Failed to complete multipart upload:", error);_250 return API.error(_250 error.message || "Failed to complete multipart upload",_250 request,_250 400_250 );_250 }_250 }_250_250 default:_250 return API.error(`Unknown action: ${action}`, request, 400);_250 }_250 } catch (error) {_250 console.error("Multipart upload error:", error);_250 return API.error("Multipart upload failed", request, 500);_250 }_250};_250_250// Uploads individual parts of a multipart upload_250export const PUT: APIRoute = async ({ request, locals }) => {_250 // Set the origin for the API_250 API.init(locals.runtime.env.ORIGIN);_250_250 // Handle CORS preflight requests_250 if (request.method === "OPTIONS") {_250 console.log("CORS preflight request from:", request.headers.get("Origin"));_250 return API.cors(request);_250 }_250_250 try {_250 // Check if bucket is available_250 const bucket = locals.runtime.env.CLOUD_FILES;_250 if (!bucket) {_250 return API.error("Cloud storage not configured", request, 500);_250 }_250_250 const url = new URL(request.url);_250 const action = url.searchParams.get("action");_250_250 if (action !== "upload-part") {_250 return API.error(`Unknown action: ${action}`, request, 400);_250 }_250_250 const uploadId = url.searchParams.get("uploadId");_250 const partNumberStr = url.searchParams.get("partNumber");_250 const key = url.searchParams.get("key");_250_250 if (!uploadId || !partNumberStr || !key) {_250 return API.error("Missing uploadId, partNumber, or key", request, 400);_250 }_250_250 const partNumber = parseInt(partNumberStr);_250 if (isNaN(partNumber) || partNumber < 1) {_250 return API.error("Invalid part number", request, 400);_250 }_250_250 if (!request.body) {_250 return API.error("Missing request body", request, 400);_250 }_250_250 try {_250 const multipartUpload = bucket.resumeMultipartUpload(key, uploadId);_250_250 // Convert request body to ArrayBuffer to get known length_250 const arrayBuffer = await request.arrayBuffer();_250 const uploadedPart = await multipartUpload.uploadPart(_250 partNumber,_250 arrayBuffer_250 );_250_250 return API.success(_250 {_250 success: true,_250 partNumber: uploadedPart.partNumber,_250 etag: uploadedPart.etag,_250 },_250 request_250 );_250 } catch (error: any) {_250 console.error("Failed to upload part:", error);_250 return API.error(error.message || "Failed to upload part", request, 400);_250 }_250 } catch (error) {_250 console.error("Upload part error:", error);_250 return API.error("Upload part failed", request, 500);_250 }_250};_250_250// Aborts a multipart upload_250export const DELETE: APIRoute = async ({ request, locals }) => {_250 // Set the origin for the API_250 API.init(locals.runtime.env.ORIGIN);_250_250 // Handle CORS preflight requests_250 if (request.method === "OPTIONS") {_250 console.log("CORS preflight request from:", request.headers.get("Origin"));_250 return API.cors(request);_250 }_250_250 try {_250 // Check if bucket is available_250 const bucket = locals.runtime.env.CLOUD_FILES;_250 if (!bucket) {_250 return API.error("Cloud storage not configured", request, 500);_250 }_250_250 const url = new URL(request.url);_250 const action = url.searchParams.get("action");_250_250 if (action !== "abort") {_250 return API.error(`Unknown action: ${action}`, request, 400);_250 }_250_250 const uploadId = url.searchParams.get("uploadId");_250 const key = url.searchParams.get("key");_250_250 if (!uploadId || !key) {_250 return API.error("Missing uploadId or key", request, 400);_250 }_250_250 try {_250 const multipartUpload = bucket.resumeMultipartUpload(key, uploadId);_250 await multipartUpload.abort();_250_250 return API.success(_250 {_250 success: true,_250 message: "Multipart upload aborted successfully",_250 },_250 request_250 );_250 } catch (error: any) {_250 console.error("Failed to abort multipart upload:", error);_250 return API.error(_250 error.message || "Failed to abort multipart upload",_250 request,_250 400_250 );_250 }_250 } catch (error) {_250 console.error("Abort multipart upload error:", error);_250 return API.error("Abort multipart upload failed", request, 500);_250 }_250};_250_250export const OPTIONS: APIRoute = async ({ request, locals }) => {_250 // Set the origin for the API_250 API.init(locals.runtime.env.ORIGIN);_250 return API.cors(request);_250};
Process a single file part upload. The request body contains the binary data for that specific chunk of the file.
What happens:
- Resumes the multipart upload using the
uploadId - Converts the request body to
ArrayBufferfor Object Storage compatibility - Uploads the part with its assigned
partNumber - Returns the
partNumberandetagfor tracking
Return the uploaded part
_250import type { APIRoute } from "astro";_250import { API } from "../../utils/api";_250_250interface MultipartUploadRequest {_250 key: string;_250 contentType?: string;_250}_250_250interface CompleteMultipartRequest {_250 uploadId: string;_250 key: string;_250 parts: R2UploadedPart[];_250}_250_250// Creates and completes a new multipart upload session_250export const POST: APIRoute = async ({ request, locals }) => {_250 // Set the origin for the API_250 API.init(locals.runtime.env.ORIGIN);_250_250 // Handle CORS preflight requests_250 if (request.method === "OPTIONS") {_250 console.log("CORS preflight request from:", request.headers.get("Origin"));_250 return API.cors(request);_250 }_250_250 try {_250 // Check if bucket is available_250 const bucket = locals.runtime.env.CLOUD_FILES;_250 if (!bucket) {_250 return API.error("Cloud storage not configured", request, 500);_250 }_250_250 const url = new URL(request.url);_250 const action = url.searchParams.get("action");_250_250 if (!action) {_250 return API.error("Missing action parameter", request, 400);_250 }_250_250 switch (action) {_250 case "create": {_250 // Create a new multipart upload_250 const body: MultipartUploadRequest = await request.json();_250_250 if (!body.key) {_250 return API.error("Missing key parameter", request, 400);_250 }_250_250 try {_250 const multipartUpload = await bucket.createMultipartUpload(body.key, {_250 httpMetadata: body.contentType_250 ? {_250 contentType: body.contentType,_250 }_250 : undefined,_250 });_250_250 return API.success(_250 {_250 success: true,_250 key: multipartUpload.key,_250 uploadId: multipartUpload.uploadId,_250 },_250 request_250 );_250 } catch (error) {_250 console.error("Failed to create multipart upload:", error);_250 return API.error("Failed to create multipart upload", request, 500);_250 }_250 }_250_250 case "complete": {_250 // Complete a multipart upload_250 const body: CompleteMultipartRequest = await request.json();_250_250 if (!body.uploadId || !body.key || !body.parts) {_250 return API.error("Missing required parameters", request, 400);_250 }_250_250 try {_250 const multipartUpload = bucket.resumeMultipartUpload(_250 body.key,_250 body.uploadId_250 );_250_250 // Parts are already in R2UploadedPart format_250 const r2Parts = body.parts;_250_250 const object = await multipartUpload.complete(r2Parts);_250_250 return API.success(_250 {_250 success: true,_250 key: object.key,_250 etag: object.httpEtag,_250 size: object.size,_250 },_250 request_250 );_250 } catch (error: any) {_250 console.error("Failed to complete multipart upload:", error);_250 return API.error(_250 error.message || "Failed to complete multipart upload",_250 request,_250 400_250 );_250 }_250 }_250_250 default:_250 return API.error(`Unknown action: ${action}`, request, 400);_250 }_250 } catch (error) {_250 console.error("Multipart upload error:", error);_250 return API.error("Multipart upload failed", request, 500);_250 }_250};_250_250// Uploads individual parts of a multipart upload_250export const PUT: APIRoute = async ({ request, locals }) => {_250 // Set the origin for the API_250 API.init(locals.runtime.env.ORIGIN);_250_250 // Handle CORS preflight requests_250 if (request.method === "OPTIONS") {_250 console.log("CORS preflight request from:", request.headers.get("Origin"));_250 return API.cors(request);_250 }_250_250 try {_250 // Check if bucket is available_250 const bucket = locals.runtime.env.CLOUD_FILES;_250 if (!bucket) {_250 return API.error("Cloud storage not configured", request, 500);_250 }_250_250 const url = new URL(request.url);_250 const action = url.searchParams.get("action");_250_250 if (action !== "upload-part") {_250 return API.error(`Unknown action: ${action}`, request, 400);_250 }_250_250 const uploadId = url.searchParams.get("uploadId");_250 const partNumberStr = url.searchParams.get("partNumber");_250 const key = url.searchParams.get("key");_250_250 if (!uploadId || !partNumberStr || !key) {_250 return API.error("Missing uploadId, partNumber, or key", request, 400);_250 }_250_250 const partNumber = parseInt(partNumberStr);_250 if (isNaN(partNumber) || partNumber < 1) {_250 return API.error("Invalid part number", request, 400);_250 }_250_250 if (!request.body) {_250 return API.error("Missing request body", request, 400);_250 }_250_250 try {_250 const multipartUpload = bucket.resumeMultipartUpload(key, uploadId);_250_250 // Convert request body to ArrayBuffer to get known length_250 const arrayBuffer = await request.arrayBuffer();_250 const uploadedPart = await multipartUpload.uploadPart(_250 partNumber,_250 arrayBuffer_250 );_250_250 return API.success(_250 {_250 success: true,_250 partNumber: uploadedPart.partNumber,_250 etag: uploadedPart.etag,_250 },_250 request_250 );_250 } catch (error: any) {_250 console.error("Failed to upload part:", error);_250 return API.error(error.message || "Failed to upload part", request, 400);_250 }_250 } catch (error) {_250 console.error("Upload part error:", error);_250 return API.error("Upload part failed", request, 500);_250 }_250};_250_250// Aborts a multipart upload_250export const DELETE: APIRoute = async ({ request, locals }) => {_250 // Set the origin for the API_250 API.init(locals.runtime.env.ORIGIN);_250_250 // Handle CORS preflight requests_250 if (request.method === "OPTIONS") {_250 console.log("CORS preflight request from:", request.headers.get("Origin"));_250 return API.cors(request);_250 }_250_250 try {_250 // Check if bucket is available_250 const bucket = locals.runtime.env.CLOUD_FILES;_250 if (!bucket) {_250 return API.error("Cloud storage not configured", request, 500);_250 }_250_250 const url = new URL(request.url);_250 const action = url.searchParams.get("action");_250_250 if (action !== "abort") {_250 return API.error(`Unknown action: ${action}`, request, 400);_250 }_250_250 const uploadId = url.searchParams.get("uploadId");_250 const key = url.searchParams.get("key");_250_250 if (!uploadId || !key) {_250 return API.error("Missing uploadId or key", request, 400);_250 }_250_250 try {_250 const multipartUpload = bucket.resumeMultipartUpload(key, uploadId);_250 await multipartUpload.abort();_250_250 return API.success(_250 {_250 success: true,_250 message: "Multipart upload aborted successfully",_250 },_250 request_250 );_250 } catch (error: any) {_250 console.error("Failed to abort multipart upload:", error);_250 return API.error(_250 error.message || "Failed to abort multipart upload",_250 request,_250 400_250 );_250 }_250 } catch (error) {_250 console.error("Abort multipart upload error:", error);_250 return API.error("Abort multipart upload failed", request, 500);_250 }_250};_250_250export const OPTIONS: APIRoute = async ({ request, locals }) => {_250 // Set the origin for the API_250 API.init(locals.runtime.env.ORIGIN);_250 return API.cors(request);_250};
After successfully uploading a part, return a response containing:
success: true- Confirms the operation completed successfullypartNumber- The sequential number of this partetag- The entity tag for this specific part, used for integrity verification
The client should store both the partNumber and etag for each uploaded part. These values are required when completing the multipart upload to ensure all parts are included and haven't been corrupted during transfer.
Create the PUT Endpoint
The PUT endpoint handles uploading individual file parts. Each part is uploaded as a separate request, allowing browsers to upload multiple parts concurrently for better performance.
Include the locals parameter, and set up CORS preflight requests.
Access your Object Storage bucket
Retrieve the CLOUD_FILES binding that provides access to your Object Storage bucket. This binding contains all the multipart upload methods you'll need throughout the upload process.
Get Action Parameter
Parse the action query parameter. The PUT endpoint only supports the upload-part action. If the action isn't upload-part, the endpoint returns an error.
Validate part upload parameters
Extract and validate the required parameters for part uploads, including the uploadId, partNumber, and key. Each part must have a unique number starting from 1, and all parts must be associated with the same upload session.
The client will send the correct uploadId, partNumber, and key for each part.
Upload individual part
Process a single file part upload. The request body contains the binary data for that specific chunk of the file.
What happens:
- Resumes the multipart upload using the
uploadId - Converts the request body to
ArrayBufferfor Object Storage compatibility - Uploads the part with its assigned
partNumber - Returns the
partNumberandetagfor tracking
Return the uploaded part
After successfully uploading a part, return a response containing:
success: true- Confirms the operation completed successfullypartNumber- The sequential number of this partetag- The entity tag for this specific part, used for integrity verification
The client should store both the partNumber and etag for each uploaded part. These values are required when completing the multipart upload to ensure all parts are included and haven't been corrupted during transfer.
_250import type { APIRoute } from "astro";_250import { API } from "../../utils/api";_250_250interface MultipartUploadRequest {_250 key: string;_250 contentType?: string;_250}_250_250interface CompleteMultipartRequest {_250 uploadId: string;_250 key: string;_250 parts: R2UploadedPart[];_250}_250_250// Creates and completes a new multipart upload session_250export const POST: APIRoute = async ({ request, locals }) => {_250 // Set the origin for the API_250 API.init(locals.runtime.env.ORIGIN);_250_250 // Handle CORS preflight requests_250 if (request.method === "OPTIONS") {_250 console.log("CORS preflight request from:", request.headers.get("Origin"));_250 return API.cors(request);_250 }_250_250 try {_250 // Check if bucket is available_250 const bucket = locals.runtime.env.CLOUD_FILES;_250 if (!bucket) {_250 return API.error("Cloud storage not configured", request, 500);_250 }_250_250 const url = new URL(request.url);_250 const action = url.searchParams.get("action");_250_250 if (!action) {_250 return API.error("Missing action parameter", request, 400);_250 }_250_250 switch (action) {_250 case "create": {_250 // Create a new multipart upload_250 const body: MultipartUploadRequest = await request.json();_250_250 if (!body.key) {_250 return API.error("Missing key parameter", request, 400);_250 }_250_250 try {_250 const multipartUpload = await bucket.createMultipartUpload(body.key, {_250 httpMetadata: body.contentType_250 ? {_250 contentType: body.contentType,_250 }_250 : undefined,_250 });_250_250 return API.success(_250 {_250 success: true,_250 key: multipartUpload.key,_250 uploadId: multipartUpload.uploadId,_250 },_250 request_250 );_250 } catch (error) {_250 console.error("Failed to create multipart upload:", error);_250 return API.error("Failed to create multipart upload", request, 500);_250 }_250 }_250_250 case "complete": {_250 // Complete a multipart upload_250 const body: CompleteMultipartRequest = await request.json();_250_250 if (!body.uploadId || !body.key || !body.parts) {_250 return API.error("Missing required parameters", request, 400);_250 }_250_250 try {_250 const multipartUpload = bucket.resumeMultipartUpload(_250 body.key,_250 body.uploadId_250 );_250_250 // Parts are already in R2UploadedPart format_250 const r2Parts = body.parts;_250_250 const object = await multipartUpload.complete(r2Parts);_250_250 return API.success(_250 {_250 success: true,_250 key: object.key,_250 etag: object.httpEtag,_250 size: object.size,_250 },_250 request_250 );_250 } catch (error: any) {_250 console.error("Failed to complete multipart upload:", error);_250 return API.error(_250 error.message || "Failed to complete multipart upload",_250 request,_250 400_250 );_250 }_250 }_250_250 default:_250 return API.error(`Unknown action: ${action}`, request, 400);_250 }_250 } catch (error) {_250 console.error("Multipart upload error:", error);_250 return API.error("Multipart upload failed", request, 500);_250 }_250};_250_250// Uploads individual parts of a multipart upload_250export const PUT: APIRoute = async ({ request, locals }) => {_250 // Set the origin for the API_250 API.init(locals.runtime.env.ORIGIN);_250_250 // Handle CORS preflight requests_250 if (request.method === "OPTIONS") {_250 console.log("CORS preflight request from:", request.headers.get("Origin"));_250 return API.cors(request);_250 }_250_250 try {_250 // Check if bucket is available_250 const bucket = locals.runtime.env.CLOUD_FILES;_250 if (!bucket) {_250 return API.error("Cloud storage not configured", request, 500);_250 }_250_250 const url = new URL(request.url);_250 const action = url.searchParams.get("action");_250_250 if (action !== "upload-part") {_250 return API.error(`Unknown action: ${action}`, request, 400);_250 }_250_250 const uploadId = url.searchParams.get("uploadId");_250 const partNumberStr = url.searchParams.get("partNumber");_250 const key = url.searchParams.get("key");_250_250 if (!uploadId || !partNumberStr || !key) {_250 return API.error("Missing uploadId, partNumber, or key", request, 400);_250 }_250_250 const partNumber = parseInt(partNumberStr);_250 if (isNaN(partNumber) || partNumber < 1) {_250 return API.error("Invalid part number", request, 400);_250 }_250_250 if (!request.body) {_250 return API.error("Missing request body", request, 400);_250 }_250_250 try {_250 const multipartUpload = bucket.resumeMultipartUpload(key, uploadId);_250_250 // Convert request body to ArrayBuffer to get known length_250 const arrayBuffer = await request.arrayBuffer();_250 const uploadedPart = await multipartUpload.uploadPart(_250 partNumber,_250 arrayBuffer_250 );_250_250 return API.success(_250 {_250 success: true,_250 partNumber: uploadedPart.partNumber,_250 etag: uploadedPart.etag,_250 },_250 request_250 );_250 } catch (error: any) {_250 console.error("Failed to upload part:", error);_250 return API.error(error.message || "Failed to upload part", request, 400);_250 }_250 } catch (error) {_250 console.error("Upload part error:", error);_250 return API.error("Upload part failed", request, 500);_250 }_250};_250_250// Aborts a multipart upload_250export const DELETE: APIRoute = async ({ request, locals }) => {_250 // Set the origin for the API_250 API.init(locals.runtime.env.ORIGIN);_250_250 // Handle CORS preflight requests_250 if (request.method === "OPTIONS") {_250 console.log("CORS preflight request from:", request.headers.get("Origin"));_250 return API.cors(request);_250 }_250_250 try {_250 // Check if bucket is available_250 const bucket = locals.runtime.env.CLOUD_FILES;_250 if (!bucket) {_250 return API.error("Cloud storage not configured", request, 500);_250 }_250_250 const url = new URL(request.url);_250 const action = url.searchParams.get("action");_250_250 if (action !== "abort") {_250 return API.error(`Unknown action: ${action}`, request, 400);_250 }_250_250 const uploadId = url.searchParams.get("uploadId");_250 const key = url.searchParams.get("key");_250_250 if (!uploadId || !key) {_250 return API.error("Missing uploadId or key", request, 400);_250 }_250_250 try {_250 const multipartUpload = bucket.resumeMultipartUpload(key, uploadId);_250 await multipartUpload.abort();_250_250 return API.success(_250 {_250 success: true,_250 message: "Multipart upload aborted successfully",_250 },_250 request_250 );_250 } catch (error: any) {_250 console.error("Failed to abort multipart upload:", error);_250 return API.error(_250 error.message || "Failed to abort multipart upload",_250 request,_250 400_250 );_250 }_250 } catch (error) {_250 console.error("Abort multipart upload error:", error);_250 return API.error("Abort multipart upload failed", request, 500);_250 }_250};_250_250export const OPTIONS: APIRoute = async ({ request, locals }) => {_250 // Set the origin for the API_250 API.init(locals.runtime.env.ORIGIN);_250 return API.cors(request);_250};