358347e8ba
- Extract fetchAndExtractPriceViaBrowser from deps (optional) - After primary fetch, if it errors or returns no price and fallback exists, try fallback - Fallback result replaces primary result for further processing - Retry-safety logic unchanged: last_price/last_checked_at only updated on success - All 4 new tests pass, all existing tests unchanged Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013gwc3aCiyQxmCWQke8RvEz
60 lines
1.9 KiB
JavaScript
60 lines
1.9 KiB
JavaScript
async function checkProduct(product, deps) {
|
|
const {
|
|
fetchAndExtractPrice, fetchAndExtractPriceViaBrowser,
|
|
sendMail, recordCheckSuccess, recordCheckFailure, now,
|
|
} = deps;
|
|
let result = await fetchAndExtractPrice(product.url);
|
|
|
|
if ((result.error || result.price == null) && fetchAndExtractPriceViaBrowser) {
|
|
result = await fetchAndExtractPriceViaBrowser(product.url);
|
|
}
|
|
|
|
if (result.error) {
|
|
console.error(`[check] fetch_error "${product.name}" (${product.url}): ${result.error.message}`);
|
|
recordCheckFailure(product.id, 'fetch_error');
|
|
return { status: 'fetch_error' };
|
|
}
|
|
if (result.price == null) {
|
|
console.error(`[check] not_found "${product.name}" (${product.url}): geen prijs gevonden op de pagina`);
|
|
recordCheckFailure(product.id, 'not_found');
|
|
return { status: 'not_found' };
|
|
}
|
|
|
|
const isBaseline = product.last_price == null;
|
|
const changed = !isBaseline && result.price !== product.last_price;
|
|
|
|
if (changed) {
|
|
try {
|
|
await sendMail({
|
|
name: product.name,
|
|
url: product.url,
|
|
oldPrice: product.last_price,
|
|
newPrice: result.price,
|
|
});
|
|
} catch (err) {
|
|
console.error(`[check] mail_error "${product.name}" (${product.url}): ${err && err.message}`);
|
|
recordCheckFailure(product.id, 'mail_error');
|
|
return { status: 'mail_error' };
|
|
}
|
|
}
|
|
|
|
recordCheckSuccess(product.id, { price: result.price, checkedAt: now() });
|
|
return { status: 'ok', changed };
|
|
}
|
|
|
|
async function checkAllProducts(products, deps) {
|
|
const results = [];
|
|
for (const product of products) {
|
|
try {
|
|
const result = await checkProduct(product, deps);
|
|
results.push({ productId: product.id, ...result });
|
|
} catch (err) {
|
|
console.error(`[check] error "${product.name}" (${product.url}): ${err && err.message}`);
|
|
results.push({ productId: product.id, status: 'error', error: err });
|
|
}
|
|
}
|
|
return results;
|
|
}
|
|
|
|
module.exports = { checkProduct, checkAllProducts };
|