Add Activepieces integration for workflow automation

- Add Activepieces fork with SmoothSchedule custom piece
- Create integrations app with Activepieces service layer
- Add embed token endpoint for iframe integration
- Create Automations page with embedded workflow builder
- Add sidebar visibility fix for embed mode
- Add list inactive customers endpoint to Public API
- Include SmoothSchedule triggers: event created/updated/cancelled
- Include SmoothSchedule actions: create/update/cancel events, list resources/services/customers

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
poduck
2025-12-18 22:59:37 -05:00
parent 9848268d34
commit 3aa7199503
16292 changed files with 1284892 additions and 4708 deletions

View File

@@ -0,0 +1,18 @@
{
"extends": ["../../../../.eslintrc.json"],
"ignorePatterns": ["!**/*"],
"overrides": [
{
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
"rules": {}
},
{
"files": ["*.ts", "*.tsx"],
"rules": {}
},
{
"files": ["*.js", "*.jsx"],
"rules": {}
}
]
}

View File

@@ -0,0 +1,7 @@
# pieces-sftp
This library was generated with [Nx](https://nx.dev).
## Running lint
Run `nx lint pieces-sftp` to execute the lint via [ESLint](https://eslint.org/).

View File

@@ -0,0 +1,8 @@
{
"name": "@activepieces/piece-sftp",
"version": "0.4.4",
"dependencies": {
"basic-ftp": "5.0.5",
"ssh2-sftp-client": "9.1.0"
}
}

View File

@@ -0,0 +1,51 @@
{
"name": "pieces-sftp",
"$schema": "../../../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "packages/pieces/community/sftp/src",
"projectType": "library",
"targets": {
"build": {
"executor": "@nx/js:tsc",
"outputs": [
"{options.outputPath}"
],
"options": {
"outputPath": "dist/packages/pieces/community/sftp",
"tsConfig": "packages/pieces/community/sftp/tsconfig.lib.json",
"packageJson": "packages/pieces/community/sftp/package.json",
"main": "packages/pieces/community/sftp/src/index.ts",
"assets": [
"packages/pieces/community/sftp/*.md",
{
"input": "packages/pieces/community/sftp/src/i18n",
"output": "./src/i18n",
"glob": "**/!(i18n.json)"
}
],
"buildableProjectDepsInPackageJsonType": "dependencies",
"updateBuildableProjectDepsInPackageJson": true
},
"dependsOn": [
"^build",
"prebuild"
]
},
"lint": {
"executor": "@nx/eslint:lint",
"outputs": [
"{options.outputFile}"
]
},
"prebuild": {
"executor": "nx:run-commands",
"options": {
"cwd": "packages/pieces/community/sftp",
"command": "bun install --no-save --silent"
},
"dependsOn": [
"^build"
]
}
},
"tags": []
}

View File

@@ -0,0 +1,69 @@
{
"Connect to FTP, FTPS or SFTP servers": "Mit FTP, FTPS oder SFTP-Servern verbinden",
"Protocol": "Protocol",
"Allow Unauthorized Certificates": "Nicht autorisierte Zertifikate erlauben",
"Host": "Host",
"Port": "Port",
"Username": "Benutzername",
"Password": "Kennwort",
"Private Key": "Privater Schlüssel",
"Host Key Algorithm": "Hostschlüssel-Algorithmus",
"The protocol to use": "Das zu verwendende Protokoll",
"Allow connections to servers with self-signed certificates": "Verbindungen zu Servern mit selbstsignierten Zertifikaten erlauben",
"The host of the server": "Der Host des Servers",
"The port of the server": "Der Port des Servers",
"The username to authenticate with": "Benutzername für Authentifizierung",
"The password to authenticate with. Either this or private key is required": "Das Passwort, mit dem sich authentifizieren soll. Entweder dieser oder der private Schlüssel ist erforderlich",
"The private key to authenticate with. Either this or password is required": "Der private Schlüssel für die Authentifizierung erforderlich ist. Entweder dieser oder das Passwort ist erforderlich",
"The host key algorithm to use for SFTP Private Key authentication": "Der Hostschlüssel-Algorithmus für die SFTP Private Key Authentifizierung",
"SFTP": "SFTP",
"FTP": "FTP",
"FTPS": "FTPS",
"ssh-rsa": "ssh-rsa",
"ssh-dss": "ssh-dss",
"ecdsa-sha2-nistp256": "ecdsa-sha2-nistp256",
"ecdsa-sha2-nistp384": "ecdsa-sha2-nistp384",
"ecdsa-sha2-nistp521": "ecdsa-sha2-nistp521",
"ssh-ed25519": "ssh-ed25519",
"rsa-sha2-256": "rsa-sha2-256",
"rsa-sha2-512": "rsa-sha2-512",
"Create File from Text": "Datei aus Text erstellen",
"Upload File": "Datei hochladen",
"Read File Content": "Dateiinhalt lesen",
"Delete file": "Datei löschen",
"Create Folder": "Ordner erstellen",
"Delete Folder": "Ordner löschen",
"List Folder Contents": "Ordnerinhalte auflisten",
"Rename File or Folder": "Datei oder Ordner umbenennen",
"Create a new file in the given path": "Erstelle eine neue Datei im angegebenen Pfad",
"Upload a file to the given path.": "Laden Sie eine Datei in den angegebenen Pfad hoch.",
"Read the content of a file.": "Lesen Sie den Inhalt einer Datei.",
"Deletes a file at given path.": "Löscht eine Datei am angegebenen Pfad.",
"Creates a folder at given path.": "Erstellt einen Ordner am angegebenen Pfad.",
"Deletes an existing folder at given path.": "Löscht einen existierenden Ordner am angegebenen Pfad.",
"Lists the contents of a given folder.": "Listet den Inhalt eines Ordners auf.",
"Renames a file or folder at given path.": "Benennt eine Datei oder einen Ordner im angegebenen Pfad um.",
"File Path": "Dateipfad",
"File content": "Dateiinhalt",
"Folder Path": "Ordnerpfad",
"Recursive": "Rekursiv",
"Directory Path": "Verzeichnispfad",
"Markdown": "Markdown",
"Old Path": "Alter Pfad",
"New Path": "Neuer Pfad",
"The path on the sftp server to store the file. e.g. `./myfolder/test.mp3`": "Der Pfad auf dem sftp-Server, um die Datei zu speichern. z.B. `./myfolder/test.mp3`",
"The path of the file to delete e.g. `./myfolder/test.mp3`": "Der Pfad der zu löschenden Datei, z.B. `./myfolder/test.mp3`",
"The new folder path e.g. `./myfolder`. For FTP/FTPS, it will create nested folders if necessary.": "Der neue Ordnerpfad z.B. `./myfolder`. Für FTP/FTPS wird er verschachtelte Ordner erstellen, falls nötig.",
"For SFTP only: Create parent directories if they do not exist": "Nur für SFTP: Erstelle übergeordnete Verzeichnisse, wenn diese nicht existieren",
"The path of the folder to delete e.g. `./myfolder`": "Der Pfad des zu löschenden Ordners, z.B. `./myfolder`",
"Enable this option to delete the folder and all its contents, including subfolders and files.": "Aktivieren Sie diese Option, um den Ordner und den gesamten Inhalt zu löschen, einschließlich Unterordner und Dateien.",
"The path of the folder to list e.g. `./myfolder`": "Der Pfad des Ordners zur Liste z.B. `./myfolder`",
"Depending on the server you can also use this to move a file to another directory, as long as the directory exists.": "Abhängig vom Server können Sie diese auch verwenden, um eine Datei in ein anderes Verzeichnis zu verschieben, solange das Verzeichnis existiert.",
"The path of the file or folder to rename e.g. `./myfolder/test.mp3`": "Der Pfad der Datei oder des Ordners, der umbenannt werden soll, z.B. `./myfolder/test.mp3`",
"The new path of the file or folder e.g. `./myfolder/new-name.mp3`": "Der neue Pfad der Datei oder des Ordners z.B. `./myfolder/new-name.mp3`",
"New File": "Neue Datei",
"Trigger when a new file is created or modified.": "Wird ausgelöst, wenn eine neue Datei erstellt oder geändert wird.",
"Path": "Pfad",
"Ignore hidden files": "Versteckte Dateien ignorieren",
"The path to watch for new files": "Der Pfad für neue Dateien"
}

View File

@@ -0,0 +1,69 @@
{
"Connect to FTP, FTPS or SFTP servers": "Conectar a servidores FTP, FTPS o SFTP",
"Protocol": "Protocol",
"Allow Unauthorized Certificates": "Permitir certificados no autorizados",
"Host": "Anfitrión",
"Port": "Puerto",
"Username": "Usuario",
"Password": "Contraseña",
"Private Key": "Clave Privada",
"Host Key Algorithm": "Algoritmo de clave de host",
"The protocol to use": "El protocolo a usar",
"Allow connections to servers with self-signed certificates": "Permitir conexiones a servidores con certificados autofirmados",
"The host of the server": "El host del servidor",
"The port of the server": "El puerto del servidor",
"The username to authenticate with": "El nombre de usuario con el que autenticar",
"The password to authenticate with. Either this or private key is required": "La contraseña con la que autenticarse. Se requiere esta o la clave privada",
"The private key to authenticate with. Either this or password is required": "La clave privada con la que autenticarse. O esto o la contraseña es necesaria",
"The host key algorithm to use for SFTP Private Key authentication": "El algoritmo de clave de host a usar para autenticación de clave privada SFTP",
"SFTP": "SFTP",
"FTP": "FTP",
"FTPS": "FTPS",
"ssh-rsa": "ssh-rsa",
"ssh-dss": "ssh-d(debate)",
"ecdsa-sha2-nistp256": "ecdsa-sha2-nistp256",
"ecdsa-sha2-nistp384": "ecdsa-sha2-nistp384",
"ecdsa-sha2-nistp521": "ecdsa-sha2-nistp521",
"ssh-ed25519": "ssh-ed25519",
"rsa-sha2-256": "rsa-sha2-256",
"rsa-sha2-512": "rsa-sha2-512",
"Create File from Text": "Crear archivo desde texto",
"Upload File": "Subir archivo",
"Read File Content": "Leer contenido del archivo",
"Delete file": "Eliminar archivo",
"Create Folder": "Crear carpeta",
"Delete Folder": "Eliminar carpeta",
"List Folder Contents": "Listar contenido de carpeta",
"Rename File or Folder": "Renombrar archivo o carpeta",
"Create a new file in the given path": "Crear un nuevo archivo en la ruta dada",
"Upload a file to the given path.": "Subir un archivo a la ruta dada.",
"Read the content of a file.": "Leer el contenido de un archivo.",
"Deletes a file at given path.": "Elimina un archivo en una ruta determinada.",
"Creates a folder at given path.": "Crea una carpeta en una ruta determinada.",
"Deletes an existing folder at given path.": "Elimina una carpeta existente en una ruta determinada.",
"Lists the contents of a given folder.": "Muestra el contenido de una carpeta determinada.",
"Renames a file or folder at given path.": "Renombrar un archivo o carpeta en una ruta determinada.",
"File Path": "Ruta del archivo",
"File content": "Contenido del archivo",
"Folder Path": "Ruta de la carpeta",
"Recursive": "Recursivo",
"Directory Path": "Ruta del directorio",
"Markdown": "Markdown",
"Old Path": "Ruta antigua",
"New Path": "Nueva ruta",
"The path on the sftp server to store the file. e.g. `./myfolder/test.mp3`": "La ruta en el servidor sftp para almacenar el archivo. ej. `./myfolder/test.mp3`",
"The path of the file to delete e.g. `./myfolder/test.mp3`": "La ruta del archivo a eliminar, p. ej., `./myfolder/test.mp3`",
"The new folder path e.g. `./myfolder`. For FTP/FTPS, it will create nested folders if necessary.": "La nueva ruta de la carpeta, p. ej., `./myfolder`. Para FTP/FTPS, creará carpetas anidadas si es necesario.",
"For SFTP only: Create parent directories if they do not exist": "Sólo para SFTP: Crear directorios padre si no existen",
"The path of the folder to delete e.g. `./myfolder`": "La ruta de la carpeta a eliminar, p. ej., `./myfolder`",
"Enable this option to delete the folder and all its contents, including subfolders and files.": "Active esta opción para eliminar la carpeta y todo su contenido, incluyendo subcarpetas y archivos.",
"The path of the folder to list e.g. `./myfolder`": "La ruta de la carpeta a listar, p. ej., `./myfolder`",
"Depending on the server you can also use this to move a file to another directory, as long as the directory exists.": "Dependiendo del servidor también puede usar esto para mover un archivo a otro directorio, siempre y cuando el directorio existe.",
"The path of the file or folder to rename e.g. `./myfolder/test.mp3`": "La ruta del archivo o carpeta a renombrar, p. ej., `./myfolder/test.mp3`",
"The new path of the file or folder e.g. `./myfolder/new-name.mp3`": "La nueva ruta del archivo o carpeta p. ej. `./myfolder/new-name.mp3`",
"New File": "Nuevo archivo",
"Trigger when a new file is created or modified.": "Activar cuando se crea o modifica un nuevo archivo.",
"Path": "Ruta",
"Ignore hidden files": "Ignorar archivos ocultos",
"The path to watch for new files": "La ruta para ver nuevos archivos"
}

View File

@@ -0,0 +1,69 @@
{
"Connect to FTP, FTPS or SFTP servers": "Se connecter aux serveurs FTP, FTPS ou SFTP",
"Protocol": "Protocol",
"Allow Unauthorized Certificates": "Autoriser les certificats non autorisés",
"Host": "Hôte",
"Port": "Port",
"Username": "Nom d'utilisateur",
"Password": "Password",
"Private Key": "Clé privée",
"Host Key Algorithm": "Algorithme de clé d'hôte",
"The protocol to use": "Le protocole à utiliser",
"Allow connections to servers with self-signed certificates": "Autoriser les connexions aux serveurs avec des certificats auto-signés",
"The host of the server": "L'hôte du serveur",
"The port of the server": "Le port du serveur",
"The username to authenticate with": "Le nom d'utilisateur avec lequel s'authentifier",
"The password to authenticate with. Either this or private key is required": "Le mot de passe pour s'authentifier. Cette clé ou privée est requise",
"The private key to authenticate with. Either this or password is required": "La clé privée avec laquelle s'authentifier. Soit ceci ou le mot de passe est requis",
"The host key algorithm to use for SFTP Private Key authentication": "L'algorithme de clé d'hôte à utiliser pour l'authentification de la clé privée SFTP",
"SFTP": "SFTP",
"FTP": "FTP",
"FTPS": "FTPS",
"ssh-rsa": "ssh-rsa",
"ssh-dss": "ssh-dss",
"ecdsa-sha2-nistp256": "ecdsa-sha2-nistp256",
"ecdsa-sha2-nistp384": "ecdsa-sha2-nistp384",
"ecdsa-sha2-nistp521": "ecdsa-sha2-nistp521",
"ssh-ed25519": "ssh-ed25519",
"rsa-sha2-256": "rsa-sha2-256",
"rsa-sha2-512": "rsa-sha2-512",
"Create File from Text": "Créer un fichier à partir du texte",
"Upload File": "Charger un fichier",
"Read File Content": "Lire le contenu du fichier",
"Delete file": "Supprimer le fichier",
"Create Folder": "Créer un dossier",
"Delete Folder": "Supprimer le dossier",
"List Folder Contents": "Contenu du dossier de liste",
"Rename File or Folder": "Renommer le fichier ou le dossier",
"Create a new file in the given path": "Créer un nouveau fichier dans le chemin donné",
"Upload a file to the given path.": "Télécharger un fichier dans le chemin donné.",
"Read the content of a file.": "Lit le contenu d'un fichier.",
"Deletes a file at given path.": "Supprime un fichier à un chemin donné.",
"Creates a folder at given path.": "Crée un dossier à un chemin donné.",
"Deletes an existing folder at given path.": "Supprime un dossier existant à un chemin donné.",
"Lists the contents of a given folder.": "Liste le contenu d'un dossier donné.",
"Renames a file or folder at given path.": "Renomme un fichier ou un dossier à un chemin donné.",
"File Path": "Chemin du fichier",
"File content": "Contenu du fichier",
"Folder Path": "Chemin du dossier",
"Recursive": "Récursif",
"Directory Path": "Chemin du répertoire",
"Markdown": "Markdown",
"Old Path": "Ancien chemin",
"New Path": "Nouveau chemin",
"The path on the sftp server to store the file. e.g. `./myfolder/test.mp3`": "Le chemin sur le serveur sftp pour stocker le fichier. Par exemple `./myfolder/test.mp3`",
"The path of the file to delete e.g. `./myfolder/test.mp3`": "Le chemin du fichier à supprimer, par exemple `./myfolder/test.mp3`",
"The new folder path e.g. `./myfolder`. For FTP/FTPS, it will create nested folders if necessary.": "Le nouveau chemin du dossier par exemple `./myfolder`. Pour FTP/FTPS, il créera des dossiers imbriqués si nécessaire.",
"For SFTP only: Create parent directories if they do not exist": "Pour SFTP uniquement : Créer des répertoires parents s'ils n'existent pas",
"The path of the folder to delete e.g. `./myfolder`": "Le chemin du dossier à supprimer, par exemple `./myfolder`",
"Enable this option to delete the folder and all its contents, including subfolders and files.": "Activez cette option pour supprimer le dossier et tout son contenu, y compris les sous-dossiers et les fichiers.",
"The path of the folder to list e.g. `./myfolder`": "Le chemin du dossier à lister, par exemple `./myfolder`",
"Depending on the server you can also use this to move a file to another directory, as long as the directory exists.": "Selon le serveur, vous pouvez également l'utiliser pour déplacer un fichier dans un autre répertoire, tant que le répertoire existe.",
"The path of the file or folder to rename e.g. `./myfolder/test.mp3`": "Le chemin du fichier ou du dossier à renommer par exemple `./myfolder/test.mp3`",
"The new path of the file or folder e.g. `./myfolder/new-name.mp3`": "Le nouveau chemin du fichier ou du dossier par exemple `./myfolder/new-name.mp3`",
"New File": "Nouveau fichier",
"Trigger when a new file is created or modified.": "Déclencher lorsqu'un nouveau fichier est créé ou modifié.",
"Path": "Chemin d'accès",
"Ignore hidden files": "Ignorer les fichiers cachés",
"The path to watch for new files": "Le chemin d'accès à la recherche de nouveaux fichiers"
}

View File

@@ -0,0 +1,69 @@
{
"Connect to FTP, FTPS or SFTP servers": "FTP、FTPS、SFTPサーバーに接続",
"Protocol": "Protocol",
"Allow Unauthorized Certificates": "許可されていない証明書を許可",
"Host": "ホスト",
"Port": "ポート",
"Username": "ユーザー名",
"Password": "Password",
"Private Key": "プライベートキー",
"Host Key Algorithm": "ホストキーアルゴリズム",
"The protocol to use": "使用するプロトコル",
"Allow connections to servers with self-signed certificates": "自己署名証明書を持つサーバーへの接続を許可する",
"The host of the server": "サーバーのホスト",
"The port of the server": "サーバーのポート",
"The username to authenticate with": "認証するユーザー名",
"The password to authenticate with. Either this or private key is required": "認証用パスワード。これまたは秘密鍵が必要です。",
"The private key to authenticate with. Either this or password is required": "この秘密鍵またはパスワードが必要です",
"The host key algorithm to use for SFTP Private Key authentication": "SFTP 秘密鍵認証に使用するホスト鍵アルゴリズム",
"SFTP": "SFTP",
"FTP": "FTP",
"FTPS": "FTPS",
"ssh-rsa": "ssh-rsa",
"ssh-dss": "ssh-dss",
"ecdsa-sha2-nistp256": "ecdsa-sha2-nistp256",
"ecdsa-sha2-nistp384": "ecdsa-sha2-nistp384",
"ecdsa-sha2-nistp521": "ecdsa-sha2-nistp521",
"ssh-ed25519": "ssh-ed25519",
"rsa-sha2-256": "rsa-sha2-256",
"rsa-sha2-512": "rsa-sha2-512",
"Create File from Text": "テキストからファイルを作成",
"Upload File": "ファイルをアップロード",
"Read File Content": "ファイルの内容を読む",
"Delete file": "ファイルを削除",
"Create Folder": "フォルダを作成",
"Delete Folder": "フォルダを削除",
"List Folder Contents": "フォルダの内容を一覧表示する",
"Rename File or Folder": "ファイルまたはフォルダの名前を変更",
"Create a new file in the given path": "指定されたパスに新しいファイルを作成します",
"Upload a file to the given path.": "指定したパスにファイルをアップロードします。",
"Read the content of a file.": "ファイルの内容を読み込みます。",
"Deletes a file at given path.": "指定されたパスのファイルを削除します。",
"Creates a folder at given path.": "指定されたパスにフォルダを作成します。",
"Deletes an existing folder at given path.": "指定されたパスの既存のフォルダを削除します。",
"Lists the contents of a given folder.": "指定したフォルダの内容を一覧表示します。",
"Renames a file or folder at given path.": "指定されたパスのファイルまたはフォルダの名前を変更します。",
"File Path": "ファイルパス",
"File content": "ファイルの内容",
"Folder Path": "フォルダパス",
"Recursive": "再帰的",
"Directory Path": "ディレクトリパス",
"Markdown": "Markdown",
"Old Path": "古いパス",
"New Path": "新しいパス",
"The path on the sftp server to store the file. e.g. `./myfolder/test.mp3`": "ファイルを保存するための sftp サーバーのパス。例: `./myfolder/test.mp3`",
"The path of the file to delete e.g. `./myfolder/test.mp3`": "削除するファイルのパス。例: `./myfolder/test.mp3`",
"The new folder path e.g. `./myfolder`. For FTP/FTPS, it will create nested folders if necessary.": "`./myfolder`のような新しいフォルダパス。FTP/FTPSの場合、必要に応じてネストされたフォルダを作成します。",
"For SFTP only: Create parent directories if they do not exist": "SFTP の場合のみ: 親ディレクトリが存在しない場合に作成します",
"The path of the folder to delete e.g. `./myfolder`": "削除するフォルダのパス。例: `./myfolder`",
"Enable this option to delete the folder and all its contents, including subfolders and files.": "このオプションを有効にすると、フォルダとそのすべてのコンテンツ(サブフォルダとファイルを含む)を削除できます。",
"The path of the folder to list e.g. `./myfolder`": "リストするフォルダのパス。例: `./myfolder`",
"Depending on the server you can also use this to move a file to another directory, as long as the directory exists.": "サーバに応じて、ディレクトリが存在する限り、ファイルを別のディレクトリに移動することもできます。",
"The path of the file or folder to rename e.g. `./myfolder/test.mp3`": "`./myfolder/test.mp3` などの名前を変更するファイルまたはフォルダのパス",
"The new path of the file or folder e.g. `./myfolder/new-name.mp3`": "ファイルまたはフォルダの新しいパス。例: `./myfolder/new-name.mp3`",
"New File": "新規ファイル",
"Trigger when a new file is created or modified.": "新しいファイルが作成または変更されたときにトリガーします。",
"Path": "パス",
"Ignore hidden files": "隠しファイルを無視",
"The path to watch for new files": "新しいファイルを見るためのパス"
}

View File

@@ -0,0 +1,69 @@
{
"Connect to FTP, FTPS or SFTP servers": "Verbinding maken met FTP, FTPS of SFTP-servers",
"Protocol": "Protocol",
"Allow Unauthorized Certificates": "Ongeautoriseerde certificaten toestaan",
"Host": "Hostnaam",
"Port": "Poort",
"Username": "Gebruikersnaam",
"Password": "Wachtwoord",
"Private Key": "Persoonlijke sleutel",
"Host Key Algorithm": "Algoritme voor hostsleutel",
"The protocol to use": "Het te gebruiken protocol",
"Allow connections to servers with self-signed certificates": "Verbindingen met servers met zelfondertekende certificaten toestaan",
"The host of the server": "De host van de server",
"The port of the server": "De poort van de server",
"The username to authenticate with": "De gebruikersnaam om mee te verifiëren",
"The password to authenticate with. Either this or private key is required": "Het wachtwoord om mee te verifiëren. Of deze of private key is vereist",
"The private key to authenticate with. Either this or password is required": "De geheime sleutel om mee te verifiëren. Of dit of het wachtwoord is vereist",
"The host key algorithm to use for SFTP Private Key authentication": "Het host-sleutel-algoritme dat moet worden gebruikt voor SFTP Private Key authenticatie",
"SFTP": "SFTP",
"FTP": "FTP",
"FTPS": "FTPS",
"ssh-rsa": "ssh-rsa",
"ssh-dss": "ssh-dss",
"ecdsa-sha2-nistp256": "ecdsa-sha2-nistp256",
"ecdsa-sha2-nistp384": "ecdsa-sha2-nistp384",
"ecdsa-sha2-nistp521": "ecdsa-sha2-nistp521",
"ssh-ed25519": "ssh-ed25519",
"rsa-sha2-256": "rsa-sha2-256",
"rsa-sha2-512": "rsa-sha2-512",
"Create File from Text": "Maak bestand van tekst",
"Upload File": "Bestand uploaden",
"Read File Content": "Lees bestandsinhoud",
"Delete file": "Bestand verwijderen",
"Create Folder": "Map aanmaken",
"Delete Folder": "Map verwijderen",
"List Folder Contents": "Lijst map inhoud",
"Rename File or Folder": "Hernoem bestand of map",
"Create a new file in the given path": "Maak een nieuw bestand aan in het opgegeven pad",
"Upload a file to the given path.": "Upload een bestand naar het opgegeven pad.",
"Read the content of a file.": "Lees de inhoud van een bestand.",
"Deletes a file at given path.": "Verwijdert een bestand van het opgegeven pad.",
"Creates a folder at given path.": "Maakt een map aan op het opgegeven pad.",
"Deletes an existing folder at given path.": "Verwijdert een bestaande map van het opgegeven pad.",
"Lists the contents of a given folder.": "Geeft de inhoud van een bepaalde map weer.",
"Renames a file or folder at given path.": "Wijzigt de naam van een bestand of map op het opgegeven pad.",
"File Path": "Bestandspad",
"File content": "Bestand inhoud",
"Folder Path": "Map pad",
"Recursive": "Recursief",
"Directory Path": "Map pad",
"Markdown": "Markdown",
"Old Path": "Oud pad",
"New Path": "Nieuw pad",
"The path on the sftp server to store the file. e.g. `./myfolder/test.mp3`": "Het pad op de sftp server om het bestand op te slaan. b.v. `./mijnmap/test.mp3`",
"The path of the file to delete e.g. `./myfolder/test.mp3`": "Het pad van het bestand om te verwijderen, bijv. `./myfolder/test.mp3`",
"The new folder path e.g. `./myfolder`. For FTP/FTPS, it will create nested folders if necessary.": "Het nieuwe mappad bijv. `./myfolder`. Voor FTP/FTPS, zal het geneste mappen aanmaken indien nodig.",
"For SFTP only: Create parent directories if they do not exist": "Alleen voor SFTP maken: Maak bovenliggende mappen aan als ze niet bestaan",
"The path of the folder to delete e.g. `./myfolder`": "Het pad van de map om te verwijderen, bijv. `./myfolder`",
"Enable this option to delete the folder and all its contents, including subfolders and files.": "Schakel deze optie in om de map en alle bijbehorende inhoud te verwijderen, inclusief submappen en bestanden.",
"The path of the folder to list e.g. `./myfolder`": "Het pad van de map om bijv. `./myfolder` te tonen",
"Depending on the server you can also use this to move a file to another directory, as long as the directory exists.": "Afhankelijk van de server kan je dit ook gebruiken om een bestand naar een andere map te verplaatsen, zolang de map bestaat.",
"The path of the file or folder to rename e.g. `./myfolder/test.mp3`": "Het pad van het bestand of de map om te hernoemen bijv. `./mijnmap/test.mp3`",
"The new path of the file or folder e.g. `./myfolder/new-name.mp3`": "Het nieuwe pad van het bestand of de map bijv. `./myfolder/new-name.mp3`",
"New File": "Nieuw bestand",
"Trigger when a new file is created or modified.": "Trigger wanneer een nieuw bestand wordt gemaakt of gewijzigd.",
"Path": "Pad",
"Ignore hidden files": "Verborgen bestanden negeren",
"The path to watch for new files": "Het pad om nieuwe bestanden te bekijken"
}

View File

@@ -0,0 +1,69 @@
{
"Connect to FTP, FTPS or SFTP servers": "Conectar-se aos servidores FTP, FTPS ou SFTP",
"Protocol": "Protocol",
"Allow Unauthorized Certificates": "Permitir Certificados Não Autorizados",
"Host": "Servidor",
"Port": "Porta",
"Username": "Usuário:",
"Password": "Senha",
"Private Key": "Chave Privada",
"Host Key Algorithm": "Algoritmo da chave do anfitrião",
"The protocol to use": "O protocolo a ser usado",
"Allow connections to servers with self-signed certificates": "Permitir conexões a servidores com certificados auto-assinados",
"The host of the server": "O host do servidor",
"The port of the server": "A porta do servidor",
"The username to authenticate with": "O nome de usuário para autenticar com",
"The password to authenticate with. Either this or private key is required": "A senha para autenticação. Ou esta ou chave privada é necessária",
"The private key to authenticate with. Either this or password is required": "A chave privada para se autenticar. Ou isto ou a senha é necessária",
"The host key algorithm to use for SFTP Private Key authentication": "O algoritmo de chave de host usado para autenticação de chave privada SFTP",
"SFTP": "SFTP",
"FTP": "FTP",
"FTPS": "FTPS",
"ssh-rsa": "ssh-rsa",
"ssh-dss": "ssh-dss",
"ecdsa-sha2-nistp256": "ecdsa-sha2-nistp256",
"ecdsa-sha2-nistp384": "ecdsa-sha2-nistp384",
"ecdsa-sha2-nistp521": "ecdsa-sha2-nistp521",
"ssh-ed25519": "ssh-ed25519",
"rsa-sha2-256": "rsa-sha2-256",
"rsa-sha2-512": "rsa-sha2-512",
"Create File from Text": "Criar Arquivo do Texto",
"Upload File": "Enviar Arquivo",
"Read File Content": "Ler conteúdo do arquivo",
"Delete file": "Excluir arquivo",
"Create Folder": "Criar pasta",
"Delete Folder": "Excluir Pasta",
"List Folder Contents": "Listar conteúdo das pastas",
"Rename File or Folder": "Renomear Arquivo ou Pasta",
"Create a new file in the given path": "Criar um novo arquivo no caminho fornecido",
"Upload a file to the given path.": "Enviar um arquivo para o caminho indicado.",
"Read the content of a file.": "Leia o conteúdo de um arquivo.",
"Deletes a file at given path.": "Exclui um arquivo em um determinado caminho.",
"Creates a folder at given path.": "Cria uma pasta em um determinado caminho.",
"Deletes an existing folder at given path.": "Exclui uma pasta existente em um determinado caminho.",
"Lists the contents of a given folder.": "Lista o conteúdo de uma determinada pasta.",
"Renames a file or folder at given path.": "Renomeia um arquivo ou pasta em um determinado caminho.",
"File Path": "Caminho do Arquivo",
"File content": "Conteúdo do arquivo",
"Folder Path": "Caminho da pasta",
"Recursive": "Recursiva",
"Directory Path": "Caminho do Diretório",
"Markdown": "Markdown",
"Old Path": "Caminho Antigo",
"New Path": "Novo caminho",
"The path on the sftp server to store the file. e.g. `./myfolder/test.mp3`": "O caminho no servidor sftp para armazenar o arquivo. Ex: `./myfolder/test.mp3`",
"The path of the file to delete e.g. `./myfolder/test.mp3`": "O caminho do arquivo a ser apagado, por exemplo, `./myfolder/test.mp3`",
"The new folder path e.g. `./myfolder`. For FTP/FTPS, it will create nested folders if necessary.": "O novo caminho de pasta, por exemplo, `./myfolder`. Para FTP/FTPS, irá criar pastas aninhadas se necessário.",
"For SFTP only: Create parent directories if they do not exist": "Somente para SFTP: Criar diretórios pai se eles não existirem",
"The path of the folder to delete e.g. `./myfolder`": "O caminho da pasta a ser excluída, por exemplo, `./myfolder`",
"Enable this option to delete the folder and all its contents, including subfolders and files.": "Habilite esta opção para excluir a pasta e todo o seu conteúdo, incluindo subpastas e arquivos.",
"The path of the folder to list e.g. `./myfolder`": "O caminho da pasta para listar, por exemplo, `./myfolder`",
"Depending on the server you can also use this to move a file to another directory, as long as the directory exists.": "Dependendo do servidor você também pode usar isso para mover um arquivo para outro diretório, contanto que o diretório existe.",
"The path of the file or folder to rename e.g. `./myfolder/test.mp3`": "O caminho do arquivo ou pasta para renomear ex: `./myfolder/test.mp3`",
"The new path of the file or folder e.g. `./myfolder/new-name.mp3`": "O novo caminho do arquivo ou pasta, por exemplo, `./myfolder/new-name.mp3`",
"New File": "Novo arquivo",
"Trigger when a new file is created or modified.": "Disparar quando um novo arquivo for criado ou modificado.",
"Path": "Caminho",
"Ignore hidden files": "Ignorar arquivos ocultos",
"The path to watch for new files": "O caminho para ver novos arquivos"
}

View File

@@ -0,0 +1,58 @@
{
"FTP/SFTP": "FTP/SFTP",
"Connect to FTP, FTPS or SFTP servers": "Подключение к FTP, FTPS или SFTP серверам",
"Protocol": "Protocol",
"Allow Unauthorized Certificates": "Разрешить несанкционированные сертификаты",
"Host": "Хост",
"Port": "Порт",
"Username": "Имя пользователя",
"Password": "Пароль",
"The protocol to use": "Используемый протокол",
"Allow connections to servers with self-signed certificates": "Разрешить подключения к серверам с самоподписанными сертификатами",
"The host of the server": "Сервер",
"The port of the server": "Порт сервера",
"The username to authenticate with": "Имя пользователя для аутентификации с",
"The password to authenticate with": "Пароль для аутентификации с",
"SFTP": "SFTP",
"FTP": "FTP",
"FTPS": "FTPS",
"Create File from Text": "Создать файл из текста",
"Upload File": "Загрузить файл",
"Read File Content": "Читать содержимое файла",
"Delete file": "Удалить файл",
"Create Folder": "Создать папку",
"Delete Folder": "Удалить папку",
"List Folder Contents": "Список содержимого папки",
"Rename File or Folder": "Переименовать файл или папку",
"Create a new file in the given path": "Создать новый файл в заданном пути",
"Upload a file to the given path.": "Загрузить файл на указанный путь.",
"Read the content of a file.": "Чтение содержимого файла.",
"Deletes a file at given path.": "Удаляет файл по указанному пути.",
"Creates a folder at given path.": "Создает папку по указанному пути.",
"Deletes an existing folder at given path.": "Удаляет существующую папку на заданном пути.",
"Lists the contents of a given folder.": "Список содержимого данной папки.",
"Renames a file or folder at given path.": "Переименовывает файл или папку на заданном пути.",
"File Path": "Путь к файлу",
"File content": "Содержимое файла",
"Folder Path": "Путь к папке",
"Recursive": "Рекурсивный",
"Directory Path": "Путь к каталогу",
"Markdown": "Markdown",
"Old Path": "Старый путь",
"New Path": "Новый путь",
"The path on the sftp server to store the file. e.g. `./myfolder/test.mp3`": "Путь на сервере sftp для хранения файла. Например, `./myfolder/test.mp3`",
"The path of the file to delete e.g. `./myfolder/test.mp3`": "Путь к удаляемому файлу, например `./myfolder/test.mp3`",
"The new folder path e.g. `./myfolder`. For FTP/FTPS, it will create nested folders if necessary.": "Путь к новой папке, например `./myfolder`. Для FTP/FTPS он создаст вложенные папки при необходимости.",
"For SFTP only: Create parent directories if they do not exist": "Только для SFTP: создавайте родительские директории, если они не существуют",
"The path of the folder to delete e.g. `./myfolder`": "Путь к удаляемой папке, например `./myfolder`",
"Enable this option to delete the folder and all its contents, including subfolders and files.": "Включите эту опцию, чтобы удалить папку и все ее содержимое, включая подпапки и файлы.",
"The path of the folder to list e.g. `./myfolder`": "Путь папки к списку, например `./myfolder`",
"Depending on the server you can also use this to move a file to another directory, as long as the directory exists.": "В зависимости от сервера вы также можете использовать это для перемещения файла в другой каталог, если каталог существует.",
"The path of the file or folder to rename e.g. `./myfolder/test.mp3`": "Путь к файлу или папке для переименования, например `./myfolder/test.mp3`",
"The new path of the file or folder e.g. `./myfolder/new-name.mp3`": "Новый путь к файлу или папке, например `./myfolder/new-name.mp3`",
"New File": "Новый файл",
"Trigger when a new file is created or modified.": "Запуск при создании или изменении нового файла.",
"Path": "Путь",
"Ignore hidden files": "Игнорировать скрытые файлы",
"The path to watch for new files": "Путь для просмотра новых файлов"
}

View File

@@ -0,0 +1,69 @@
{
"Connect to FTP, FTPS or SFTP servers": "Connect to FTP, FTPS or SFTP servers",
"Protocol": "Protocol",
"Allow Unauthorized Certificates": "Allow Unauthorized Certificates",
"Host": "Host",
"Port": "Port",
"Username": "Username",
"Password": "Password",
"Private Key": "Private Key",
"Host Key Algorithm": "Host Key Algorithm",
"The protocol to use": "The protocol to use",
"Allow connections to servers with self-signed certificates": "Allow connections to servers with self-signed certificates",
"The host of the server": "The host of the server",
"The port of the server": "The port of the server",
"The username to authenticate with": "The username to authenticate with",
"The password to authenticate with. Either this or private key is required": "The password to authenticate with. Either this or private key is required",
"The private key to authenticate with. Either this or password is required": "The private key to authenticate with. Either this or password is required",
"The host key algorithm to use for SFTP Private Key authentication": "The host key algorithm to use for SFTP Private Key authentication",
"SFTP": "SFTP",
"FTP": "FTP",
"FTPS": "FTPS",
"ssh-rsa": "ssh-rsa",
"ssh-dss": "ssh-dss",
"ecdsa-sha2-nistp256": "ecdsa-sha2-nistp256",
"ecdsa-sha2-nistp384": "ecdsa-sha2-nistp384",
"ecdsa-sha2-nistp521": "ecdsa-sha2-nistp521",
"ssh-ed25519": "ssh-ed25519",
"rsa-sha2-256": "rsa-sha2-256",
"rsa-sha2-512": "rsa-sha2-512",
"Create File from Text": "Create File from Text",
"Upload File": "Upload File",
"Read File Content": "Read File Content",
"Delete file": "Delete file",
"Create Folder": "Create Folder",
"Delete Folder": "Delete Folder",
"List Folder Contents": "List Folder Contents",
"Rename File or Folder": "Rename File or Folder",
"Create a new file in the given path": "Create a new file in the given path",
"Upload a file to the given path.": "Upload a file to the given path.",
"Read the content of a file.": "Read the content of a file.",
"Deletes a file at given path.": "Deletes a file at given path.",
"Creates a folder at given path.": "Creates a folder at given path.",
"Deletes an existing folder at given path.": "Deletes an existing folder at given path.",
"Lists the contents of a given folder.": "Lists the contents of a given folder.",
"Renames a file or folder at given path.": "Renames a file or folder at given path.",
"File Path": "File Path",
"File content": "File content",
"Folder Path": "Folder Path",
"Recursive": "Recursive",
"Directory Path": "Directory Path",
"Markdown": "Markdown",
"Old Path": "Old Path",
"New Path": "New Path",
"The path on the sftp server to store the file. e.g. `./myfolder/test.mp3`": "The path on the sftp server to store the file. e.g. `./myfolder/test.mp3`",
"The path of the file to delete e.g. `./myfolder/test.mp3`": "The path of the file to delete e.g. `./myfolder/test.mp3`",
"The new folder path e.g. `./myfolder`. For FTP/FTPS, it will create nested folders if necessary.": "The new folder path e.g. `./myfolder`. For FTP/FTPS, it will create nested folders if necessary.",
"For SFTP only: Create parent directories if they do not exist": "For SFTP only: Create parent directories if they do not exist",
"The path of the folder to delete e.g. `./myfolder`": "The path of the folder to delete e.g. `./myfolder`",
"Enable this option to delete the folder and all its contents, including subfolders and files.": "Enable this option to delete the folder and all its contents, including subfolders and files.",
"The path of the folder to list e.g. `./myfolder`": "The path of the folder to list e.g. `./myfolder`",
"Depending on the server you can also use this to move a file to another directory, as long as the directory exists.": "Depending on the server you can also use this to move a file to another directory, as long as the directory exists.",
"The path of the file or folder to rename e.g. `./myfolder/test.mp3`": "The path of the file or folder to rename e.g. `./myfolder/test.mp3`",
"The new path of the file or folder e.g. `./myfolder/new-name.mp3`": "The new path of the file or folder e.g. `./myfolder/new-name.mp3`",
"New File": "New File",
"Trigger when a new file is created or modified.": "Trigger when a new file is created or modified.",
"Path": "Path",
"Ignore hidden files": "Ignore hidden files",
"The path to watch for new files": "The path to watch for new files"
}

View File

@@ -0,0 +1,58 @@
{
"FTP/SFTP": "FTP/SFTP",
"Connect to FTP, FTPS or SFTP servers": "Connect to FTP, FTPS or SFTP servers",
"Protocol": "Protocol",
"Allow Unauthorized Certificates": "Allow Unauthorized Certificates",
"Host": "Host",
"Port": "Port",
"Username": "Username",
"Password": "Password",
"The protocol to use": "The protocol to use",
"Allow connections to servers with self-signed certificates": "Allow connections to servers with self-signed certificates",
"The host of the server": "The host of the server",
"The port of the server": "The port of the server",
"The username to authenticate with": "The username to authenticate with",
"The password to authenticate with": "The password to authenticate with",
"SFTP": "SFTP",
"FTP": "FTP",
"FTPS": "FTPS",
"Create File from Text": "Create File from Text",
"Upload File": "Upload File",
"Read File Content": "Read File Content",
"Delete file": "Delete file",
"Create Folder": "Create Folder",
"Delete Folder": "Delete Folder",
"List Folder Contents": "List Folder Contents",
"Rename File or Folder": "Rename File or Folder",
"Create a new file in the given path": "Create a new file in the given path",
"Upload a file to the given path.": "Upload a file to the given path.",
"Read the content of a file.": "Read the content of a file.",
"Deletes a file at given path.": "Deletes a file at given path.",
"Creates a folder at given path.": "Creates a folder at given path.",
"Deletes an existing folder at given path.": "Deletes an existing folder at given path.",
"Lists the contents of a given folder.": "Lists the contents of a given folder.",
"Renames a file or folder at given path.": "Renames a file or folder at given path.",
"File Path": "File Path",
"File content": "File content",
"Folder Path": "Folder Path",
"Recursive": "Recursive",
"Directory Path": "Directory Path",
"Markdown": "Markdown",
"Old Path": "Old Path",
"New Path": "New Path",
"The path on the sftp server to store the file. e.g. `./myfolder/test.mp3`": "The path on the sftp server to store the file. e.g. `./myfolder/test.mp3`",
"The path of the file to delete e.g. `./myfolder/test.mp3`": "The path of the file to delete e.g. `./myfolder/test.mp3`",
"The new folder path e.g. `./myfolder`. For FTP/FTPS, it will create nested folders if necessary.": "The new folder path e.g. `./myfolder`. For FTP/FTPS, it will create nested folders if necessary.",
"For SFTP only: Create parent directories if they do not exist": "For SFTP only: Create parent directories if they do not exist",
"The path of the folder to delete e.g. `./myfolder`": "The path of the folder to delete e.g. `./myfolder`",
"Enable this option to delete the folder and all its contents, including subfolders and files.": "Enable this option to delete the folder and all its contents, including subfolders and files.",
"The path of the folder to list e.g. `./myfolder`": "The path of the folder to list e.g. `./myfolder`",
"Depending on the server you can also use this to move a file to another directory, as long as the directory exists.": "Depending on the server you can also use this to move a file to another directory, as long as the directory exists.",
"The path of the file or folder to rename e.g. `./myfolder/test.mp3`": "The path of the file or folder to rename e.g. `./myfolder/test.mp3`",
"The new path of the file or folder e.g. `./myfolder/new-name.mp3`": "The new path of the file or folder e.g. `./myfolder/new-name.mp3`",
"New File": "New File",
"Trigger when a new file is created or modified.": "Trigger when a new file is created or modified.",
"Path": "Path",
"Ignore hidden files": "Ignore hidden files",
"The path to watch for new files": "The path to watch for new files"
}

View File

@@ -0,0 +1,69 @@
{
"Connect to FTP, FTPS or SFTP servers": "Connect to FTP, FTPS or SFTP servers",
"Protocol": "Protocol",
"Allow Unauthorized Certificates": "Allow Unauthorized Certificates",
"Host": "主机",
"Port": "端口",
"Username": "用户名",
"Password": "Password",
"Private Key": "Private Key",
"Host Key Algorithm": "Host Key Algorithm",
"The protocol to use": "The protocol to use",
"Allow connections to servers with self-signed certificates": "Allow connections to servers with self-signed certificates",
"The host of the server": "The host of the server",
"The port of the server": "The port of the server",
"The username to authenticate with": "The username to authenticate with",
"The password to authenticate with. Either this or private key is required": "The password to authenticate with. Either this or private key is required",
"The private key to authenticate with. Either this or password is required": "The private key to authenticate with. Either this or password is required",
"The host key algorithm to use for SFTP Private Key authentication": "The host key algorithm to use for SFTP Private Key authentication",
"SFTP": "SFTP",
"FTP": "FTP",
"FTPS": "FTPS",
"ssh-rsa": "ssh-rsa",
"ssh-dss": "ssh-dss",
"ecdsa-sha2-nistp256": "ecdsa-sha2-nistp256",
"ecdsa-sha2-nistp384": "ecdsa-sha2-nistp384",
"ecdsa-sha2-nistp521": "ecdsa-sha2-nistp521",
"ssh-ed25519": "ssh-ed25519",
"rsa-sha2-256": "rsa-sha2-256",
"rsa-sha2-512": "rsa-sha2-512",
"Create File from Text": "Create File from Text",
"Upload File": "Upload File",
"Read File Content": "Read File Content",
"Delete file": "Delete file",
"Create Folder": "Create Folder",
"Delete Folder": "Delete Folder",
"List Folder Contents": "List Folder Contents",
"Rename File or Folder": "Rename File or Folder",
"Create a new file in the given path": "Create a new file in the given path",
"Upload a file to the given path.": "Upload a file to the given path.",
"Read the content of a file.": "Read the content of a file.",
"Deletes a file at given path.": "Deletes a file at given path.",
"Creates a folder at given path.": "Creates a folder at given path.",
"Deletes an existing folder at given path.": "Deletes an existing folder at given path.",
"Lists the contents of a given folder.": "Lists the contents of a given folder.",
"Renames a file or folder at given path.": "Renames a file or folder at given path.",
"File Path": "File Path",
"File content": "File content",
"Folder Path": "Folder Path",
"Recursive": "Recursive",
"Directory Path": "Directory Path",
"Markdown": "Markdown",
"Old Path": "Old Path",
"New Path": "New Path",
"The path on the sftp server to store the file. e.g. `./myfolder/test.mp3`": "The path on the sftp server to store the file. e.g. `./myfolder/test.mp3`",
"The path of the file to delete e.g. `./myfolder/test.mp3`": "The path of the file to delete e.g. `./myfolder/test.mp3`",
"The new folder path e.g. `./myfolder`. For FTP/FTPS, it will create nested folders if necessary.": "The new folder path e.g. `./myfolder`. For FTP/FTPS, it will create nested folders if necessary.",
"For SFTP only: Create parent directories if they do not exist": "For SFTP only: Create parent directories if they do not exist",
"The path of the folder to delete e.g. `./myfolder`": "The path of the folder to delete e.g. `./myfolder`",
"Enable this option to delete the folder and all its contents, including subfolders and files.": "Enable this option to delete the folder and all its contents, including subfolders and files.",
"The path of the folder to list e.g. `./myfolder`": "The path of the folder to list e.g. `./myfolder`",
"Depending on the server you can also use this to move a file to another directory, as long as the directory exists.": "Depending on the server you can also use this to move a file to another directory, as long as the directory exists.",
"The path of the file or folder to rename e.g. `./myfolder/test.mp3`": "The path of the file or folder to rename e.g. `./myfolder/test.mp3`",
"The new path of the file or folder e.g. `./myfolder/new-name.mp3`": "The new path of the file or folder e.g. `./myfolder/new-name.mp3`",
"New File": "New File",
"Trigger when a new file is created or modified.": "Trigger when a new file is created or modified.",
"Path": "Path",
"Ignore hidden files": "Ignore hidden files",
"The path to watch for new files": "The path to watch for new files"
}

View File

@@ -0,0 +1,212 @@
import {
PieceAuth,
Property,
createPiece,
} from '@activepieces/pieces-framework';
import { isNil, PieceCategory } from '@activepieces/shared';
import Client from 'ssh2-sftp-client';
import { Client as FTPClient } from 'basic-ftp';
import { createFile } from './lib/actions/create-file';
import { uploadFileAction } from './lib/actions/upload-file';
import { readFileContent } from './lib/actions/read-file';
import { newOrModifiedFile } from './lib/triggers/new-modified-file';
import { deleteFolderAction } from './lib/actions/delete-folder';
import { deleteFileAction } from './lib/actions/delete-file';
import { listFolderContentsAction } from './lib/actions/list-files';
import { createFolderAction } from './lib/actions/create-folder';
import { renameFileOrFolderAction } from './lib/actions/rename-file-or-folder';
export async function getProtocolBackwardCompatibility(protocol: string | undefined) {
if (isNil(protocol)) {
return 'sftp';
}
return protocol;
}
export async function getClient<T extends Client | FTPClient>(auth: { protocol: string | undefined, host: string, port: number, allow_unauthorized_certificates: boolean | undefined, username: string, password: string | undefined, privateKey: string | undefined, algorithm: string[] | undefined }): Promise<T> {
const { protocol, host, port, allow_unauthorized_certificates, username, password, privateKey, algorithm } = auth;
const protocolBackwardCompatibility = await getProtocolBackwardCompatibility(protocol);
if (protocolBackwardCompatibility === 'sftp') {
const sftp = new Client();
if (auth.password){
await sftp.connect({
host,
port,
username,
password,
timeout: 10000,
});
}
else if (privateKey) {
if (!algorithm || algorithm.length === 0) {
throw new Error('At least one algorithm must be selected for SFTP Private Key authentication.');
}
await sftp.connect({
host,
port,
username,
privateKey: privateKey.replace(/\\n/g, '\n').trim(),
algorithms: {
serverHostKey: algorithm
} as Client.ConnectOptions['algorithms'],
timeout: 10000,
});
}
return sftp as T;
} else {
const ftpClient = new FTPClient();
await ftpClient.access({
host,
port,
user: username,
password,
secure: protocolBackwardCompatibility === 'ftps',
secureOptions: {
rejectUnauthorized: !(allow_unauthorized_certificates ?? false),
}
});
return ftpClient as T;
}
}
export async function endClient(client: Client | FTPClient, protocol: string | undefined) {
const protocolBackwardCompatibility = await getProtocolBackwardCompatibility(protocol);
if (protocolBackwardCompatibility === 'sftp') {
await (client as Client).end();
} else {
(client as FTPClient).close();
}
}
export const sftpAuth = PieceAuth.CustomAuth({
props: {
protocol: Property.StaticDropdown({
displayName: 'Protocol',
description: 'The protocol to use',
required: false,
options: {
options: [
{ value: 'sftp', label: 'SFTP' },
{ value: 'ftp', label: 'FTP' },
{ value: 'ftps', label: 'FTPS' }
],
},
}),
allow_unauthorized_certificates: Property.Checkbox({
displayName: 'Allow Unauthorized Certificates',
description:
'Allow connections to servers with self-signed certificates',
defaultValue: false,
required: false,
}),
host: Property.ShortText({
displayName: 'Host',
description: 'The host of the server',
required: true,
}),
port: Property.Number({
displayName: 'Port',
description: 'The port of the server',
required: true,
defaultValue: 22,
}),
username: Property.ShortText({
displayName: 'Username',
description: 'The username to authenticate with',
required: true,
}),
password: PieceAuth.SecretText({
displayName: 'Password',
description: 'The password to authenticate with. Either this or private key is required',
required: false,
}),
privateKey: PieceAuth.SecretText({
displayName: 'Private Key',
description: 'The private key to authenticate with. Either this or password is required',
required: false,
}),
algorithm: Property.StaticMultiSelectDropdown({
displayName: 'Host Key Algorithm',
description: 'The host key algorithm to use for SFTP Private Key authentication',
required: false,
options: {
options: [
{ value: 'ssh-rsa', label: 'ssh-rsa' },
{ value: 'ssh-dss', label: 'ssh-dss' },
{ value: 'ecdsa-sha2-nistp256', label: 'ecdsa-sha2-nistp256' },
{ value: 'ecdsa-sha2-nistp384', label: 'ecdsa-sha2-nistp384' },
{ value: 'ecdsa-sha2-nistp521', label: 'ecdsa-sha2-nistp521' },
{ value: 'ssh-ed25519', label: 'ssh-ed25519' },
{ value: 'rsa-sha2-256', label: 'rsa-sha2-256' },
{ value: 'rsa-sha2-512', label: 'rsa-sha2-512' }
],
},
})
},
validate: async ({ auth }) => {
if (!auth.password && !auth.privateKey) {
return {
valid: false,
error: 'Either password or private key must be provided for authentication.',
};
}
let client: Client | FTPClient | null = null;
const protocolBackwardCompatibility = await getProtocolBackwardCompatibility(auth.protocol);
try {
switch (protocolBackwardCompatibility) {
case 'sftp': {
client = await getClient<Client>(auth);
break;
}
default: {
client = await getClient<FTPClient>(auth);
break;
}
}
return {
valid: true,
};
} catch (err) {
return {
valid: false,
error: (err as Error)?.message,
};
} finally {
if (client) {
await endClient(client, auth.protocol);
}
}
},
required: true,
});
export const ftpSftp = createPiece({
displayName: 'FTP/SFTP',
description: 'Connect to FTP, FTPS or SFTP servers',
minimumSupportedRelease: '0.30.0',
logoUrl: 'https://cdn.activepieces.com/pieces/sftp.svg',
categories: [PieceCategory.CORE, PieceCategory.DEVELOPER_TOOLS],
authors: [
'Abdallah-Alwarawreh',
'kishanprmr',
'AbdulTheActivePiecer',
'khaledmashaly',
'abuaboud',
'prasanna2000-max',
],
auth: sftpAuth,
actions: [
createFile,
uploadFileAction,
readFileContent,
deleteFileAction,
createFolderAction,
deleteFolderAction,
listFolderContentsAction,
renameFileOrFolderAction,
],
triggers: [newOrModifiedFile],
});

View File

@@ -0,0 +1,144 @@
type sFtpError = {
error: string;
description?: string;
}
type sFtpErrorWithCode = {
[code: number]: sFtpError;
}
const sftpErrors: sFtpErrorWithCode = {
0: {
error: 'OK',
description: 'Indicates successful completion of the operation.',
},
1: {
error: 'EOF',
description: 'An attempt to read past the end-of-file was made; or, there are no more directory entries to return.',
},
2: {
error: 'No such file',
description: 'A reference was made to a file which does not exist.',
},
3: {
error: 'Permission denied',
description: 'The user does not have sufficient permissions to perform the operation.',
},
4: {
error: 'Failure',
description: 'An error occurred, but no specific error code exists to describe the failure. This error message should always have meaningful text in the error message field.',
},
5: {
error: 'Bad message',
description: 'A badly formatted packet or other SFTP protocol incompatibility was detected.',
},
6: {
error: 'No connection',
description: 'There is no connection to the server. This error may be used locally, but must not be returned by a server.',
},
7: {
error: 'Connection lost',
description: 'The connection to the server was lost. This error may be used locally, but must not be returned by a server.',
},
8: {
error: 'Operation unsupported',
description: 'An attempted operation could not be completed by the server because the server does not support the operation.',
},
9: {
error: 'Invalid handle',
description: 'The handle value was invalid.',
},
10: {
error: 'No such path',
description: 'The file path does not exist or is invalid.',
},
11: {
error: 'File already exists',
description: 'The file already exists.',
},
12: {
error: 'Write protect',
description: 'The file is on read-only media, or the media is write protected.',
},
13: {
error: 'No media',
description: 'The requested operation cannot be completed because there is no media available in the drive.',
},
14: {
error: 'No space on file-system',
description: 'The requested operation cannot be completed because there is insufficient free space on the filesystem.',
},
15: {
error: 'Quota exceeded',
description: "The operation cannot be completed because it would exceed the users storage quota.",
},
16: {
error: 'Unknown principal',
description: 'A principal referenced by the request (either the owner, group, or who field of an ACL), was unknown.',
},
17: {
error: 'Lock conflict',
description: 'The file could not be opened because it is locked by another process.',
},
18: {
error: 'Directory not empty',
description: 'The directory is not empty.',
},
19: {
error: 'Not a directory',
description: 'The specified file is not a directory.',
},
20: {
error: 'Invalid filename',
description: 'The filename is not valid.',
},
21: {
error: 'Link loop',
description: 'Too many symbolic links encountered or an SSH_FXF_NOFOLLOW encountered a symbolic link as the final component.',
},
22: {
error: 'Cannot delete',
description: 'The file cannot be deleted. One possible reason is that the advisory read-only attribute-bit is set.',
},
23: {
error: 'Invalid parameter',
description: 'One of the parameters was out of range or the parameters specified cannot be used together.',
},
24: {
error: 'File is a directory',
description: 'The specified file was a directory in a context where a directory cannot be used.',
},
25: {
error: 'Range lock conflict',
description: 'A read or write operation failed because another processs mandatory byte-range lock overlaps with the request.',
},
26: {
error: 'Range lock refused',
description: 'A request for a byte range lock was refused.',
},
27: {
error: 'Delete pending',
description: 'An operation was attempted on a file for which a delete operation is pending.',
},
28: {
error: 'File corrupt',
description: 'The file is corrupt; a filesystem integrity check should be run.',
},
29: {
error: 'Owner invalid',
description: 'The principal specified cannot be assigned as an owner of a file.',
},
30: {
error: 'Group invalid',
description: 'The principal specified cannot be assigned as the primary group of a file.',
},
31: {
error: 'No matching byte range lock',
description: 'The requested operation could not be completed because the specified byte range lock has not been granted.',
},
};
export function getSftpError(code: number): sFtpError {
const error = sftpErrors[code];
return error ?? { error: 'Unknown error code' };
}

View File

@@ -0,0 +1,82 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import Client from 'ssh2-sftp-client';
import { Client as FTPClient, FTPError } from 'basic-ftp';
import { endClient, getClient, getProtocolBackwardCompatibility, sftpAuth } from '../..';
import { Readable } from 'stream';
import { getSftpError } from './common';
async function createFileWithSFTP(client: Client, fileName: string, fileContent: string) {
const remotePathExists = await client.exists(fileName);
if (!remotePathExists) {
// Extract the directory path from the fileName
const remoteDirectory = fileName.substring(0, fileName.lastIndexOf('/'));
// Create the directory if it doesn't exist
await client.mkdir(remoteDirectory, true);
}
await client.put(Buffer.from(fileContent), fileName);
}
async function createFileWithFTP(client: FTPClient, fileName: string, fileContent: string) {
// Extract the directory path from the fileName
const remoteDirectory = fileName.substring(0, fileName.lastIndexOf('/'));
// Create the directory if it doesn't exist
await client.ensureDir(remoteDirectory);
// Upload the file content
const buffer = Buffer.from(fileContent);
await client.uploadFrom(Readable.from(buffer), fileName);
}
export const createFile = createAction({
auth: sftpAuth,
name: 'create_file',
displayName: 'Create File from Text',
description: 'Create a new file in the given path',
props: {
fileName: Property.ShortText({
displayName: 'File Path',
required: true,
}),
fileContent: Property.LongText({
displayName: 'File content',
required: true,
}),
},
async run(context) {
const fileName = context.propsValue['fileName'];
const fileContent = context.propsValue['fileContent'];
const protocolBackwardCompatibility = await getProtocolBackwardCompatibility(context.auth.props.protocol);
const client = await getClient(context.auth.props);
try {
switch (protocolBackwardCompatibility) {
case 'ftps':
case 'ftp':
await createFileWithFTP(client as FTPClient, fileName, fileContent);
break;
default:
case 'sftp':
await createFileWithSFTP(client as Client, fileName, fileContent);
break;
}
return {
status: 'success',
};
} catch (err) {
if (err instanceof FTPError) {
console.error(getSftpError(err.code));
return {
status: 'error',
error: getSftpError(err.code),
};
} else {
return {
status: 'error',
error: err
}
}
} finally {
await endClient(client, context.auth.props.protocol);
}
},
});

View File

@@ -0,0 +1,63 @@
import { endClient, getClient, getProtocolBackwardCompatibility, sftpAuth } from '../../index';
import { Property, createAction } from '@activepieces/pieces-framework';
import Client from 'ssh2-sftp-client';
import { Client as FTPClient, FTPError } from 'basic-ftp';
import { getSftpError } from './common';
export const createFolderAction = createAction({
auth: sftpAuth,
name: 'createFolder',
displayName: 'Create Folder',
description: 'Creates a folder at given path.',
props: {
folderPath: Property.ShortText({
displayName: 'Folder Path',
required: true,
description: 'The new folder path e.g. `./myfolder`. For FTP/FTPS, it will create nested folders if necessary.',
}),
recursive: Property.Checkbox({
displayName: 'Recursive',
defaultValue: false,
required: false,
description: 'For SFTP only: Create parent directories if they do not exist',
}),
},
async run(context) {
const client = await getClient(context.auth.props);
const directoryPath = context.propsValue.folderPath;
const recursive = context.propsValue.recursive ?? false;
const protocolBackwardCompatibility = await getProtocolBackwardCompatibility(context.auth.props.protocol);
try {
switch (protocolBackwardCompatibility) {
case 'ftps':
case 'ftp':
await (client as FTPClient).ensureDir(directoryPath);
break;
default:
case 'sftp':
await (client as Client).mkdir(directoryPath, recursive);
break;
}
return {
status: 'success',
};
}
catch (err) {
if (err instanceof FTPError) {
console.error(getSftpError(err.code));
return {
status: 'error',
error: getSftpError(err.code),
};
} else {
return {
status: 'error',
error: err
}
}
} finally {
await endClient(client, context.auth.props.protocol);
}
},
});

View File

@@ -0,0 +1,64 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { endClient, getClient, getProtocolBackwardCompatibility, sftpAuth } from '../..';
import { Client as FTPClient, FTPError } from 'basic-ftp';
import Client from 'ssh2-sftp-client';
import { getSftpError } from './common';
async function deleteFileFromFTP(client: FTPClient, filePath: string) {
await client.remove(filePath);
}
async function deleteFileFromSFTP(client: Client, filePath: string) {
await client.delete(filePath);
}
export const deleteFileAction = createAction({
auth: sftpAuth,
name: 'deleteFile',
displayName: 'Delete file',
description: 'Deletes a file at given path.',
props: {
filePath: Property.ShortText({
displayName: 'File Path',
required: true,
description: 'The path of the file to delete e.g. `./myfolder/test.mp3`',
}),
},
async run(context) {
const client = await getClient(context.auth.props);
const filePath = context.propsValue.filePath;
const protocolBackwardCompatibility = await getProtocolBackwardCompatibility(context.auth.props.protocol);
try {
switch (protocolBackwardCompatibility) {
case 'ftps':
case 'ftp':
await deleteFileFromFTP(client as FTPClient, filePath);
break;
default:
case 'sftp':
await deleteFileFromSFTP(client as Client, filePath);
break;
}
return {
status: 'success',
};
}
catch (err) {
if (err instanceof FTPError) {
console.error(getSftpError(err.code));
return {
status: 'error',
error: getSftpError(err.code),
};
} else {
return {
status: 'error',
error: err
}
}
} finally {
await endClient(client, context.auth.props.protocol);
}
},
});

View File

@@ -0,0 +1,76 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import Client from 'ssh2-sftp-client';
import { Client as FTPClient, FTPError } from 'basic-ftp';
import { endClient, getClient, getProtocolBackwardCompatibility, sftpAuth } from '../..';
import { getSftpError } from './common';
async function deleteFolderFTP(client: FTPClient, directoryPath: string, recursive: boolean) {
if (recursive) {
await client.removeDir(directoryPath);
} else {
await client.removeEmptyDir(directoryPath);
}
}
async function deleteFolderSFTP(client: Client, directoryPath: string, recursive: boolean) {
await client.rmdir(directoryPath, recursive);
}
export const deleteFolderAction = createAction({
auth: sftpAuth,
name: 'deleteFolder',
displayName: 'Delete Folder',
description: 'Deletes an existing folder at given path.',
props: {
folderPath: Property.ShortText({
displayName: 'Folder Path',
required: true,
description: 'The path of the folder to delete e.g. `./myfolder`',
}),
recursive: Property.Checkbox({
displayName: 'Recursive',
defaultValue: false,
required: false,
description:
'Enable this option to delete the folder and all its contents, including subfolders and files.',
}),
},
async run(context) {
const client = await getClient(context.auth.props);
const directoryPath = context.propsValue.folderPath;
const recursive = context.propsValue.recursive ?? false;
const protocolBackwardCompatibility = await getProtocolBackwardCompatibility(context.auth.props.protocol);
try {
switch (protocolBackwardCompatibility) {
case 'ftps':
case 'ftp':
await deleteFolderFTP(client as FTPClient, directoryPath, recursive);
break;
default:
case 'sftp':
await deleteFolderSFTP(client as Client, directoryPath, recursive);
break;
}
return {
status: 'success',
};
}
catch (err) {
if (err instanceof FTPError) {
console.error(getSftpError(err.code));
return {
status: 'error',
error: getSftpError(err.code),
};
} else {
return {
status: 'error',
error: err
}
}
} finally {
await endClient(client, context.auth.props.protocol);
}
},
});

View File

@@ -0,0 +1,86 @@
import { endClient, sftpAuth } from '../../index';
import { Property, createAction } from '@activepieces/pieces-framework';
import Client from 'ssh2-sftp-client';
import { Client as FTPClient, FTPError } from 'basic-ftp';
import { getClient, getProtocolBackwardCompatibility } from '../..';
import { getSftpError } from './common';
import { unknown } from 'zod';
async function listSFTP(client: Client, directoryPath: string) {
const contents = await client.list(directoryPath);
await client.end();
return contents;
}
async function listFTP(client: FTPClient, directoryPath: string) {
const contents = await client.list(directoryPath);
return contents.map(item => ({
type: item.type === 1 ? 'd' : '-',
name: item.name,
size: item.size,
modifyTime: item.modifiedAt,
accessTime: item.modifiedAt, // FTP doesn't provide access time
rights: {
user: item.permissions || '',
group: '',
other: ''
},
owner: '',
group: ''
}));
}
export const listFolderContentsAction = createAction({
auth: sftpAuth,
name: 'listFolderContents',
displayName: 'List Folder Contents',
description: 'Lists the contents of a given folder.',
props: {
directoryPath: Property.ShortText({
displayName: 'Directory Path',
required: true,
description: 'The path of the folder to list e.g. `./myfolder`',
}),
},
async run(context) {
const client = await getClient(context.auth.props);
const directoryPath = context.propsValue.directoryPath;
const protocolBackwardCompatibility = await getProtocolBackwardCompatibility(context.auth.props.protocol);
try {
let contents;
switch (protocolBackwardCompatibility) {
case 'ftps':
case 'ftp':
contents = await listFTP(client as FTPClient, directoryPath);
break;
default:
case 'sftp':
contents = await listSFTP(client as Client, directoryPath);
break;
}
return {
status: 'success',
contents: contents,
};
}
catch (err) {
if (err instanceof FTPError) {
console.error(getSftpError(err.code));
return {
status: 'error',
content: null,
error: getSftpError(err.code),
};
} else {
return {
status: 'error',
content: null,
error: err
}
}
} finally {
await endClient(client, context.auth.props.protocol);
}
},
});

View File

@@ -0,0 +1,82 @@
import { endClient, sftpAuth } from '../../index';
import { Property, createAction } from '@activepieces/pieces-framework';
import Client from 'ssh2-sftp-client';
import { Client as FTPClient, FTPError } from 'basic-ftp';
import { getClient, getProtocolBackwardCompatibility } from '../..';
import { Writable } from 'stream';
import { getSftpError } from './common';
async function readFTP(client: FTPClient, filePath: string) {
const chunks: Buffer[] = [];
const writeStream = new Writable({
write(chunk: Buffer, _encoding: string, callback: () => void) {
chunks.push(chunk);
callback();
}
});
await client.downloadTo(writeStream, filePath);
return Buffer.concat(chunks);
}
async function readSFTP(client: Client, filePath: string) {
const fileContent = await client.get(filePath);
await client.end();
return fileContent as Buffer;
}
export const readFileContent = createAction({
auth: sftpAuth,
name: 'read_file_content',
displayName: 'Read File Content',
description: 'Read the content of a file.',
props: {
filePath: Property.ShortText({
displayName: 'File Path',
required: true,
}),
},
async run(context) {
const client = await getClient(context.auth.props);
const filePath = context.propsValue['filePath'];
const fileName = filePath.split('/').pop() ?? filePath;
const protocolBackwardCompatibility = await getProtocolBackwardCompatibility(context.auth.props.protocol);
try {
let fileContent: Buffer;
switch (protocolBackwardCompatibility) {
case 'ftps':
case 'ftp':
fileContent = await readFTP(client as FTPClient, filePath);
break;
default:
case 'sftp':
fileContent = await readSFTP(client as Client, filePath);
break;
}
return {
file: await context.files.write({
fileName: fileName,
data: fileContent,
}),
};
}
catch (err) {
if (err instanceof FTPError) {
console.error(getSftpError(err.code));
return {
status: 'error',
content: null,
error: getSftpError(err.code),
};
} else {
return {
status: 'error',
content: null,
error: err
}
}
} finally {
await endClient(client, context.auth.props.protocol);
}
},
});

View File

@@ -0,0 +1,81 @@
import { endClient, sftpAuth } from '../../index';
import { Property, createAction } from '@activepieces/pieces-framework';
import Client from 'ssh2-sftp-client';
import { Client as FTPClient, FTPError } from 'basic-ftp';
import { getClient, getProtocolBackwardCompatibility } from '../..';
import { MarkdownVariant } from '@activepieces/shared';
import { getSftpError } from './common';
async function renameFTP(client: FTPClient, oldPath: string, newPath: string) {
await client.rename(oldPath, newPath);
}
async function renameSFTP(client: Client, oldPath: string, newPath: string) {
await client.rename(oldPath, newPath);
await client.end();
}
export const renameFileOrFolderAction = createAction({
auth: sftpAuth,
name: 'renameFileOrFolder',
displayName: 'Rename File or Folder',
description: 'Renames a file or folder at given path.',
props: {
information: Property.MarkDown({
value: 'Depending on the server you can also use this to move a file to another directory, as long as the directory exists.',
variant: MarkdownVariant.INFO,
}),
oldPath: Property.ShortText({
displayName: 'Old Path',
required: true,
description:
'The path of the file or folder to rename e.g. `./myfolder/test.mp3`',
}),
newPath: Property.ShortText({
displayName: 'New Path',
required: true,
description:
'The new path of the file or folder e.g. `./myfolder/new-name.mp3`',
}),
},
async run(context) {
const client = await getClient(context.auth.props);
const oldPath = context.propsValue.oldPath;
const newPath = context.propsValue.newPath;
const protocolBackwardCompatibility = await getProtocolBackwardCompatibility(context.auth.props.protocol);
try {
switch (protocolBackwardCompatibility) {
case 'ftps':
case 'ftp':
await renameFTP(client as FTPClient, oldPath, newPath);
break;
default:
case 'sftp':
await renameSFTP(client as Client, oldPath, newPath);
break;
}
return {
status: 'success',
};
}
catch (err) {
if (err instanceof FTPError) {
console.error(getSftpError(err.code));
return {
status: 'error',
content: null,
error: getSftpError(err.code),
};
} else {
return {
status: 'error',
content: null,
error: err
}
}
} finally {
await endClient(client, context.auth.props.protocol);
}
},
});

View File

@@ -0,0 +1,80 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import Client from 'ssh2-sftp-client';
import { Client as FTPClient, FTPError } from 'basic-ftp';
import { endClient, getClient, getProtocolBackwardCompatibility, sftpAuth } from '../..';
import { Readable } from 'stream';
import { getSftpError } from './common';
async function uploadFileToFTP(client: FTPClient, fileName: string, fileContent: { data: any }) {
const remoteDirectory = fileName.substring(0, fileName.lastIndexOf('/'));
await client.ensureDir(remoteDirectory);
await client.uploadFrom(Readable.from(fileContent.data), fileName);
}
async function uploadFileToSFTP(client: Client, fileName: string, fileContent: { data: any }) {
const remotePathExists = await client.exists(fileName);
if (!remotePathExists) {
const remoteDirectory = fileName.substring(0, fileName.lastIndexOf('/'));
await client.mkdir(remoteDirectory, true);
}
await client.put(fileContent.data, fileName);
await client.end();
}
export const uploadFileAction = createAction({
auth: sftpAuth,
name: 'upload_file',
displayName: 'Upload File',
description: 'Upload a file to the given path.',
props: {
fileName: Property.ShortText({
displayName: 'File Path',
required: true,
description:
'The path on the sftp server to store the file. e.g. `./myfolder/test.mp3`',
}),
fileContent: Property.File({
displayName: 'File content',
required: true,
}),
},
async run(context) {
const client = await getClient(context.auth.props);
const fileName = context.propsValue['fileName'];
const fileContent = context.propsValue['fileContent'];
const protocolBackwardCompatibility = await getProtocolBackwardCompatibility(context.auth.props.protocol);
try {
switch (protocolBackwardCompatibility) {
case 'ftps':
case 'ftp':
await uploadFileToFTP(client as FTPClient, fileName, fileContent);
break;
default:
case 'sftp':
await uploadFileToSFTP(client as Client, fileName, fileContent);
break;
}
return {
status: 'success',
};
}
catch (err) {
if (err instanceof FTPError) {
console.error(getSftpError(err.code));
return {
status: 'error',
content: null,
error: getSftpError(err.code),
};
} else {
return {
status: 'error',
content: null,
error: err
}
}
} finally {
await endClient(client, context.auth.props.protocol);
}
},
});

View File

@@ -0,0 +1,86 @@
import { PiecePropValueSchema, Property, createTrigger, TriggerStrategy, AppConnectionValueForAuthProperty } from '@activepieces/pieces-framework';
import { DedupeStrategy, Polling, pollingHelper } from '@activepieces/pieces-common';
import { sftpAuth, getClient, getProtocolBackwardCompatibility, endClient } from '../..';
import dayjs from 'dayjs';
import Client from 'ssh2-sftp-client';
import { Client as FTPClient, FileInfo as FTPFileInfo } from 'basic-ftp';
function getModifyTime(file: Client.FileInfo | FTPFileInfo, protocol: string): number {
return protocol === 'sftp' ?
(file as Client.FileInfo).modifyTime :
dayjs((file as FTPFileInfo).modifiedAt).valueOf();
}
const polling: Polling<AppConnectionValueForAuthProperty<typeof sftpAuth>, { path: string; ignoreHiddenFiles?: boolean }> = {
strategy: DedupeStrategy.TIMEBASED,
items: async ({ auth, propsValue, lastFetchEpochMS }) => {
let client: Client | FTPClient | null = null;
try {
const protocolBackwardCompatibility = await getProtocolBackwardCompatibility(auth.props.protocol);
client = await getClient(auth.props);
const files = await client.list(propsValue.path);
const filteredFiles = files.filter(file => {
const modTime = getModifyTime(file, protocolBackwardCompatibility);
return dayjs(modTime).valueOf() > lastFetchEpochMS;
});
const finalFiles: (Client.FileInfo | FTPFileInfo)[] = propsValue.ignoreHiddenFiles ?
filteredFiles.filter(file => !file.name.startsWith('.')) :
filteredFiles;
return finalFiles.map(file => {
const modTime = getModifyTime(file, protocolBackwardCompatibility);
return {
data: {
...file,
path: `${propsValue.path}/${file.name}`,
},
epochMilliSeconds: dayjs(modTime).valueOf(),
};
});
} catch (err) {
return [];
} finally {
if (client) {
await endClient(client, auth.props.protocol);
}
}
},
};
export const newOrModifiedFile = createTrigger({
auth: sftpAuth,
name: 'new_file',
displayName: 'New File',
description: 'Trigger when a new file is created or modified.',
props: {
path: Property.ShortText({
displayName: 'Path',
description: 'The path to watch for new files',
required: true,
defaultValue: './',
}),
ignoreHiddenFiles: Property.Checkbox({
displayName: 'Ignore hidden files',
description: 'Ignore hidden files',
required: false,
defaultValue: false,
}),
},
type: TriggerStrategy.POLLING,
onEnable: async (context) => {
await pollingHelper.onEnable(polling, context);
},
onDisable: async (context) => {
await pollingHelper.onDisable(polling, context);
},
run: async (context) => {
return await pollingHelper.poll(polling, context);
},
test: async (context) => {
return await pollingHelper.test(polling, context);
},
sampleData: null,
});

View File

@@ -0,0 +1,16 @@
{
"extends": "../../../../tsconfig.base.json",
"files": [],
"include": [],
"references": [
{
"path": "./tsconfig.lib.json"
}
],
"compilerOptions": {
"forceConsistentCasingInFileNames": true,
"strict": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true
}
}

View File

@@ -0,0 +1,11 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"module": "commonjs",
"outDir": "../../../../dist/out-tsc",
"declaration": true,
"types": ["node"]
},
"exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"],
"include": ["src/**/*.ts"]
}