n8n-nodes-pdf-accessibility
Version:
AI-powered PDF accessibility automation for N8N - comprehensive WCAG compliance analysis, intelligent remediation, and professional audit reporting with 5 integrated accessibility tools
283 lines (282 loc) • 12.7 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.getPdfInput = getPdfInput;
const fs = __importStar(require("fs"));
/**
* Helper function to detect if a string is valid base64
*/
function isBase64String(str) {
if (typeof str !== 'string' || str.length === 0)
return false;
const base64Pattern = /^[A-Za-z0-9+/]+=*$/;
if (!base64Pattern.test(str) || str.length % 4 !== 0)
return false;
try {
const decoded = Buffer.from(str, 'base64');
return decoded.slice(0, 8).toString().startsWith('%PDF-');
}
catch {
return false;
}
}
/**
* Intelligent format detection and conversion to PDF Buffer
* Handles all major binary data formats from Google Drive, HTTP Request, and other N8N nodes
*/
async function convertToPdfBuffer(rawData, binaryData) {
// Optional debug mode (can be enabled via environment variable)
const debug = process.env.PDF_DEBUG === 'true';
if (debug) {
console.log('=== PDF BUFFER CONVERSION DEBUG ===');
console.log('rawData type:', typeof rawData);
console.log('rawData isBuffer:', Buffer.isBuffer(rawData));
console.log('binaryData exists:', !!binaryData);
}
// If it's already a proper Buffer with PDF header, return it
if (Buffer.isBuffer(rawData)) {
const header = rawData.slice(0, 8).toString();
if (debug)
console.log('Buffer header:', header);
if (header.startsWith('%PDF-')) {
if (debug)
console.log('✅ Valid PDF Buffer found');
return rawData;
}
// If Buffer but not PDF, might be base64 encoded
const base64String = rawData.toString();
if (isBase64String(base64String)) {
if (debug)
console.log('✅ Buffer contains base64, converting');
return Buffer.from(base64String, 'base64');
}
}
// Handle base64 string (Google Drive format)
if (typeof rawData === 'string') {
if (debug) {
console.log('rawData is string, length:', rawData.length);
console.log('String starts with:', rawData.substring(0, 20));
}
if (isBase64String(rawData)) {
if (debug)
console.log('✅ Valid base64 string found');
return Buffer.from(rawData, 'base64');
}
}
// Handle serialized Buffer: {type: "Buffer", data: [array]}
if (typeof rawData === 'object' &&
rawData.type === 'Buffer' &&
Array.isArray(rawData.data)) {
if (debug)
console.log('✅ Serialized Buffer found, data length:', rawData.data.length);
return Buffer.from(rawData.data);
}
// Check if binaryData contains the actual data in .data property
if (binaryData && binaryData.data) {
if (debug)
console.log('Checking binaryData.data...');
if (typeof binaryData.data === 'string' && isBase64String(binaryData.data)) {
if (debug)
console.log('✅ Base64 in binaryData.data found');
return Buffer.from(binaryData.data, 'base64');
}
if (typeof binaryData.data === 'object' &&
binaryData.data.type === 'Buffer' &&
Array.isArray(binaryData.data.data)) {
if (debug)
console.log('✅ Serialized Buffer in binaryData.data found');
return Buffer.from(binaryData.data.data);
}
// Check if binaryData.data is already a Buffer
if (Buffer.isBuffer(binaryData.data)) {
if (debug)
console.log('✅ Direct Buffer in binaryData.data found');
return binaryData.data;
}
}
// Additional Google Drive formats
if (binaryData && binaryData.content) {
if (debug)
console.log('Checking binaryData.content...');
if (typeof binaryData.content === 'string' && isBase64String(binaryData.content)) {
if (debug)
console.log('✅ Base64 in binaryData.content found');
return Buffer.from(binaryData.content, 'base64');
}
}
// Check nested data structures
if (rawData && rawData.data && typeof rawData.data === 'string') {
if (debug)
console.log('Checking rawData.data string...');
if (isBase64String(rawData.data)) {
if (debug)
console.log('✅ Base64 in rawData.data found');
return Buffer.from(rawData.data, 'base64');
}
}
// Enhanced error with troubleshooting guidance
const errorDetails = {
rawDataType: typeof rawData,
rawDataKeys: rawData && typeof rawData === 'object' ? Object.keys(rawData) : 'N/A',
binaryDataKeys: binaryData ? Object.keys(binaryData) : 'N/A'
};
if (debug) {
console.log('❌ No valid PDF format detected');
console.log('Available data summary:', errorDetails);
}
throw new Error('Unable to convert binary data to PDF Buffer. ' +
'Troubleshooting: ' +
'1) Ensure the input is a valid PDF file. ' +
'2) If using Google Drive, try "Get File" or "Download File" operations. ' +
'3) If using HTTP Request, ensure response type is binary. ' +
'4) Enable debug mode (set PDF_DEBUG=true) for detailed analysis. ' +
`Data analysis: ${JSON.stringify(errorDetails)}`);
}
async function getPdfInput(context, itemIndex) {
const inputMethod = context.getNodeParameter('inputMethod', itemIndex, 'binary');
let pdfBuffer;
let fileName = 'unknown.pdf';
switch (inputMethod) {
case 'filepath': {
// Handle file path (supports expressions)
const filePath = context.getNodeParameter('filePath', itemIndex, '');
if (!filePath) {
throw new Error('Please provide a file path to the PDF');
}
try {
pdfBuffer = fs.readFileSync(filePath);
fileName = filePath.split('/').pop() || 'file.pdf';
}
catch (error) {
throw new Error(`Failed to read file from path "${filePath}": ${error instanceof Error ? error.message : String(error)}`);
}
break;
}
case 'base64': {
// Handle base64 encoded data (supports expressions)
const base64Data = context.getNodeParameter('base64Data', itemIndex, '');
if (!base64Data) {
throw new Error('Please provide base64 encoded PDF data');
}
try {
// Remove data URL prefix if present (data:application/pdf;base64,)
const cleanBase64 = base64Data.replace(/^data:application\/pdf;base64,/, '');
pdfBuffer = Buffer.from(cleanBase64, 'base64');
fileName = 'base64.pdf';
}
catch (error) {
throw new Error(`Failed to decode base64 data: ${error instanceof Error ? error.message : String(error)}`);
}
break;
}
case 'url': {
// Handle URL download (Google Drive share links, direct URLs, etc.)
const url = context.getNodeParameter('url', itemIndex, '');
if (!url) {
throw new Error('Please provide a URL to the PDF');
}
try {
// Convert Google Drive share links to direct download links
let downloadUrl = url;
if (url.includes('drive.google.com/file/d/')) {
// Extract file ID from share link
const fileIdMatch = url.match(/\/file\/d\/([a-zA-Z0-9-_]+)/);
if (fileIdMatch) {
downloadUrl = `https://drive.google.com/uc?export=download&id=${fileIdMatch[1]}`;
}
}
else if (url.includes('docs.google.com/document/d/')) {
// Extract document ID from Google Docs link
const docIdMatch = url.match(/\/document\/d\/([a-zA-Z0-9-_]+)/);
if (docIdMatch) {
downloadUrl = `https://docs.google.com/document/d/${docIdMatch[1]}/export?format=pdf`;
}
}
const response = await context.helpers.httpRequest({
method: 'GET',
url: downloadUrl,
returnFullResponse: false,
encoding: 'arraybuffer',
headers: {
'User-Agent': 'N8N-PDF-Accessibility-Node/1.2.8'
}
});
pdfBuffer = Buffer.isBuffer(response) ? response : Buffer.from(response);
// Extract filename from URL or use default
fileName = url.split('/').pop()?.split('?')[0] || 'downloaded.pdf';
if (!fileName.endsWith('.pdf')) {
fileName += '.pdf';
}
}
catch (error) {
throw new Error(`Failed to download PDF from URL "${url}". ` +
'Troubleshooting: ' +
'1) Ensure the URL is publicly accessible. ' +
'2) For Google Drive, use shareable links with "Anyone with the link can view" permissions. ' +
'3) For Google Docs, the document will be automatically converted to PDF. ' +
`Error: ${error instanceof Error ? error.message : String(error)}`);
}
break;
}
case 'binary':
default: {
// Handle binary data from previous node with intelligent format detection
const binaryPropertyName = context.getNodeParameter('binaryPropertyName', itemIndex, 'data');
try {
const binaryData = context.helpers.assertBinaryData(itemIndex, binaryPropertyName);
const rawData = await context.helpers.getBinaryDataBuffer(itemIndex, binaryPropertyName);
// 🆕 INTELLIGENT FORMAT DETECTION AND CONVERSION
pdfBuffer = await convertToPdfBuffer(rawData, binaryData);
fileName = binaryData.fileName || 'binary.pdf';
}
catch (error) {
const isFormatError = error instanceof Error && error.message.includes('Unable to convert binary data');
if (isFormatError) {
// Re-throw format conversion errors with original message
throw error;
}
throw new Error(`PDF file required: No binary data found with property name "${binaryPropertyName}". ` +
'Troubleshooting: ' +
'1) Connect a node that provides PDF data (HTTP Request, Read Binary File, Google Drive, etc.). ' +
'2) Ensure the previous node outputs binary data, not JSON. ' +
'3) Check the binary property name matches the previous node output. ' +
'4) Alternative: Switch to "File Path", "URL", or "Base64 Data" input method. ' +
'5) For Google Drive: Use "Get File" or "Download File" operations instead of "Get" or "List".');
}
break;
}
}
return { buffer: pdfBuffer, fileName };
}