n8n-nodes-filemanager
Version:
Manage files and folders on disk with create, copy, move, remove, and rename operations for n8n workflows
445 lines • 20.9 kB
JavaScript
"use strict";
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.FileManager = void 0;
const n8n_workflow_1 = require("n8n-workflow");
const fs_1 = require("fs");
const path = __importStar(require("path"));
const child_process_1 = require("child_process");
const zlib_1 = require("zlib");
class FileManager {
constructor() {
this.description = {
displayName: 'File Manager',
name: 'fileManager',
icon: 'fa:folder-open',
group: ['transform'],
version: 1,
usableAsTool: true,
description: 'Manage files and folders on disk',
defaults: { name: 'File Manager' },
inputs: ["main"],
outputs: ["main"],
properties: [
{
displayName: 'Operation',
name: 'operation',
type: 'options',
noDataExpression: true,
options: [
{ name: 'Append', value: 'append' },
{ name: 'Change Permissions', value: 'chmod' },
{ name: 'Compress', value: 'compress' },
{ name: 'Copy', value: 'copy' },
{ name: 'Create', value: 'create' },
{ name: 'Exists', value: 'exists' },
{ name: 'Extract', value: 'extract' },
{ name: 'List', value: 'list' },
{ name: 'Metadata', value: 'metadata' },
{ name: 'Move', value: 'move' },
{ name: 'Read', value: 'read' },
{ name: 'Remove', value: 'remove' },
{ name: 'Rename', value: 'rename' },
{ name: 'Search', value: 'search' },
{ name: 'Write', value: 'write' },
],
default: 'remove',
},
{
displayName: 'Source Path',
name: 'sourcePath',
type: 'string',
default: '',
placeholder: '/path/to/source',
description: 'Path of the source file or folder',
required: true,
},
{
displayName: 'Destination Path',
name: 'destinationPath',
type: 'string',
default: '',
placeholder: '/path/to/destination',
description: 'Target path for copy, move, rename, compress, and extract operations',
required: true,
displayOptions: {
show: {
operation: ['compress', 'copy', 'extract', 'move', 'rename'],
},
},
},
{
displayName: 'Recursive',
name: 'recursive',
type: 'boolean',
default: true,
description: 'Whether to delete folders recursively',
displayOptions: {
show: {
operation: ['remove'],
},
},
},
{
displayName: 'Target Path',
name: 'targetPath',
type: 'string',
default: '',
placeholder: '/path/to/target',
description: 'Path of the file or folder to operate on',
required: true,
displayOptions: {
show: {
operation: ['read', 'write', 'append', 'list', 'exists', 'metadata', 'chmod'],
},
},
},
{
displayName: 'Data',
name: 'data',
type: 'string',
default: '',
description: 'Content to write or append to the file',
displayOptions: {
show: {
operation: ['write', 'append'],
},
},
},
{
displayName: 'Encoding',
name: 'encoding',
type: 'string',
default: 'utf8',
description: 'File encoding',
displayOptions: {
show: {
operation: ['read', 'write', 'append'],
},
},
},
{
displayName: 'Mode',
name: 'mode',
type: 'number',
default: 0o644,
description: 'Unix permission bits, e.g. 644',
displayOptions: {
show: {
operation: ['chmod'],
},
},
},
{
displayName: 'Base Path',
name: 'basePath',
type: 'string',
default: '',
placeholder: '/start/path',
description: 'Directory to start searching from',
required: true,
displayOptions: {
show: {
operation: ['search'],
},
},
},
{
displayName: 'Pattern',
name: 'pattern',
type: 'string',
default: '',
placeholder: '.*\\.txt$',
description: 'Regex pattern to match file paths',
required: true,
displayOptions: {
show: {
operation: ['search'],
},
},
},
],
};
}
async execute() {
const inputItems = this.getInputData();
const returnItems = [];
for (let i = 0; i < inputItems.length; i++) {
try {
const operation = this.getNodeParameter('operation', i);
switch (operation) {
case 'remove': {
const sourcePath = this.getNodeParameter('sourcePath', i);
let isDir = false;
try {
const stats = await fs_1.promises.lstat(sourcePath);
isDir = stats.isDirectory();
}
catch {
isDir = false;
}
if (isDir) {
const recursive = this.getNodeParameter('recursive', i);
if (recursive) {
await fs_1.promises.rm(sourcePath, { recursive: true, force: true });
}
else {
await fs_1.promises.rmdir(sourcePath);
}
}
else {
await fs_1.promises.unlink(sourcePath);
}
break;
}
case 'copy': {
const sourcePath = this.getNodeParameter('sourcePath', i);
const destinationPath = this.getNodeParameter('destinationPath', i);
let isDir = false;
try {
const stats = await fs_1.promises.lstat(sourcePath);
isDir = stats.isDirectory();
}
catch {
isDir = false;
}
if (isDir) {
const copyDirectory = async (src, dest) => {
await fs_1.promises.mkdir(dest, { recursive: true });
const entries = await fs_1.promises.readdir(src, { withFileTypes: true });
for (const entry of entries) {
const srcPath = path.join(src, entry.name);
const destPath = path.join(dest, entry.name);
if (entry.isDirectory()) {
await copyDirectory(srcPath, destPath);
}
else if (entry.isSymbolicLink()) {
const symlink = await fs_1.promises.readlink(srcPath);
await fs_1.promises.symlink(symlink, destPath);
}
else {
await fs_1.promises.copyFile(srcPath, destPath);
}
}
};
await copyDirectory(sourcePath, destinationPath);
}
else {
await fs_1.promises.copyFile(sourcePath, destinationPath);
}
break;
}
case 'move': {
const sourcePath = this.getNodeParameter('sourcePath', i);
const destinationPath = this.getNodeParameter('destinationPath', i);
await fs_1.promises.rename(sourcePath, destinationPath);
break;
}
case 'compress': {
const sourcePath = this.getNodeParameter('sourcePath', i);
const destinationPath = this.getNodeParameter('destinationPath', i);
await new Promise((resolve, reject) => {
const tar = (0, child_process_1.spawn)('tar', ['-czf', destinationPath, path.basename(sourcePath)], {
cwd: path.dirname(sourcePath),
});
tar.on('error', reject);
tar.on('close', (code) => {
if (code !== 0)
reject(new Error(`tar exited with code ${code}`));
else
resolve();
});
});
break;
}
case 'extract': {
const sourcePath = this.getNodeParameter('sourcePath', i);
const destinationPath = this.getNodeParameter('destinationPath', i);
await fs_1.promises.mkdir(destinationPath, { recursive: true });
await new Promise((resolve, reject) => {
const input = (0, fs_1.createReadStream)(sourcePath);
const gunzip = (0, zlib_1.createGunzip)();
const tar = (0, child_process_1.spawn)('tar', ['-xf', '-', '-C', destinationPath]);
tar.on('error', reject);
tar.on('close', (code) => {
if (code !== 0)
reject(new Error(`tar exited with code ${code}`));
else
resolve();
});
input.pipe(gunzip).pipe(tar.stdin).on('error', reject);
});
break;
}
case 'create': {
const sourcePath = this.getNodeParameter('sourcePath', i);
const ext = path.extname(sourcePath);
if (ext) {
await fs_1.promises.writeFile(sourcePath, '', 'utf8');
}
else {
await fs_1.promises.mkdir(sourcePath, { recursive: true });
}
break;
}
case 'rename': {
const sourcePath = this.getNodeParameter('sourcePath', i);
const destinationPath = this.getNodeParameter('destinationPath', i);
await fs_1.promises.rename(sourcePath, destinationPath);
break;
}
case 'read': {
const targetPath = this.getNodeParameter('targetPath', i);
const encoding = this.getNodeParameter('encoding', i);
const data = await fs_1.promises.readFile(targetPath, { encoding });
inputItems[i].json.data = data;
inputItems[i].json.targetPath = targetPath;
break;
}
case 'write': {
const targetPath = this.getNodeParameter('targetPath', i);
const content = this.getNodeParameter('data', i);
const encoding = this.getNodeParameter('encoding', i);
await fs_1.promises.writeFile(targetPath, content, { encoding });
inputItems[i].json.targetPath = targetPath;
break;
}
case 'append': {
const targetPath = this.getNodeParameter('targetPath', i);
const content = this.getNodeParameter('data', i);
const encoding = this.getNodeParameter('encoding', i);
await fs_1.promises.appendFile(targetPath, content, { encoding });
inputItems[i].json.targetPath = targetPath;
break;
}
case 'chmod': {
const targetPath = this.getNodeParameter('targetPath', i);
const mode = this.getNodeParameter('mode', i);
await fs_1.promises.chmod(targetPath, mode);
inputItems[i].json.targetPath = targetPath;
inputItems[i].json.mode = mode;
break;
}
case 'list': {
const targetPath = this.getNodeParameter('targetPath', i);
const files = await fs_1.promises.readdir(targetPath);
inputItems[i].json.list = files;
inputItems[i].json.targetPath = targetPath;
break;
}
case 'exists': {
const targetPath = this.getNodeParameter('targetPath', i);
let exists = true;
try {
await fs_1.promises.access(targetPath);
}
catch {
exists = false;
}
inputItems[i].json.exists = exists;
inputItems[i].json.targetPath = targetPath;
break;
}
case 'metadata': {
const targetPath = this.getNodeParameter('targetPath', i);
const stats = await fs_1.promises.lstat(targetPath);
inputItems[i].json.size = stats.size;
inputItems[i].json.mtime = stats.mtime;
inputItems[i].json.atime = stats.atime;
inputItems[i].json.isDirectory = stats.isDirectory();
inputItems[i].json.isFile = stats.isFile();
inputItems[i].json.targetPath = targetPath;
break;
}
case 'search': {
const basePath = this.getNodeParameter('basePath', i);
const pattern = this.getNodeParameter('pattern', i);
const regex = new RegExp(pattern);
const matches = [];
const walk = async (dir) => {
const entries = await fs_1.promises.readdir(dir, { withFileTypes: true });
for (const entry of entries) {
const full = path.join(dir, entry.name);
if (regex.test(full))
matches.push(full);
if (entry.isDirectory())
await walk(full);
}
};
await walk(basePath);
inputItems[i].json.paths = matches;
inputItems[i].json.basePath = basePath;
break;
}
default:
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Unknown operation "${operation}"`);
}
inputItems[i].json.operation = operation;
inputItems[i].json.success = true;
if (['compress', 'copy', 'extract', 'move', 'rename', 'remove', 'create'].includes(operation)) {
inputItems[i].json.sourcePath = this.getNodeParameter('sourcePath', i);
}
if (['compress', 'copy', 'extract', 'move', 'rename'].includes(operation)) {
inputItems[i].json.destinationPath = this.getNodeParameter('destinationPath', i);
}
if (['read', 'write', 'append', 'list', 'exists', 'metadata', 'chmod'].includes(operation)) {
inputItems[i].json.targetPath = this.getNodeParameter('targetPath', i);
}
if (operation === 'search') {
inputItems[i].json.basePath = this.getNodeParameter('basePath', i);
inputItems[i].json.pattern = this.getNodeParameter('pattern', i);
}
returnItems.push(inputItems[i]);
}
catch (error) {
if (this.continueOnFail()) {
returnItems.push({
json: inputItems[i].json,
error,
pairedItem: i,
});
continue;
}
if (error instanceof n8n_workflow_1.NodeOperationError) {
throw error;
}
throw new n8n_workflow_1.NodeOperationError(this.getNode(), error, { itemIndex: i });
}
}
return [returnItems];
}
}
exports.FileManager = FileManager;
//# sourceMappingURL=FileManager.node.js.map