84 lines
2.6 KiB
TypeScript
84 lines
2.6 KiB
TypeScript
const API_VERSION = '2024-01'
|
|
|
|
function getConfig() {
|
|
const domain = process.env.SHOPIFY_STORE_DOMAIN
|
|
const token = process.env.SHOPIFY_ADMIN_API_TOKEN
|
|
if (!domain || !token) {
|
|
throw new Error('SHOPIFY_STORE_DOMAIN et SHOPIFY_ADMIN_API_TOKEN requis')
|
|
}
|
|
return {
|
|
baseUrl: `https://${domain}/admin/api/${API_VERSION}`,
|
|
headers: {
|
|
'X-Shopify-Access-Token': token,
|
|
'Content-Type': 'application/json',
|
|
},
|
|
}
|
|
}
|
|
|
|
export type ShopifyProductResult =
|
|
| { found: false }
|
|
| { found: true; shopifyId: string; title: string }
|
|
|
|
/**
|
|
* Recherche un produit Shopify par sa référence.
|
|
* Tente d'abord par handle (ex: "ref-1042"), puis par titre exact.
|
|
*/
|
|
export async function searchProductByRef(ref: string): Promise<ShopifyProductResult> {
|
|
const { baseUrl, headers } = getConfig()
|
|
|
|
// Normalise la référence en handle Shopify (minuscules, tirets)
|
|
const handle = ref.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '')
|
|
|
|
const tryFetch = async (params: string) => {
|
|
const res = await fetch(`${baseUrl}/products.json?${params}&fields=id,title,handle&limit=1`, { headers })
|
|
if (!res.ok) throw new Error(`Shopify API error: ${res.status}`)
|
|
const data = await res.json()
|
|
return (data.products ?? []) as Array<{ id: number; title: string; handle: string }>
|
|
}
|
|
|
|
let products = await tryFetch(`handle=${encodeURIComponent(handle)}`)
|
|
|
|
if (products.length === 0) {
|
|
products = await tryFetch(`title=${encodeURIComponent(ref)}`)
|
|
}
|
|
|
|
if (products.length === 0) return { found: false }
|
|
|
|
return {
|
|
found: true,
|
|
shopifyId: String(products[0].id),
|
|
title: products[0].title,
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Upload une image (base64) vers un produit Shopify via l'API REST.
|
|
* @param shopifyProductId — ID numérique du produit (string)
|
|
* @param imageBase64 — contenu JPEG encodé en base64 (sans le préfixe data:)
|
|
* @param filename — nom de fichier avec extension (ex: "REF-1042.jpg")
|
|
*/
|
|
export async function uploadProductImage(
|
|
shopifyProductId: string,
|
|
imageBase64: string,
|
|
filename: string,
|
|
): Promise<{ url: string }> {
|
|
const { baseUrl, headers } = getConfig()
|
|
|
|
const res = await fetch(`${baseUrl}/products/${shopifyProductId}/images.json`, {
|
|
method: 'POST',
|
|
headers,
|
|
body: JSON.stringify({ image: { attachment: imageBase64, filename } }),
|
|
})
|
|
|
|
if (!res.ok) {
|
|
const body = await res.text()
|
|
throw new Error(`Shopify upload error: ${res.status} — ${body}`)
|
|
}
|
|
|
|
const data = await res.json()
|
|
if (!data.image?.src) {
|
|
throw new Error('Shopify response invalide : champ image.src manquant')
|
|
}
|
|
return { url: data.image.src as string }
|
|
}
|