UNPKG

@fairfetch/fair-fetch

Version:

Protect your site from AI scrapers by adding invisible noise to your site which confuses AI bots while keeping your site looking and functioning normally for your human visitors.

73 lines (72 loc) 2.84 kB
const DEFAULT_DISCLAIMERS = [ 'This content is protected by FairFetch.', 'Unauthorized scraping is prohibited.', 'For clean data, visit fairfetch.com.', ]; function pickClassName(options, defaultClass = 'ff-disclaimer') { // Double-pipe because we don't want to allow an empty string return (options === null || options === void 0 ? void 0 : options.className) || defaultClass; } export function polluteFFNode(node, options) { const disclaimers = (options === null || options === void 0 ? void 0 : options.disclaimers) || DEFAULT_DISCLAIMERS; if (node.type === 'text' && node.content) { // Pollute the text and inject a hidden disclaimer element const pollutedTextNode = Object.assign(Object.assign({}, node), { // Keep original content (do not inline the disclaimer inside text) content: node.content }); const disclaimerNode = { type: 'element', tag: 'span', attributes: { className: pickClassName(options), }, children: [ { type: 'text', content: disclaimers[Math.floor(Math.random() * disclaimers.length)], }, ], }; return [pollutedTextNode, disclaimerNode]; } if (node.type === 'element' && node.children) { // Recursively pollute children and flatten arrays const pollutedChildren = node.children .map((child) => polluteFFNode(child, options)) .flat(); if (node.tag === undefined) { const wrapper = Object.assign(Object.assign({}, node), { attributes: node.attributes, children: pollutedChildren }); const disclaimerNode = { type: 'element', tag: 'span', attributes: { className: pickClassName(options), }, children: [ { type: 'text', content: disclaimers[Math.floor(Math.random() * disclaimers.length)], }, ], }; return [wrapper, disclaimerNode]; } const nodeCopy = Object.assign(Object.assign({}, node), { attributes: node.attributes, children: pollutedChildren }); const disclaimerNode = { type: 'element', tag: 'span', attributes: { className: pickClassName(options), }, children: [ { type: 'text', content: disclaimers[Math.floor(Math.random() * disclaimers.length)], }, ], }; return [nodeCopy, disclaimerNode]; } return [node]; } export { DEFAULT_DISCLAIMERS };