export default defineEventHandler(async (event) => { let data: any = {} const body = await readBody(event) const config = useRuntimeConfig() // body: { sourceImageUrl, sourceImageHash, sourceImageExt, sourceName, sourceMime, // targetStrapiId (numeric), targetStrapiDocumentId, targetProductId, targetProductValue } try { // 1. Download the original image from Strapi const strapiBase = config.api.strapiupload || 'http://127.0.0.1:1337' let imageUrl = '' let imageBuffer: ArrayBuffer | null = null // Strategy 1: Use the image's url field (most reliable, e.g. /uploads/filename.jpg) if (body.sourceImageUrl) { try { imageUrl = strapiBase + body.sourceImageUrl const res = await fetch(imageUrl) if (res.ok) imageBuffer = await res.arrayBuffer() } catch (e: any) { console.log(`[copy-image] Strategy 1 failed (${imageUrl}): ${e.message}`) } } // Strategy 2: files-api with hash+ext if (!imageBuffer && body.sourceImageHash) { try { imageUrl = strapiBase + '/files-api/' + body.sourceImageHash + body.sourceImageExt const res = await fetch(imageUrl) if (res.ok) imageBuffer = await res.arrayBuffer() } catch (e: any) { console.log(`[copy-image] Strategy 2 failed (${imageUrl}): ${e.message}`) } } // Strategy 3: Strapi API base with url field if (!imageBuffer && body.sourceImageUrl) { try { imageUrl = config.api.strapi?.replace(/\/api$/, '') + body.sourceImageUrl const res = await fetch(imageUrl) if (res.ok) imageBuffer = await res.arrayBuffer() } catch (e: any) { console.log(`[copy-image] Strategy 3 failed (${imageUrl}): ${e.message}`) } } if (!imageBuffer) { return { status: 404, message: `Failed to download source image from all URL strategies. Last tried: ${imageUrl}` } } console.log(`[copy-image] Downloaded image: ${imageBuffer.byteLength} bytes from ${imageUrl}`) // 2. Upload to Strapi with linking fields (matching Laravel's curlUpload pattern) // refId must be the numeric Strapi product ID (not documentId) const strapiApiBase = 'http://127.0.0.1:1337/api' const strapiAuth = 'Bearer ' + config.api.strapitoken const blob = new Blob([imageBuffer], { type: body.sourceMime || 'image/jpeg' }) const fileName = (body.targetStrapiId || 'img') + '_image' + (body.sourceImageExt || '.jpg') const formData = new FormData() formData.append('files', blob, fileName) formData.append('ref', 'api::m-product.m-product') formData.append('refId', String(body.targetStrapiId)) formData.append('field', 'image') formData.append('fileInfo', JSON.stringify({ caption: String(body.targetProductId), alternativeText: String(body.targetProductValue || '') })) const uploadResponse = await fetch(strapiApiBase + '/upload', { method: 'POST', headers: { Authorization: strapiAuth }, body: formData }) if (!uploadResponse.ok) { const errorText = await uploadResponse.text() console.log(`[copy-image] Upload failed (${uploadResponse.status}): ${errorText}`) return { status: uploadResponse.status, message: `Strapi upload failed: ${uploadResponse.statusText} - ${errorText}` } } const uploadRes: any = await uploadResponse.json() const uploadedFile = Array.isArray(uploadRes) ? uploadRes[0] : uploadRes const uploadedFileId = uploadedFile?.id if (!uploadedFileId) { return { status: 500, message: 'Upload succeeded but no file ID returned' } } // 3. Set as Main_Image on the Strapi product (matching Laravel's Step 4) // PUT /m-products/{strapi_product_id} with { data: { Main_Image: fileId } } if (body.targetStrapiId && body.setAsMain) { try { await fetch(strapiApiBase + '/m-products/' + body.targetStrapiId, { method: 'PUT', headers: { Authorization: strapiAuth, 'Content-Type': 'application/json' }, body: JSON.stringify({ data: { Main_Image: uploadedFileId } }) }) } catch (e: any) { console.log(`[copy-image] Set Main_Image failed: ${e.message}`) } } data = { status: 200, message: '', imageId: uploadedFileId } } catch (error: any) { console.log(`[copy-image] Error: ${error.message}`) data = { status: error.status || error.statusCode || 500, message: error.detail || error.message || error.statusMessage || 'Image copy failed' } } return data })