n8n-nodes-docx-filler 1.0.0 → 1.1.0

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.
package/README.md CHANGED
@@ -14,6 +14,7 @@ n8n community node to automatically fill DOCX documents (French DC1, DC2, AE adm
14
14
  - Automatic field detection (SIRET, TVA, email, address, etc.)
15
15
  - Checkbox state copying
16
16
  - Compatible with n8n AI Agents (`usableAsTool: true`)
17
+ - **Multiple input formats**: file path, binary property, or base64
17
18
 
18
19
  ## Installation
19
20
 
@@ -46,8 +47,8 @@ Fills a template document with data extracted from a source document.
46
47
 
47
48
  | Parameter | Description |
48
49
  |-----------|-------------|
49
- | `sourceDocument` | Document containing company data (binary property or base64) |
50
- | `templateDocument` | Empty template to fill (binary property or base64) |
50
+ | `sourceDocument` | Document containing company data |
51
+ | `templateDocument` | Empty template to fill |
51
52
  | `outputProperty` | Binary property name for output (default: "data") |
52
53
 
53
54
  ### Extract Data
@@ -56,7 +57,7 @@ Extracts company data from a filled document.
56
57
 
57
58
  | Parameter | Description |
58
59
  |-----------|-------------|
59
- | `document` | Document to analyze (binary property or base64) |
60
+ | `document` | Document to analyze |
60
61
 
61
62
  ### Analyze
62
63
 
@@ -66,6 +67,16 @@ Analyzes document structure for debugging.
66
67
  |-----------|-------------|
67
68
  | `document` | Document to analyze |
68
69
 
70
+ ### Input Formats
71
+
72
+ All document parameters accept **3 input formats** (auto-detected):
73
+
74
+ | Format | Example | Use Case |
75
+ |--------|---------|----------|
76
+ | **File path** | `/home/node/shared_docs/doc.docx` | AI Agents, direct file access |
77
+ | **Binary property** | `data` | Standard n8n workflow |
78
+ | **Base64** | `UEsDBBQAAAAI...` | Inline data |
79
+
69
80
  ## Supported Fields
70
81
 
71
82
  The node automatically recognizes these fields in French administrative documents:
@@ -82,19 +93,21 @@ The node automatically recognizes these fields in French administrative document
82
93
 
83
94
  ## Usage with AI Agent
84
95
 
85
- This node is compatible with n8n AI Agents.
96
+ This node is compatible with n8n AI Agents. You can pass **file paths directly** - no need for binary data handling.
86
97
 
87
98
  **Example agent prompt:**
88
99
  ```
89
100
  You have access to the DOCX Filler tool to fill documents.
90
101
 
91
102
  Use the "fill" operation with:
92
- - sourceDocument: the document containing company data
93
- - templateDocument: the empty form to fill
103
+ - sourceDocument: /home/node/shared_docs/company_data.docx
104
+ - templateDocument: /home/node/shared_docs/template_DC2.docx
94
105
 
95
106
  Execute directly without asking for confirmation.
96
107
  ```
97
108
 
109
+ > **Note**: When using file paths in Docker, ensure the directory is mounted and accessible from the container.
110
+
98
111
  ## Example Workflow
99
112
 
100
113
  ```
@@ -115,7 +128,7 @@ cd n8n-nodes-docx-filler
115
128
  # Install dependencies
116
129
  npm install
117
130
 
118
- # Build
131
+ # Build & | package.json Version 1.0.0 → 1.1.0
119
132
  npm run build
120
133
 
121
134
  # Watch mode
@@ -1,4 +1,37 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
2
35
  var __importDefault = (this && this.__importDefault) || function (mod) {
3
36
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
37
  };
@@ -6,6 +39,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
39
  exports.DocxFiller = void 0;
7
40
  const n8n_workflow_1 = require("n8n-workflow");
8
41
  const pizzip_1 = __importDefault(require("pizzip"));
42
+ const fs = __importStar(require("fs"));
9
43
  // Labels spécifiques à rechercher dans les documents DC/AE
10
44
  const LABEL_PATTERNS = [
11
45
  ['siret', ['numéro siret', 'n° siret', 'siret']],
@@ -224,6 +258,48 @@ function escapeXml(text) {
224
258
  .replace(/"/g, '&quot;')
225
259
  .replace(/'/g, '&apos;');
226
260
  }
261
+ /**
262
+ * Détecte le type d'entrée et retourne le buffer du document
263
+ * Supporte : chemin de fichier, nom de propriété binaire, ou base64
264
+ */
265
+ async function getDocumentBuffer(context, itemIndex, input, items) {
266
+ // 1. Vérifier si c'est un chemin de fichier (commence par / ou contient .docx)
267
+ const looksLikePath = input.startsWith('/') ||
268
+ input.startsWith('./') ||
269
+ input.startsWith('../') ||
270
+ /^[a-zA-Z]:\\/.test(input) || // Windows path
271
+ (input.includes('.docx') && !input.includes(' ') && input.length < 500);
272
+ if (looksLikePath) {
273
+ // Tenter de lire le fichier depuis le système de fichiers
274
+ try {
275
+ if (fs.existsSync(input)) {
276
+ return fs.readFileSync(input);
277
+ }
278
+ }
279
+ catch {
280
+ // Si la lecture échoue, continuer avec les autres méthodes
281
+ }
282
+ }
283
+ // 2. Vérifier si c'est un nom de propriété binaire
284
+ if (items[itemIndex].binary && items[itemIndex].binary[input]) {
285
+ return await context.helpers.getBinaryDataBuffer(itemIndex, input);
286
+ }
287
+ // 3. Vérifier si c'est du base64 valide (longueur raisonnable et caractères valides)
288
+ const base64Regex = /^[A-Za-z0-9+/]+=*$/;
289
+ if (input.length > 100 && base64Regex.test(input.replace(/\s/g, ''))) {
290
+ const buffer = Buffer.from(input, 'base64');
291
+ // Vérifier que c'est bien un ZIP (DOCX = ZIP)
292
+ if (buffer.length > 4 && buffer[0] === 0x50 && buffer[1] === 0x4B) {
293
+ return buffer;
294
+ }
295
+ }
296
+ // 4. Si rien n'a fonctionné, donner un message d'erreur clair
297
+ throw new Error(`Impossible de charger le document "${input.substring(0, 50)}..."\n` +
298
+ `Formats acceptés:\n` +
299
+ `- Chemin de fichier: /path/to/document.docx\n` +
300
+ `- Propriété binaire: data (si le fichier est attaché en binaire)\n` +
301
+ `- Base64: contenu encodé en base64`);
302
+ }
227
303
  class DocxFiller {
228
304
  constructor() {
229
305
  this.description = {
@@ -281,7 +357,7 @@ class DocxFiller {
281
357
  operation: ['fill'],
282
358
  },
283
359
  },
284
- description: 'Document source contenant les données entreprise (binary property name ou base64)',
360
+ description: 'Document source contenant les données entreprise (chemin fichier, binary property name, ou base64)',
285
361
  },
286
362
  {
287
363
  displayName: 'Template Document',
@@ -294,7 +370,7 @@ class DocxFiller {
294
370
  operation: ['fill'],
295
371
  },
296
372
  },
297
- description: 'Document template vide à remplir (binary property name ou base64)',
373
+ description: 'Document template vide à remplir (chemin fichier, binary property name, ou base64)',
298
374
  },
299
375
  {
300
376
  displayName: 'Output Property',
@@ -320,7 +396,7 @@ class DocxFiller {
320
396
  operation: ['extract', 'analyze'],
321
397
  },
322
398
  },
323
- description: 'Document à analyser (binary property name ou base64)',
399
+ description: 'Document à analyser (chemin fichier, binary property name, ou base64)',
324
400
  },
325
401
  ],
326
402
  };
@@ -336,25 +412,9 @@ class DocxFiller {
336
412
  const sourceDocParam = this.getNodeParameter('sourceDocument', i);
337
413
  const templateDocParam = this.getNodeParameter('templateDocument', i);
338
414
  const outputProperty = this.getNodeParameter('outputProperty', i);
339
- // Charger les documents (depuis binary ou base64)
340
- let sourceBuffer;
341
- let templateBuffer;
342
- // Source document
343
- if (items[i].binary && items[i].binary[sourceDocParam]) {
344
- sourceBuffer = await this.helpers.getBinaryDataBuffer(i, sourceDocParam);
345
- }
346
- else {
347
- // Assume base64
348
- sourceBuffer = Buffer.from(sourceDocParam, 'base64');
349
- }
350
- // Template document
351
- if (items[i].binary && items[i].binary[templateDocParam]) {
352
- templateBuffer = await this.helpers.getBinaryDataBuffer(i, templateDocParam);
353
- }
354
- else {
355
- // Assume base64
356
- templateBuffer = Buffer.from(templateDocParam, 'base64');
357
- }
415
+ // Charger les documents (depuis chemin, binary ou base64)
416
+ const sourceBuffer = await getDocumentBuffer(this, i, sourceDocParam, items);
417
+ const templateBuffer = await getDocumentBuffer(this, i, templateDocParam, items);
358
418
  // Charger les DOCX avec PizZip
359
419
  const sourceZip = new pizzip_1.default(sourceBuffer);
360
420
  const templateZip = new pizzip_1.default(templateBuffer);
@@ -392,13 +452,7 @@ class DocxFiller {
392
452
  }
393
453
  else if (operation === 'extract') {
394
454
  const documentParam = this.getNodeParameter('document', i);
395
- let docBuffer;
396
- if (items[i].binary && items[i].binary[documentParam]) {
397
- docBuffer = await this.helpers.getBinaryDataBuffer(i, documentParam);
398
- }
399
- else {
400
- docBuffer = Buffer.from(documentParam, 'base64');
401
- }
455
+ const docBuffer = await getDocumentBuffer(this, i, documentParam, items);
402
456
  const zip = new pizzip_1.default(docBuffer);
403
457
  const xml = ((_c = zip.file('word/document.xml')) === null || _c === void 0 ? void 0 : _c.asText()) || '';
404
458
  const paragraphs = extractParagraphs(xml);
@@ -423,13 +477,7 @@ class DocxFiller {
423
477
  }
424
478
  else if (operation === 'analyze') {
425
479
  const documentParam = this.getNodeParameter('document', i);
426
- let docBuffer;
427
- if (items[i].binary && items[i].binary[documentParam]) {
428
- docBuffer = await this.helpers.getBinaryDataBuffer(i, documentParam);
429
- }
430
- else {
431
- docBuffer = Buffer.from(documentParam, 'base64');
432
- }
480
+ const docBuffer = await getDocumentBuffer(this, i, documentParam, items);
433
481
  const zip = new pizzip_1.default(docBuffer);
434
482
  const xml = ((_d = zip.file('word/document.xml')) === null || _d === void 0 ? void 0 : _d.asText()) || '';
435
483
  const paragraphs = extractParagraphs(xml);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n8n-nodes-docx-filler",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "n8n node to automatically fill DOCX documents (French DC1, DC2, AE forms) with company data. Works as AI Agent tool.",
5
5
  "keywords": [
6
6
  "n8n-community-node-package",