n8n-nodes-sotoros-gotenberg 1.0.8 → 1.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -288,95 +288,125 @@ class Gotenberg {
288
288
  // Создаем FormData для отправки в Gotenberg - один запрос для всех элементов списка
289
289
  const formData = new form_data_1.default();
290
290
  let totalFilesCount = 0;
291
- // Собираем все binary данные из всех элементов списка
291
+ const processedFiles = [];
292
+ // Собираем информацию о доступных binary данных в aggregatedItem
293
+ const aggregatedBinaryKeys = Object.keys(aggregatedItem.binary || {});
294
+ const debugInfo = {
295
+ aggregatedItemBinaryKeys: aggregatedBinaryKeys,
296
+ listDataLength: listData.length,
297
+ binaryPropertyName,
298
+ listPropertyName: listPropertyName || '(root array)',
299
+ processingSteps: [],
300
+ };
301
+ // Собираем все binary данные из aggregatedItem.binary
302
+ // Используем только getBinaryDataBuffer(0, key) для получения файлов
292
303
  for (let listIndex = 0; listIndex < listData.length; listIndex++) {
293
304
  const listItem = listData[listIndex];
305
+ const stepInfo = {
306
+ listIndex,
307
+ itemType: typeof listItem,
308
+ isObject: typeof listItem === 'object' && listItem !== null,
309
+ itemKeys: listItem && typeof listItem === 'object' ? Object.keys(listItem) : [],
310
+ foundBinary: false,
311
+ binaryKey: undefined,
312
+ processedFiles: 0,
313
+ };
294
314
  if (!listItem || typeof listItem !== 'object') {
315
+ stepInfo.error = 'Item is not an object or is null';
316
+ debugInfo.processingSteps.push(stepInfo);
295
317
  continue; // Пропускаем некорректные элементы
296
318
  }
297
- // Элемент списка может быть INodeExecutionData полями json и binary)
298
- // или обычным объектом с binary данными в разных местах
299
- let itemBinary;
300
- let binaryProperty;
301
- // Вариант 1: элемент имеет структуру INodeExecutionData (json и binary)
302
- if ('binary' in listItem && listItem.binary && typeof listItem.binary === 'object') {
303
- itemBinary = listItem.binary;
304
- binaryProperty = itemBinary[binaryPropertyName];
305
- }
306
- // Вариант 2: binary данные находятся в свойстве элемента напрямую
307
- else if (binaryPropertyName in listItem) {
308
- const binaryProp = listItem[binaryPropertyName];
309
- if (binaryProp && typeof binaryProp === 'object') {
310
- // Может быть одиночным объектом или массивом
311
- if (binaryProp.data) {
312
- // Это одиночный binary объект
313
- binaryProperty = binaryProp;
314
- }
315
- else if (Array.isArray(binaryProp)) {
316
- // Это массив binary объектов
317
- binaryProperty = binaryProp;
318
- }
319
- }
320
- }
321
- // Вариант 3: если binary данные не найдены в элементе списка,
322
- // ищем их в aggregatedItem.binary по индексу
319
+ // Определяем ключ для binary данных в aggregatedItem.binary
323
320
  // Для первого элемента (index 0) используем binaryPropertyName, для остальных - binaryPropertyName_${index}
324
- let binaryKeyFromAggregated;
325
- if (!binaryProperty && aggregatedItem.binary) {
326
- binaryKeyFromAggregated = listIndex === 0 ? binaryPropertyName : `${binaryPropertyName}_${listIndex}`;
327
- if (binaryKeyFromAggregated in aggregatedItem.binary) {
328
- binaryProperty = aggregatedItem.binary[binaryKeyFromAggregated];
321
+ let binaryKey;
322
+ const possibleKeys = [
323
+ listIndex === 0 ? binaryPropertyName : `${binaryPropertyName}_${listIndex}`, // data или data_0, data_1, etc.
324
+ `${binaryPropertyName}_${listIndex + 1}`, // data_1 для index 0
325
+ `${listIndex}`, // просто индекс
326
+ `file_${listIndex}`, // file_0, file_1
327
+ ];
328
+ // Ищем первый доступный ключ в aggregatedItem.binary
329
+ for (const key of possibleKeys) {
330
+ if (aggregatedItem.binary && key in aggregatedItem.binary) {
331
+ binaryKey = key;
332
+ stepInfo.binaryKey = key;
333
+ stepInfo.foundBinary = true;
334
+ break;
329
335
  }
330
336
  }
331
- if (!binaryProperty) {
337
+ if (!binaryKey) {
338
+ stepInfo.error = `Binary key not found in aggregatedItem.binary. Tried keys: ${possibleKeys.join(', ')}. Available keys: ${aggregatedBinaryKeys.join(', ')}`;
339
+ debugInfo.processingSteps.push(stepInfo);
332
340
  continue; // Пропускаем элементы без binary данных
333
341
  }
334
- // Обрабатываем как одиночное значение, так и массив
335
- const binaryItems = Array.isArray(binaryProperty) ? binaryProperty : [binaryProperty];
336
- // Добавляем все файлы из этого элемента списка
337
- for (let i = 0; i < binaryItems.length; i++) {
338
- const binaryItem = binaryItems[i];
339
- if (!binaryItem) {
340
- continue; // Пропускаем файлы без данных
341
- }
342
- // Получаем buffer из binary данных через хелпер n8n
343
- let dataBuffer;
344
- try {
345
- // Если binary данные из aggregatedItem.binary, используем имя свойства напрямую
346
- if (binaryKeyFromAggregated) {
347
- dataBuffer = await this.helpers.getBinaryDataBuffer(0, binaryKeyFromAggregated);
348
- }
349
- else {
350
- // Используем хелпер getBinaryDataBuffer для правильной обработки binary данных
351
- // Передаем itemIndex = 0 (aggregatedItem) и IBinaryData объект
352
- dataBuffer = await this.helpers.getBinaryDataBuffer(0, binaryItem);
353
- }
354
- }
355
- catch (error) {
356
- // Если не получилось через хелпер, пробуем напрямую (для обратной совместимости)
357
- if (binaryItem.data) {
358
- dataBuffer = Buffer.from(binaryItem.data, 'base64');
359
- }
360
- else {
361
- continue; // Пропускаем файлы без данных
362
- }
363
- }
364
- // Используем fileName из метаданных элемента списка, если доступно
365
- const fileName = binaryItem.fileName ||
366
- (listItem && typeof listItem === 'object' && 'fileName' in listItem
367
- ? listItem.fileName
368
- : undefined) ||
369
- (listItem && typeof listItem === 'object' && 'fileExtension' in listItem
370
- ? `${binaryPropertyName}_${listIndex}.${listItem.fileExtension}`
371
- : `${binaryPropertyName}_${listIndex}_${i}.${getFileExtensionFromMimeType(binaryItem.mimeType || '')}`);
372
- formData.append('files', dataBuffer, {
373
- filename: fileName,
374
- contentType: binaryItem.mimeType || 'application/octet-stream',
375
- });
376
- totalFilesCount++;
342
+ // Получаем метаданные binary файла из aggregatedItem.binary
343
+ if (!aggregatedItem.binary) {
344
+ stepInfo.error = 'aggregatedItem.binary is undefined';
345
+ debugInfo.processingSteps.push(stepInfo);
346
+ continue;
347
+ }
348
+ const binaryMetadata = aggregatedItem.binary[binaryKey];
349
+ if (!binaryMetadata) {
350
+ stepInfo.error = `Binary metadata not found for key: ${binaryKey}`;
351
+ debugInfo.processingSteps.push(stepInfo);
352
+ continue;
353
+ }
354
+ // Получаем buffer из binary данных через хелпер n8n
355
+ // Используем только getBinaryDataBuffer(0, key)
356
+ let dataBuffer;
357
+ let bufferError;
358
+ const fileInfo = {
359
+ listIndex,
360
+ fileIndex: 0,
361
+ binaryKey,
362
+ fileName: binaryMetadata.fileName || 'unknown',
363
+ mimeType: binaryMetadata.mimeType || 'application/octet-stream',
364
+ hasData: false,
365
+ fileSize: 0,
366
+ };
367
+ try {
368
+ // Используем только getBinaryDataBuffer(0, key) для получения файла
369
+ dataBuffer = await this.helpers.getBinaryDataBuffer(0, binaryKey);
370
+ fileInfo.hasData = true;
371
+ fileInfo.fileSize = dataBuffer.length;
377
372
  }
373
+ catch (error) {
374
+ bufferError = error.message || String(error);
375
+ fileInfo.error = bufferError;
376
+ stepInfo.error = `Failed to get binary data buffer: ${bufferError}`;
377
+ debugInfo.processingSteps.push(stepInfo);
378
+ processedFiles.push(fileInfo);
379
+ continue; // Пропускаем файлы, которые не удалось получить
380
+ }
381
+ if (!dataBuffer || dataBuffer.length === 0) {
382
+ fileInfo.error = 'Buffer is empty or null';
383
+ stepInfo.error = 'Buffer is empty or null';
384
+ debugInfo.processingSteps.push(stepInfo);
385
+ processedFiles.push(fileInfo);
386
+ continue; // Пропускаем пустые файлы
387
+ }
388
+ // Используем fileName из метаданных или генерируем на основе данных элемента списка
389
+ const fileName = binaryMetadata.fileName ||
390
+ (listItem && typeof listItem === 'object' && 'fileName' in listItem
391
+ ? listItem.fileName
392
+ : undefined) ||
393
+ (listItem && typeof listItem === 'object' && 'fileExtension' in listItem
394
+ ? `${binaryPropertyName}_${listIndex}.${listItem.fileExtension}`
395
+ : `${binaryPropertyName}_${listIndex}.${getFileExtensionFromMimeType(binaryMetadata.mimeType || '')}`);
396
+ fileInfo.fileName = fileName;
397
+ formData.append('files', dataBuffer, {
398
+ filename: fileName,
399
+ contentType: binaryMetadata.mimeType || 'application/octet-stream',
400
+ });
401
+ processedFiles.push(fileInfo);
402
+ totalFilesCount++;
403
+ stepInfo.processedFiles = 1;
404
+ debugInfo.processingSteps.push(stepInfo);
378
405
  }
379
406
  if (totalFilesCount === 0) {
407
+ // Добавляем информацию о шагах обработки в debugInfo
408
+ debugInfo.processedFiles = processedFiles;
409
+ debugInfo.totalFilesCount = totalFilesCount;
380
410
  // Собираем информацию о структуре элементов списка
381
411
  const sampleItems = listData.slice(0, 3).map((item, index) => {
382
412
  const itemInfo = {
@@ -414,7 +444,7 @@ class Gotenberg {
414
444
  sampleBinaryData: {},
415
445
  };
416
446
  // Показываем структуру первых нескольких binary данных
417
- const binaryKeysToShow = Object.keys(aggregatedItem.binary || {}).slice(0, 3);
447
+ const binaryKeysToShow = Object.keys(aggregatedItem.binary || {}).slice(0, 5);
418
448
  for (const key of binaryKeysToShow) {
419
449
  const binaryData = aggregatedItem.binary[key];
420
450
  if (binaryData) {
@@ -423,6 +453,8 @@ class Gotenberg {
423
453
  dataLength: binaryData.data ? binaryData.data.length : 0,
424
454
  mimeType: binaryData.mimeType,
425
455
  fileName: binaryData.fileName,
456
+ hasId: !!binaryData.id,
457
+ id: binaryData.id,
426
458
  };
427
459
  }
428
460
  }
@@ -449,6 +481,7 @@ class Gotenberg {
449
481
  return keys;
450
482
  })(),
451
483
  },
484
+ debugInfo,
452
485
  });
453
486
  const structureInfo = JSON.stringify(formattedStructure, null, 2);
454
487
  // Проверяем, есть ли binary данные в aggregatedItem.binary
@@ -458,6 +491,7 @@ class Gotenberg {
458
491
  expectedBinaryKeys.push(i === 0 ? binaryPropertyName : `${binaryPropertyName}_${i}`);
459
492
  }
460
493
  throw new n8n_workflow_1.NodeOperationError(this.getNode(), `No valid binary files found in any items. Please make sure binary data exists.\n\n` +
494
+ `Processing steps:\n${JSON.stringify(debugInfo.processingSteps, null, 2)}\n\n` +
461
495
  `Input data structure:\n${structureInfo}\n\n` +
462
496
  `Binary data search locations:\n` +
463
497
  `1. In list item: item.binary["${binaryPropertyName}"] or item["${binaryPropertyName}"]\n` +
@@ -468,7 +502,7 @@ class Gotenberg {
468
502
  `Tips:\n` +
469
503
  `- Check that binaryPropertyName "${binaryPropertyName}" matches the property name\n` +
470
504
  `- Verify that binary data exists in aggregatedItem.binary with keys: "${binaryPropertyName}", "${binaryPropertyName}_1", "${binaryPropertyName}_2", etc.\n` +
471
- `- Make sure binary data has a "data" field with base64 content`);
505
+ `- Make sure binary data has a "data" field with base64 content or uses n8n binary storage`);
472
506
  }
473
507
  // Добавляем опции в зависимости от операции
474
508
  if (operation === 'office' || operation === 'html' || operation === 'markdown') {
@@ -622,9 +656,14 @@ class Gotenberg {
622
656
  }
623
657
  // Проверяем, что получили валидный PDF
624
658
  if (pdfBuffer.length < 4 || pdfBuffer.toString('ascii', 0, 4) !== '%PDF') {
625
- throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Invalid PDF received from Gotenberg. The response does not appear to be a valid PDF file.');
659
+ const pdfHeader = pdfBuffer.length > 0 ? pdfBuffer.toString('ascii', 0, Math.min(20, pdfBuffer.length)) : 'empty';
660
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Invalid PDF received from Gotenberg. The response does not appear to be a valid PDF file.\n` +
661
+ `PDF buffer size: ${pdfBuffer.length} bytes\n` +
662
+ `First 20 bytes: ${pdfHeader}\n` +
663
+ `Processed files info:\n${JSON.stringify(processedFiles, null, 2)}\n` +
664
+ `Debug info:\n${JSON.stringify(debugInfo, null, 2)}`);
626
665
  }
627
- // Создаем один выходной элемент с результатом
666
+ // Создаем один выходной элемент с результатом и отладочной информацией
628
667
  const newItem = {
629
668
  json: {
630
669
  ...aggregatedItem.json,
@@ -632,6 +671,28 @@ class Gotenberg {
632
671
  operation,
633
672
  fileCount: totalFilesCount,
634
673
  processedItems: listData.length,
674
+ debug: {
675
+ processedFiles: processedFiles.map((f) => ({
676
+ binaryKey: f.binaryKey,
677
+ fileName: f.fileName,
678
+ fileSize: f.fileSize,
679
+ mimeType: f.mimeType,
680
+ listIndex: f.listIndex,
681
+ fileIndex: f.fileIndex,
682
+ hasData: f.hasData,
683
+ error: f.error,
684
+ })),
685
+ processingSteps: debugInfo.processingSteps,
686
+ aggregatedBinaryKeys: debugInfo.aggregatedItemBinaryKeys,
687
+ configuration: {
688
+ binaryPropertyName,
689
+ listPropertyName: listPropertyName || '(root array)',
690
+ },
691
+ },
692
+ pdfInfo: {
693
+ size: pdfBuffer.length,
694
+ isValid: pdfBuffer.length >= 4 && pdfBuffer.toString('ascii', 0, 4) === '%PDF',
695
+ },
635
696
  },
636
697
  binary: {
637
698
  ...aggregatedItem.binary,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n8n-nodes-sotoros-gotenberg",
3
- "version": "1.0.8",
3
+ "version": "1.0.10",
4
4
  "description": "n8n custom node for Gotenberg integration with binary data support",
5
5
  "keywords": [
6
6
  "n8n-community-node",