{
  "name": "ezGPT - Base64 to File",
  "active": false,
  "nodes": [
    {
      "id": "trigger",
      "name": "Manual Trigger",
      "type": "n8n-nodes-base.manualTrigger",
      "typeVersion": 1,
      "position": [
        200,
        300
      ],
      "parameters": {}
    },
    {
      "id": "sample",
      "name": "Sample Response",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        420,
        300
      ],
      "parameters": {
        "mode": "runOnceForAllItems",
        "jsCode": "return [{ json: {\n  file_name: 'base64-demo.txt',\n  mime_type: 'text/plain',\n  file_base64: '0J/RgNC40LLQtdGCLCBuOG4hCg==',\n} }];"
      }
    },
    {
      "id": "validate",
      "name": "Check Base64",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        640,
        300
      ],
      "parameters": {
        "mode": "runOnceForAllItems",
        "jsCode": "const items = $input.all();\nif (items.length !== 1) throw new Error('Expected one response');\nconst row = items[0].json;\nif (Object.keys(row).sort().join('|') !== 'file_base64|file_name|mime_type' ||\n    row.file_name !== 'base64-demo.txt' || row.mime_type !== 'text/plain') {\n  throw new Error('Unexpected fields, filename or MIME');\n}\nconst value = row.file_base64;\nif (typeof value !== 'string' || value.length === 0 || value.length > 5464 ||\n    !/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(value)) {\n  throw new Error('Expected standard padded Base64 without spaces or prefix');\n}\nconst bytes = Buffer.from(value, 'base64');\nif (bytes.length < 1 || bytes.length > 4096 || bytes.toString('base64') !== value) {\n  throw new Error('Invalid size or noncanonical Base64');\n}\nconst text = bytes.toString('utf8');\nif (!Buffer.from(text, 'utf8').equals(bytes) || !text.trim() ||\n    text.charCodeAt(0) === 0xFEFF || text.includes('\\u0000')) {\n  throw new Error('Expected nonempty UTF-8 text without BOM or NUL');\n}\nreturn [{ json: {\n  file_name: row.file_name, mime_type: row.mime_type, file_base64: value,\n} }];"
      }
    },
    {
      "id": "make-file",
      "name": "Make File",
      "type": "n8n-nodes-base.convertToFile",
      "typeVersion": 1.1,
      "position": [
        860,
        300
      ],
      "parameters": {
        "operation": "toBinary",
        "sourceProperty": "file_base64",
        "binaryPropertyName": "document",
        "options": {
          "fileName": "base64-demo.txt",
          "mimeType": "text/plain",
          "addBOM": false
        }
      }
    },
    {
      "id": "check-file",
      "name": "Check File",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1080,
        300
      ],
      "parameters": {
        "mode": "runOnceForAllItems",
        "jsCode": "const items = $input.all();\nif (items.length !== 1 || Object.keys(items[0].binary ?? {}).join('|') !== 'document') {\n  throw new Error('Expected one file in binary.document');\n}\nconst item = items[0];\nconst source = $('Check Base64').first().json;\nconst file = item.binary.document;\nif (file.fileName !== source.file_name || file.mimeType !== source.mime_type) {\n  throw new Error('Filename or MIME changed');\n}\nconst bytes = await this.helpers.getBinaryDataBuffer(0, 'document');\nif (bytes.toString('base64') !== source.file_base64) {\n  throw new Error('File bytes differ from the Base64 input');\n}\nreturn [{ json: { bytes: bytes.length }, binary: { document: file } }];"
      }
    },
    {
      "id": "read-text",
      "name": "Read Text",
      "type": "n8n-nodes-base.extractFromFile",
      "typeVersion": 1.1,
      "position": [
        1300,
        300
      ],
      "parameters": {
        "operation": "text",
        "binaryPropertyName": "document",
        "destinationKey": "text",
        "options": {
          "encoding": "utf8",
          "stripBOM": true,
          "keepSource": "both"
        }
      }
    },
    {
      "id": "verify",
      "name": "Verify File",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1520,
        300
      ],
      "parameters": {
        "mode": "runOnceForAllItems",
        "jsCode": "const item = $input.first();\nconst source = $('Check Base64').first().json;\nconst expected = Buffer.from(source.file_base64, 'base64').toString('utf8');\nif (typeof item.json.text !== 'string' || item.json.text !== expected ||\n    item.json.bytes !== Buffer.byteLength(expected, 'utf8') || !item.binary?.document) {\n  throw new Error('Read text, metadata or binary differs');\n}\nreturn [{\n  json: {\n    file_name: source.file_name, bytes: item.json.bytes,\n    text: item.json.text, verified: true, action: false,\n  },\n  binary: { document: item.binary.document },\n}];"
      }
    }
  ],
  "connections": {
    "Manual Trigger": {
      "main": [
        [
          {
            "node": "Sample Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Sample Response": {
      "main": [
        [
          {
            "node": "Check Base64",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check Base64": {
      "main": [
        [
          {
            "node": "Make File",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Make File": {
      "main": [
        [
          {
            "node": "Check File",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check File": {
      "main": [
        [
          {
            "node": "Read Text",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Read Text": {
      "main": [
        [
          {
            "node": "Verify File",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1"
  },
  "pinData": {}
}
