#!/usr/bin/env node const fs = require('fs'); const path = require('path'); const puppeteer = require('puppeteer'); function detectChromeExecutable() { const candidates = []; const cacheRoot = '/home/ubuntu/.cache/puppeteer/chrome'; try { if (fs.existsSync(cacheRoot)) { const versions = fs.readdirSync(cacheRoot).sort().reverse(); for (const version of versions) { candidates.push(path.join(cacheRoot, version, 'chrome-linux64', 'chrome')); } } } catch (error) { // Ignoramos y seguimos con rutas fijas. } if (process.env.PUPPETEER_EXECUTABLE_PATH) { candidates.unshift(process.env.PUPPETEER_EXECUTABLE_PATH); } candidates.push( '/usr/bin/google-chrome-stable', '/usr/bin/google-chrome', '/usr/bin/chromium', '/usr/bin/chromium-browser' ); return candidates.find((candidate) => candidate && fs.existsSync(candidate)) || null; } function sleep(ms) { return new Promise((resolve) => setTimeout(resolve, ms)); } async function main() { const orderNumber = (process.argv[2] || '').trim(); const orderCode = (process.argv[3] || '').trim(); if (!orderNumber || !orderCode) { console.log(JSON.stringify({ success: false, error: 'Número de orden y código de orden son requeridos.' })); process.exit(1); } const trackingUrl = `https://shalom.com.pe/rastrea/${encodeURIComponent(orderNumber)}/${encodeURIComponent(orderCode)}`; let browser = null; try { const executablePath = detectChromeExecutable(); browser = await puppeteer.launch({ headless: 'new', executablePath: executablePath || undefined, args: [ '--no-sandbox', '--disable-setuid-sandbox', '--disable-dev-shm-usage' ] }); const page = await browser.newPage(); await page.setViewport({ width: 1280, height: 900 }); await page.setUserAgent('Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36'); await page.goto(trackingUrl, { waitUntil: 'networkidle2', timeout: 60000, }); await sleep(4000); const payload = await page.evaluate(() => { const textOf = (selectorList) => { for (const selector of selectorList) { const el = document.querySelector(selector); const text = el && el.textContent ? el.textContent.trim() : ''; if (text) return text; } return ''; }; const allParagraphs = Array.from(document.querySelectorAll('p')) .map((p) => (p.textContent || '').trim()) .filter(Boolean); const status = textOf([ '.text-4xl.font-bold.text-red-color-sidebar', '.text-3xl.font-bold.text-red-color-sidebar' ]); let description = textOf([ 'p.text-md.font-normal.text-silver-title', 'p.text-sm.font-normal.text-silver-title' ]); if (!description) { description = allParagraphs.find((text) => { return !/^N° DE ORDEN:/i.test(text) && !/^Desde el/i.test(text) && /destino|recojo|entregado|origen|procesado|tránsito|transito/i.test(text); }) || ''; } const orderLabel = allParagraphs.find((text) => /^N° DE ORDEN:/i.test(text)) || ''; const dateLabel = allParagraphs.find((text) => /^Desde el/i.test(text)) || ''; const internalOrderNumber = orderLabel.replace(/^N° DE ORDEN:\s*/i, '').trim(); const bodyText = document.body && document.body.innerText ? document.body.innerText.trim() : ''; return { status, description, orderLabel, dateLabel, internalOrderNumber, requiresLogin: /Inicia sesión para acceder/i.test(bodyText), currentUrl: location.href, currentPath: location.pathname, }; }); if (!payload.status || payload.currentPath === '/rastrea') { console.log(JSON.stringify({ success: false, error: 'No se pudo encontrar la guía en el rastreo público de Shalom.', tracking_url: trackingUrl, })); process.exit(2); } console.log(JSON.stringify({ success: true, source: 'shalom_web', status: payload.status, description: payload.description, internal_order_number: payload.internalOrderNumber || null, external_order_number: orderNumber, order_code: orderCode, date_text: payload.dateLabel || null, tracking_url: trackingUrl, requires_login: !!payload.requiresLogin, })); } catch (error) { console.log(JSON.stringify({ success: false, error: error && error.message ? error.message : 'Error al consultar Shalom.', tracking_url: trackingUrl, })); process.exit(3); } finally { if (browser) { try { await browser.close(); } catch (error) { // Ignoramos errores al cerrar el navegador. } } } } main();