feat: API route POST /api/sync/execute (NDJSON streaming)
This commit is contained in:
@@ -0,0 +1,113 @@
|
||||
import { NextRequest, NextResponse } from 'next/server'
|
||||
import { getServerSession } from 'next-auth'
|
||||
import { authOptions } from '@/lib/auth'
|
||||
import { prisma } from '@/lib/prisma'
|
||||
import {
|
||||
createShopifyProduct,
|
||||
updateShopifyProduct,
|
||||
deactivateShopifyProduct,
|
||||
getFirstVariantId,
|
||||
} from '@/lib/shopifySync'
|
||||
import type { SyncChange, SyncLogEntry, SyncStreamEvent } from '@/types/sync'
|
||||
|
||||
export async function POST(req: NextRequest) {
|
||||
const session = await getServerSession(authOptions)
|
||||
if (!session?.user) {
|
||||
return NextResponse.json({ error: 'Non authentifié' }, { status: 401 })
|
||||
}
|
||||
|
||||
let changes: SyncChange[]
|
||||
try {
|
||||
const body = await req.json()
|
||||
changes = body.changes
|
||||
} catch {
|
||||
return NextResponse.json({ error: 'Corps JSON invalide' }, { status: 400 })
|
||||
}
|
||||
|
||||
if (!Array.isArray(changes) || changes.length === 0) {
|
||||
return NextResponse.json({ error: 'Aucun changement à appliquer' }, { status: 400 })
|
||||
}
|
||||
|
||||
const userId = (session.user as { id: string }).id
|
||||
const encoder = new TextEncoder()
|
||||
|
||||
const stream = new ReadableStream({
|
||||
async start(controller) {
|
||||
const send = (event: SyncStreamEvent) => {
|
||||
controller.enqueue(encoder.encode(JSON.stringify(event) + '\n'))
|
||||
}
|
||||
|
||||
const log: SyncLogEntry[] = []
|
||||
let created = 0, updated = 0, deactivated = 0, errors = 0
|
||||
const total = changes.filter((c) => c.type !== 'unchanged').length
|
||||
let current = 0
|
||||
|
||||
for (const change of changes) {
|
||||
if (change.type === 'unchanged') continue
|
||||
current++
|
||||
|
||||
try {
|
||||
if (change.type === 'create') {
|
||||
await createShopifyProduct(change.sheetProduct!)
|
||||
created++
|
||||
const msg = `✓ ${change.ref} créé`
|
||||
log.push({ ref: change.ref, action: 'create', status: 'success', message: msg })
|
||||
send({ type: 'progress', current, total, message: msg })
|
||||
|
||||
} else if (change.type === 'update') {
|
||||
const variantId = await getFirstVariantId(change.shopifyProduct!.shopifyId)
|
||||
await updateShopifyProduct(
|
||||
change.shopifyProduct!.shopifyId,
|
||||
change.sheetProduct!,
|
||||
variantId,
|
||||
)
|
||||
updated++
|
||||
const fields = change.changedFields?.map((f) => f.field).join(', ') ?? ''
|
||||
const msg = `✓ ${change.ref} mis à jour (${fields})`
|
||||
log.push({ ref: change.ref, action: 'update', status: 'success', message: msg })
|
||||
send({ type: 'progress', current, total, message: msg })
|
||||
|
||||
} else if (change.type === 'deactivate') {
|
||||
await deactivateShopifyProduct(change.shopifyProduct!.shopifyId)
|
||||
deactivated++
|
||||
const msg = `✓ ${change.ref} désactivé`
|
||||
log.push({ ref: change.ref, action: 'deactivate', status: 'success', message: msg })
|
||||
send({ type: 'progress', current, total, message: msg })
|
||||
}
|
||||
} catch (err) {
|
||||
errors++
|
||||
const msg = `✗ ${change.ref} : ${(err as Error).message}`
|
||||
log.push({ ref: change.ref, action: change.type as SyncLogEntry['action'], status: 'error', message: msg })
|
||||
send({ type: 'progress', current, total, message: msg })
|
||||
}
|
||||
}
|
||||
|
||||
const syncStatus = errors === 0 ? 'success' : errors === total ? 'error' : 'partial'
|
||||
try {
|
||||
await prisma.syncRun.create({
|
||||
data: {
|
||||
userId,
|
||||
status: syncStatus,
|
||||
created,
|
||||
updated,
|
||||
deactivated,
|
||||
errors,
|
||||
log: JSON.stringify(log),
|
||||
},
|
||||
})
|
||||
} catch (dbErr) {
|
||||
console.error('Erreur sauvegarde SyncRun:', dbErr)
|
||||
}
|
||||
|
||||
send({
|
||||
type: 'done',
|
||||
summary: { created, updated, deactivated, errors, status: syncStatus },
|
||||
})
|
||||
controller.close()
|
||||
},
|
||||
})
|
||||
|
||||
return new Response(stream, {
|
||||
headers: { 'Content-Type': 'application/x-ndjson; charset=utf-8' },
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user