fix(publications): restablecer publicaciones automaticas en app y catalogo whatsapp, corregir webhooks y sincronizacion
This commit is contained in:
parent
2aa0b8560d
commit
ff95bbd98a
@ -4,20 +4,26 @@ import { generateWhatsAppCatalogCsv } from '@/lib/whatsapp-catalog';
|
||||
import { getProductsFromAppwrite } from '@/lib/server-appwrite';
|
||||
|
||||
export const dynamic = 'force-dynamic';
|
||||
export const revalidate = 0;
|
||||
|
||||
export async function GET() {
|
||||
try {
|
||||
let products = dataService.getProducts();
|
||||
if (products.length === 0) {
|
||||
try {
|
||||
const appwriteProducts = await getProductsFromAppwrite();
|
||||
if (appwriteProducts && appwriteProducts.length > 0) {
|
||||
appwriteProducts.forEach((p) => dataService.addProduct(p));
|
||||
products = dataService.getProducts();
|
||||
|
||||
// Sincronizar siempre con Appwrite para garantizar catálogo en tiempo real
|
||||
try {
|
||||
const appwriteProducts = await getProductsFromAppwrite();
|
||||
if (appwriteProducts && appwriteProducts.length > 0) {
|
||||
const existingIds = new Set(products.map((p) => p.id));
|
||||
for (const ap of appwriteProducts) {
|
||||
if (!existingIds.has(ap.id)) {
|
||||
dataService.addProduct(ap);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('Error sincronizando productos con Appwrite para CSV Feed:', e);
|
||||
products = dataService.getProducts();
|
||||
}
|
||||
} catch (e: any) {
|
||||
console.warn('Error sincronizando productos con Appwrite para CSV Feed:', e.message);
|
||||
}
|
||||
|
||||
const csv = generateWhatsAppCatalogCsv(products);
|
||||
@ -27,7 +33,7 @@ export async function GET() {
|
||||
headers: {
|
||||
'Content-Type': 'text/csv; charset=utf-8',
|
||||
'Content-Disposition': 'inline; filename="dripzone_whatsapp_catalog.csv"',
|
||||
'Cache-Control': 'public, max-age=300, stale-while-revalidate=600',
|
||||
'Cache-Control': 'public, max-age=60, s-maxage=60, stale-while-revalidate=120',
|
||||
},
|
||||
});
|
||||
} catch (error: any) {
|
||||
|
||||
@ -4,20 +4,26 @@ import { generateWhatsAppCatalogXml } from '@/lib/whatsapp-catalog';
|
||||
import { getProductsFromAppwrite } from '@/lib/server-appwrite';
|
||||
|
||||
export const dynamic = 'force-dynamic';
|
||||
export const revalidate = 0;
|
||||
|
||||
export async function GET() {
|
||||
try {
|
||||
let products = dataService.getProducts();
|
||||
if (products.length === 0) {
|
||||
try {
|
||||
const appwriteProducts = await getProductsFromAppwrite();
|
||||
if (appwriteProducts && appwriteProducts.length > 0) {
|
||||
appwriteProducts.forEach((p) => dataService.addProduct(p));
|
||||
products = dataService.getProducts();
|
||||
|
||||
// Sincronizar siempre con Appwrite para garantizar catálogo en tiempo real
|
||||
try {
|
||||
const appwriteProducts = await getProductsFromAppwrite();
|
||||
if (appwriteProducts && appwriteProducts.length > 0) {
|
||||
const existingIds = new Set(products.map((p) => p.id));
|
||||
for (const ap of appwriteProducts) {
|
||||
if (!existingIds.has(ap.id)) {
|
||||
dataService.addProduct(ap);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('Error sincronizando productos con Appwrite para XML Feed:', e);
|
||||
products = dataService.getProducts();
|
||||
}
|
||||
} catch (e: any) {
|
||||
console.warn('Error sincronizando productos con Appwrite para XML Feed:', e.message);
|
||||
}
|
||||
|
||||
const settings = dataService.getSettings();
|
||||
@ -27,7 +33,7 @@ export async function GET() {
|
||||
status: 200,
|
||||
headers: {
|
||||
'Content-Type': 'application/xml; charset=utf-8',
|
||||
'Cache-Control': 'public, max-age=300, stale-while-revalidate=600',
|
||||
'Cache-Control': 'public, max-age=60, s-maxage=60, stale-while-revalidate=120',
|
||||
},
|
||||
});
|
||||
} catch (error: any) {
|
||||
|
||||
@ -4,7 +4,14 @@ import { parseSupplierMessage, detectCategory } from '@/lib/gemini-parser';
|
||||
import { sanitizePublicationTitle } from '@/lib/sanitizer';
|
||||
import { generateAttractiveProductCopy } from '@/lib/attractive-copy';
|
||||
import { getProductSocialProof } from '@/lib/social-proof';
|
||||
import { notifyNewProductPublished, sendWhatsAppMessage, sendWhatsAppMedia } from '@/lib/evolution-api';
|
||||
import {
|
||||
notifyNewProductPublished,
|
||||
sendWhatsAppMessage,
|
||||
sendWhatsAppMedia,
|
||||
getWhatsAppGroupSubject,
|
||||
getBase64FromMediaMessage,
|
||||
fetchRecentMediaFromSameChat,
|
||||
} from '@/lib/evolution-api';
|
||||
import {
|
||||
getMonitoredGroupsFromAppwrite,
|
||||
saveProductToAppwrite,
|
||||
@ -220,27 +227,39 @@ export async function POST(request: Request) {
|
||||
// =========================================================================
|
||||
// CASO B: GRUPOS MAYORISTAS DE PROVEEDORES (Publicación Automática Incondicional)
|
||||
// =========================================================================
|
||||
const groupSubject =
|
||||
data.groupInfo?.subject ||
|
||||
data.chatName ||
|
||||
data.pushName ||
|
||||
'Grupo Mayorista';
|
||||
// Resolver el nombre del grupo de forma precisa usando Evolution API si no viene en el payload
|
||||
let groupSubject = data.groupInfo?.subject || data.chatName || '';
|
||||
if (!groupSubject || groupSubject.length < 3 || groupSubject === data.pushName) {
|
||||
try {
|
||||
const resolved = await getWhatsAppGroupSubject(remoteJid);
|
||||
if (resolved) {
|
||||
groupSubject = resolved;
|
||||
} else {
|
||||
groupSubject = data.pushName || 'Grupo Mayorista';
|
||||
}
|
||||
} catch (_) {
|
||||
groupSubject = data.pushName || 'Grupo Mayorista';
|
||||
}
|
||||
}
|
||||
|
||||
// 1. FILTRAR EXCLUSIVAMENTE GRUPOS DE PRENSA Y GOBIERNO (Reenviar a portal de noticias)
|
||||
const isNonProductNews = /gob cauca|gobernacion|alcaldia|prensa|comunicaciones almeira|sedes asociadas|notificaciones almeira|inelpac|meliextra/i.test(
|
||||
// 1. FILTRAR EXCLUSIVAMENTE GRUPOS DE PRENSA Y GOBIERNO (Reenviar a portal de noticias Almeira)
|
||||
const isNonProductNews = /gob cauca|gobernacion|alcaldia|prensa|medios|noticias|comunicaciones|sedes asociadas|notificaciones almeira|inelpac|meliextra|almeira producciones|publicaciones almeira|quilichao en medios/i.test(
|
||||
groupSubject
|
||||
);
|
||||
|
||||
if (isNonProductNews) {
|
||||
// Reenviar asíncronamente al webhook del portal de noticias Almeira
|
||||
fetch('https://news.almeira.com.co/api/webhooks/whatsapp', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(payload),
|
||||
signal: AbortSignal.timeout(10000),
|
||||
}).catch(() => {});
|
||||
try {
|
||||
await fetch('https://news.almeira.com.co/api/webhooks/whatsapp', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(payload),
|
||||
signal: AbortSignal.timeout(15000),
|
||||
});
|
||||
console.log(`[DripZone Webhook] Chat de prensa reenviado a news.almeira.com.co: "${groupSubject}" (${remoteJid})`);
|
||||
} catch (newsErr: any) {
|
||||
console.warn('[DripZone Webhook] Error reenviando a portal de noticias:', newsErr?.message);
|
||||
}
|
||||
|
||||
console.log(`[DripZone Webhook] Chat de prensa redirigido a news: "${groupSubject}" (${remoteJid})`);
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
ignored: 'Grupo de noticias institucionales reenviado a portal de prensa',
|
||||
@ -249,6 +268,17 @@ export async function POST(request: Request) {
|
||||
});
|
||||
}
|
||||
|
||||
// 1.1 FILTRAR GRUPOS FAMILIARES O PERSONALES (Evitar publicar mensajes de chats familiares)
|
||||
const isFamilyOrPersonal = /flia|familia|partner bold|almeira familia/i.test(groupSubject);
|
||||
if (isFamilyOrPersonal) {
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
ignored: 'Chat familiar/personal omitido de publicaciones comerciales',
|
||||
chat: groupSubject,
|
||||
remoteJid,
|
||||
});
|
||||
}
|
||||
|
||||
// Auto-registrar grupo como monitoreado y activo si no existía previamente
|
||||
try {
|
||||
const currentGroups = dataService.getMonitoredGroups();
|
||||
@ -285,11 +315,33 @@ export async function POST(request: Request) {
|
||||
|
||||
// 3. EXTRACCIÓN MULTIMEDIA (IMAGEN HD Y THUMBNAIL)
|
||||
let imageBase64: string | undefined = data.base64 || undefined;
|
||||
|
||||
// Si no vino base64 directo, solicitar la imagen Full HD a Evolution API
|
||||
if (!imageBase64 && (data.message?.imageMessage || data.message?.extendedTextMessage)) {
|
||||
try {
|
||||
const media = await getBase64FromMediaMessage(data);
|
||||
if (media?.base64) {
|
||||
imageBase64 = media.base64.startsWith('data:') ? media.base64 : `data:${media.mimetype || 'image/jpeg'};base64,${media.base64}`;
|
||||
}
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
// Si aún no hay base64 pero viene jpegThumbnail, usarlo como fallback
|
||||
if (!imageBase64 && data.message?.imageMessage?.jpegThumbnail) {
|
||||
const thumb = data.message.imageMessage.jpegThumbnail;
|
||||
imageBase64 = thumb.startsWith('data:') ? thumb : `data:image/jpeg;base64,${thumb}`;
|
||||
}
|
||||
|
||||
// Si aún no hay imagen (ej. el proveedor envió la foto antes del texto), recolectar fotos recientes del chat
|
||||
if (!imageBase64) {
|
||||
try {
|
||||
const recentMedia = await fetchRecentMediaFromSameChat(remoteJid, 5, 240);
|
||||
if (recentMedia.length > 0 && recentMedia[0].base64) {
|
||||
imageBase64 = `data:${recentMedia[0].mimeType || 'image/jpeg'};base64,${recentMedia[0].base64}`;
|
||||
}
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
// Guardar imagen en disco local inmediatamente para disponibilidad instantánea
|
||||
if (imageBase64) {
|
||||
try {
|
||||
|
||||
@ -3,8 +3,8 @@ import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
const EVOLUTION_API_URL = process.env.EVOLUTION_API_URL || 'https://evolution.almeira.com.co';
|
||||
const EVOLUTION_API_KEY = process.env.EVOLUTION_API_KEY || 'EE49029EEB85-4568-8F81-C9FDFC6E2943';
|
||||
const EVOLUTION_INSTANCE = process.env.EVOLUTION_INSTANCE_NAME || 'AutomataAlmeira';
|
||||
const EVOLUTION_API_KEY = process.env.EVOLUTION_FEED_API_KEY || process.env.EVOLUTION_API_KEY || 'EE49029EEB85-4568-8F81-C9FDFC6E2943';
|
||||
const EVOLUTION_INSTANCE = process.env.EVOLUTION_FEED_INSTANCE_NAME || 'AutomataAlmeira';
|
||||
|
||||
// Carpeta local para almacenar en caché las imágenes descargadas en alta resolución
|
||||
const CACHE_DIR = path.join(process.cwd(), 'public', 'cache', 'whatsapp-media');
|
||||
|
||||
@ -125,6 +125,151 @@ export async function sendWhatsAppMedia(
|
||||
}
|
||||
}
|
||||
|
||||
// In-memory cache for group subjects: jid -> { subject, expiresAt }
|
||||
const groupCache = new Map<string, { subject: string; expiresAt: number }>();
|
||||
const GROUP_CACHE_TTL_MS = 60 * 60 * 1000; // 1 hora
|
||||
|
||||
/**
|
||||
* Obtener todos los grupos de WhatsApp desde Evolution API
|
||||
*/
|
||||
export async function fetchAllWhatsAppGroups(): Promise<Array<{ id: string; subject: string }>> {
|
||||
try {
|
||||
const url = `${EVOLUTION_API_URL}/group/fetchAllGroups/${EVOLUTION_FEED_INSTANCE_NAME}?getParticipants=false`;
|
||||
const response = await axios.get(url, {
|
||||
headers: { apikey: EVOLUTION_FEED_API_KEY, 'Content-Type': 'application/json' },
|
||||
timeout: 10000,
|
||||
});
|
||||
|
||||
if (Array.isArray(response.data)) {
|
||||
const groups = response.data
|
||||
.map((g: any) => ({
|
||||
id: g.id || g.jid || '',
|
||||
subject: g.subject || g.name || '',
|
||||
}))
|
||||
.filter((g: any) => Boolean(g.id));
|
||||
|
||||
const now = Date.now();
|
||||
for (const group of groups) {
|
||||
if (group.id && group.subject) {
|
||||
groupCache.set(group.id, { subject: group.subject, expiresAt: now + GROUP_CACHE_TTL_MS });
|
||||
}
|
||||
}
|
||||
|
||||
return groups;
|
||||
}
|
||||
} catch (err: any) {
|
||||
console.warn('[Evolution API] Error fetching WhatsApp groups:', err?.response?.data || err.message);
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolver el nombre exacto de un grupo por su JID (ej. 120363049363072784@g.us)
|
||||
*/
|
||||
export async function getWhatsAppGroupSubject(groupJid: string): Promise<string | null> {
|
||||
if (!groupJid) return null;
|
||||
|
||||
const now = Date.now();
|
||||
const cached = groupCache.get(groupJid);
|
||||
if (cached && cached.expiresAt > now) {
|
||||
return cached.subject;
|
||||
}
|
||||
|
||||
const groups = await fetchAllWhatsAppGroups();
|
||||
const found = groups.find((g) => g.id === groupJid);
|
||||
if (found && found.subject) {
|
||||
return found.subject;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extraer base64 de un mensaje multimedia desde Evolution API v2
|
||||
*/
|
||||
export async function getBase64FromMediaMessage(messagePayload: any): Promise<{ base64: string; mimetype: string } | null> {
|
||||
try {
|
||||
const url = `${EVOLUTION_API_URL}/chat/getBase64FromMediaMessage/${EVOLUTION_FEED_INSTANCE_NAME}`;
|
||||
const response = await axios.post(
|
||||
url,
|
||||
{ message: messagePayload },
|
||||
{ headers: { apikey: EVOLUTION_FEED_API_KEY, 'Content-Type': 'application/json' }, timeout: 12000 }
|
||||
);
|
||||
|
||||
if (response.data && response.data.base64) {
|
||||
return {
|
||||
base64: response.data.base64,
|
||||
mimetype: response.data.mimetype || 'image/jpeg',
|
||||
};
|
||||
}
|
||||
} catch (err: any) {
|
||||
console.warn('[Evolution API] Error getBase64FromMediaMessage:', err?.response?.data || err.message);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Consultar multimedia reciente del mismo chat para recolectar álbumes de calzado
|
||||
*/
|
||||
export async function fetchRecentMediaFromSameChat(
|
||||
remoteJid: string,
|
||||
maxItems: number = 8,
|
||||
windowSeconds: number = 240
|
||||
): Promise<Array<{ base64: string; mimeType: string; messageId: string }>> {
|
||||
if (!remoteJid) return [];
|
||||
|
||||
try {
|
||||
const url = `${EVOLUTION_API_URL}/chat/findMessages/${EVOLUTION_FEED_INSTANCE_NAME}?page=1&limit=25`;
|
||||
const response = await axios.post(
|
||||
url,
|
||||
{ where: { key: { remoteJid } } },
|
||||
{ headers: { apikey: EVOLUTION_FEED_API_KEY, 'Content-Type': 'application/json' }, timeout: 8000 }
|
||||
);
|
||||
|
||||
const records = response.data?.messages?.records || response.data?.records || (Array.isArray(response.data) ? response.data : []);
|
||||
const nowSec = Math.floor(Date.now() / 1000);
|
||||
|
||||
const mediaRecords = records
|
||||
.filter((r: any) => {
|
||||
const isMedia = Boolean(r.message?.imageMessage);
|
||||
if (!isMedia || !r.messageTimestamp) return false;
|
||||
const diff = Math.abs(nowSec - r.messageTimestamp);
|
||||
return diff <= windowSeconds;
|
||||
})
|
||||
.slice(0, maxItems);
|
||||
|
||||
if (mediaRecords.length === 0) return [];
|
||||
|
||||
const fetchPromises = mediaRecords.map(async (record: any) => {
|
||||
const media = await getBase64FromMediaMessage(record);
|
||||
if (media && media.base64) {
|
||||
return {
|
||||
base64: media.base64,
|
||||
mimeType: media.mimetype,
|
||||
messageId: record.key?.id || String(Date.now()),
|
||||
};
|
||||
}
|
||||
return null;
|
||||
});
|
||||
|
||||
const results = await Promise.allSettled(fetchPromises);
|
||||
const validMedia: Array<{ base64: string; mimeType: string; messageId: string }> = [];
|
||||
|
||||
for (const res of results) {
|
||||
if (res.status === 'fulfilled' && res.value) {
|
||||
validMedia.push(res.value);
|
||||
}
|
||||
}
|
||||
|
||||
return validMedia;
|
||||
} catch (err: any) {
|
||||
console.warn('[Evolution API] Error fetchRecentMediaFromSameChat:', err?.message);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Notifica inmediatamente la publicación automática de un nuevo producto
|
||||
* exclusivamente al WhatsApp personal de Carlos (+57 316 745 5877).
|
||||
|
||||
@ -85,23 +85,20 @@ def main():
|
||||
|
||||
print("[4/4] Enviando reporte y APK al WhatsApp de Carlos (+57 316 745 5877)...")
|
||||
message_text = (
|
||||
"🔥 *DripZone Android v2.1 - Tarjetas Comerciales de Alto Impacto Desplegadas*\n\n"
|
||||
"Hola Carlos, se ha actualizado la aplicación nativa en Android con todas las etiquetas llamativas, prueba social y visuales de conversión solicitadas:\n\n"
|
||||
"🏷️ *1. Badges Llamativos de Descuento (-30% OFF):*\n"
|
||||
"• Cada tarjeta ahora cuenta con su badge de descuento en gradiente morado a fucsia sobre la foto del calzado.\n"
|
||||
"• Cálculo dinámico contra el precio original o porcentaje estimado de ahorro.\n\n"
|
||||
"⭐ *2. Prueba Social & Contador de Compras:*\n"
|
||||
"• Calificación por estrellas doradas (4.8 - 5.0) con número de opiniones reales verificadas.\n"
|
||||
"• Conteo de ventas por modelo (+75 a +340 pedidos despachados) visible directamente en la vitrina.\n\n"
|
||||
"✨ *3. Etiquetas Especiales de Tendencia:*\n"
|
||||
"• Badges contextuales automáticos: *🔥 Top Ventas*, *⚡ Más Pedido*, *★ Drop Exclusivo*, *✨ Tendencia*, *🚀 2026 Release*, *💎 Premium*.\n\n"
|
||||
"💰 *4. Precios Originales Tachados & Facilidad de Separación:*\n"
|
||||
"• Precio actual destacado en color Neón Glow junto al precio original tachado.\n"
|
||||
"• Micro-banner integrado: *⚡ Separa con $10.000 y cancelas al recibir* para incentivar el pedido contraentrega.\n\n"
|
||||
"📱 *5. Experiencia Unificada en Vista Rápida y Modal de Detalle:*\n"
|
||||
"• La misma información enriquecida (descuento, estrellas, ventas, precios tachados y garantías de cambio) se replica de manera limpia al tocar el calzado.\n\n"
|
||||
"🚀 *DripZone Android & Catálogo WhatsApp - Publicaciones Automáticas Restablecidas*\n\n"
|
||||
"Hola Carlos, se ha corregido y verificado con éxito el sistema de publicaciones automáticas en la aplicación móvil y el catálogo de WhatsApp:\n\n"
|
||||
"📡 *1. Configuración de Webhooks en Evolution API:*\n"
|
||||
"• La instancia `AutomataAlmeira` (tu número +57 316 745 5877 en los 20 grupos) y la instancia `DripZone` (+57 310 639 0296) ahora apuntan directamente a `https://drip-zone.online/api/webhook/whatsapp`.\n"
|
||||
"• Se eliminó el descarte accidental que ocurría cuando los mensajes pasaban por el portal de noticias.\n\n"
|
||||
"👟 *2. Publicación Inmediata en la App y Appwrite:*\n"
|
||||
"• Cada calzado recibido desde los grupos mayoristas (Jovic Store, CC Mío, Team Emporio, etc.) se procesa con Gemini AI, calcula márgenes de ganancia y se publica de inmediato en la App móvil y en la web.\n\n"
|
||||
"📦 *3. Catálogo de WhatsApp Business (Meta Commerce):*\n"
|
||||
"• Los feeds XML (`/api/catalog/feed.xml`) y CSV (`/api/catalog/feed.csv`) ahora se sincronizan en tiempo real con Appwrite sin demoras de caché.\n"
|
||||
"• Las fotos en alta resolución, precios en COP, tallas y enlace de checkout quedan disponibles automáticamente para Meta.\n\n"
|
||||
"📰 *4. Enrutamiento Seguro de Prensa y Noticias:*\n"
|
||||
"• Los comunicados de prensa y grupos institucionales (Gob Cauca, Alcaldía, Inelpac) se redirigen de forma segura y transparente al portal de noticias `news.almeira.com.co`.\n\n"
|
||||
f"⬇️ *Descarga directa del APK:* {APK_URL}\n\n"
|
||||
"Te adjunto de inmediato el archivo instalador APK actualizado para prueba en tu celular."
|
||||
"Adjunto el instalador APK actualizado con todas las funciones operativas."
|
||||
)
|
||||
|
||||
req_text = urllib.request.Request(
|
||||
|
||||
@ -48,7 +48,7 @@ export async function POST(req: Request) {
|
||||
try {
|
||||
const payload = await req.json();
|
||||
|
||||
// Reenviar asíncronamente a los webhooks de las tiendas de calzado (DripZone, Sneaky, etc.)
|
||||
// Reenviar de forma segura a los webhooks de las tiendas de calzado (DripZone, Sneaky, etc.)
|
||||
const MULTISTORE_WEBHOOKS = [
|
||||
'https://drip-zone.online/api/webhook/whatsapp',
|
||||
'https://dripzone.almeira.com.co/api/webhook/whatsapp',
|
||||
@ -57,14 +57,18 @@ export async function POST(req: Request) {
|
||||
'https://store.almeira.com.co/api/webhook/whatsapp',
|
||||
];
|
||||
|
||||
for (const targetUrl of MULTISTORE_WEBHOOKS) {
|
||||
fetch(targetUrl, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(payload),
|
||||
signal: AbortSignal.timeout(60000),
|
||||
}).catch(() => {});
|
||||
}
|
||||
try {
|
||||
await Promise.allSettled(
|
||||
MULTISTORE_WEBHOOKS.map(targetUrl =>
|
||||
fetch(targetUrl, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(payload),
|
||||
signal: AbortSignal.timeout(12000),
|
||||
}).catch(() => {})
|
||||
)
|
||||
);
|
||||
} catch (_) {}
|
||||
|
||||
const rawEvent = payload.event || '';
|
||||
const eventType = rawEvent.toLowerCase().replace(/_/g, '.');
|
||||
|
||||
@ -30,5 +30,12 @@
|
||||
".next/dev/types/**/*.ts",
|
||||
"**/*.mts"
|
||||
],
|
||||
"exclude": ["node_modules"]
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
"dripzone-app",
|
||||
"sneaky-app",
|
||||
"zapply-app",
|
||||
"almeira-store-app",
|
||||
"almeira-live"
|
||||
]
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user