Files
simstudioai--sim/apps/sim/blocks/blocks/sftp.ts
T
wehub-resource-sync d25d482dc2
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled
Publish CLI Package / publish-npm (push) Has been cancelled
Publish Python SDK / publish-pypi (push) Has been cancelled
Publish TypeScript SDK / publish-npm (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:20:55 +08:00

428 lines
16 KiB
TypeScript

import {
ClipboardList,
Download,
File,
Search,
Server,
TrashOutline,
Upload,
} from '@sim/emcn/icons'
import { SftpIcon } from '@/components/icons'
import type { BlockConfig, BlockMeta } from '@/blocks/types'
import { AuthMode, IntegrationType } from '@/blocks/types'
import { normalizeFileInput } from '@/blocks/utils'
import type { SftpUploadResult } from '@/tools/sftp/types'
export const SftpBlock: BlockConfig<SftpUploadResult> = {
type: 'sftp',
name: 'SFTP',
description: 'Transfer files via SFTP (SSH File Transfer Protocol)',
longDescription:
'Upload, download, list, and manage files on remote servers via SFTP. Supports both password and private key authentication for secure file transfers.',
docsLink: 'https://docs.sim.ai/integrations/sftp',
category: 'tools',
integrationType: IntegrationType.Documents,
bgColor: '#2D3748',
icon: SftpIcon,
authMode: AuthMode.ApiKey,
subBlocks: [
{
id: 'operation',
title: 'Operation',
type: 'dropdown',
options: [
{ label: 'Upload Files', id: 'sftp_upload' },
{ label: 'Create File', id: 'sftp_create' },
{ label: 'Download File', id: 'sftp_download' },
{ label: 'List Directory', id: 'sftp_list' },
{ label: 'Delete File/Directory', id: 'sftp_delete' },
{ label: 'Create Directory', id: 'sftp_mkdir' },
],
value: () => 'sftp_upload',
},
{
id: 'host',
title: 'SFTP Host',
type: 'short-input',
placeholder: 'sftp.example.com or 192.168.1.100',
required: true,
},
{
id: 'port',
title: 'SFTP Port',
type: 'short-input',
placeholder: '22',
value: () => '22',
},
{
id: 'username',
title: 'Username',
type: 'short-input',
placeholder: 'sftp-user',
required: true,
},
{
id: 'authMethod',
title: 'Authentication Method',
type: 'dropdown',
options: [
{ label: 'Password', id: 'password' },
{ label: 'Private Key', id: 'privateKey' },
],
value: () => 'password',
},
{
id: 'password',
title: 'Password',
type: 'short-input',
password: true,
placeholder: 'Your SFTP password',
condition: { field: 'authMethod', value: 'password' },
dependsOn: ['authMethod'],
},
{
id: 'privateKey',
title: 'Private Key',
type: 'code',
placeholder: '-----BEGIN OPENSSH PRIVATE KEY-----\n...',
condition: { field: 'authMethod', value: 'privateKey' },
dependsOn: ['authMethod'],
},
{
id: 'passphrase',
title: 'Passphrase',
type: 'short-input',
password: true,
placeholder: 'Passphrase for encrypted key (optional)',
condition: { field: 'authMethod', value: 'privateKey' },
dependsOn: ['authMethod'],
},
{
id: 'remotePath',
title: 'Remote Path',
type: 'short-input',
placeholder: '/home/user/uploads',
required: true,
},
{
id: 'uploadFiles',
title: 'Files to Upload',
type: 'file-upload',
canonicalParamId: 'files',
placeholder: 'Select files to upload',
mode: 'basic',
multiple: true,
required: false,
condition: { field: 'operation', value: 'sftp_upload' },
},
{
id: 'files',
title: 'File Reference',
type: 'short-input',
canonicalParamId: 'files',
placeholder: 'Reference file from previous block (e.g., {{block_name.file}})',
mode: 'advanced',
required: false,
condition: { field: 'operation', value: 'sftp_upload' },
},
{
id: 'overwrite',
title: 'Overwrite Existing Files',
type: 'switch',
defaultValue: true,
condition: { field: 'operation', value: ['sftp_upload', 'sftp_create'] },
},
{
id: 'permissions',
title: 'File Permissions',
type: 'short-input',
placeholder: '0644',
condition: { field: 'operation', value: ['sftp_upload', 'sftp_create'] },
mode: 'advanced',
},
{
id: 'fileName',
title: 'File Name',
type: 'short-input',
placeholder: 'filename.txt',
condition: { field: 'operation', value: 'sftp_create' },
required: true,
},
{
id: 'fileContent',
title: 'File Content',
type: 'code',
placeholder: 'Text content to write to the file',
condition: { field: 'operation', value: 'sftp_create' },
required: true,
},
{
id: 'encoding',
title: 'Output Encoding',
type: 'dropdown',
options: [
{ label: 'UTF-8 (Text)', id: 'utf-8' },
{ label: 'Base64 (Binary)', id: 'base64' },
],
value: () => 'utf-8',
condition: { field: 'operation', value: 'sftp_download' },
},
{
id: 'detailed',
title: 'Show Detailed Info',
type: 'switch',
defaultValue: false,
condition: { field: 'operation', value: 'sftp_list' },
},
{
id: 'recursive',
title: 'Recursive Delete',
type: 'switch',
defaultValue: false,
condition: { field: 'operation', value: 'sftp_delete' },
},
{
id: 'mkdirRecursive',
title: 'Create Parent Directories',
type: 'switch',
defaultValue: true,
condition: { field: 'operation', value: 'sftp_mkdir' },
},
],
tools: {
access: ['sftp_upload', 'sftp_download', 'sftp_list', 'sftp_delete', 'sftp_mkdir'],
config: {
tool: (params) => {
const operation = params.operation || 'sftp_upload'
if (operation === 'sftp_create') return 'sftp_upload'
return operation
},
params: (params) => {
const connectionConfig: Record<string, unknown> = {
host: params.host,
port:
typeof params.port === 'string' ? Number.parseInt(params.port, 10) : params.port || 22,
username: params.username,
}
if (params.authMethod === 'privateKey') {
connectionConfig.privateKey = params.privateKey
if (params.passphrase) {
connectionConfig.passphrase = params.passphrase
}
} else {
connectionConfig.password = params.password
}
const operation = params.operation || 'sftp_upload'
switch (operation) {
case 'sftp_upload':
return {
...connectionConfig,
remotePath: params.remotePath,
// files is the canonical param from uploadFiles (basic) or files (advanced)
files: normalizeFileInput(params.files),
overwrite: params.overwrite !== false,
permissions: params.permissions,
}
case 'sftp_create':
return {
...connectionConfig,
remotePath: params.remotePath,
fileContent: params.fileContent,
fileName: params.fileName,
overwrite: params.overwrite !== false,
permissions: params.permissions,
}
case 'sftp_download':
return {
...connectionConfig,
remotePath: params.remotePath,
encoding: params.encoding || 'utf-8',
}
case 'sftp_list':
return {
...connectionConfig,
remotePath: params.remotePath,
detailed: params.detailed || false,
}
case 'sftp_delete':
return {
...connectionConfig,
remotePath: params.remotePath,
recursive: params.recursive || false,
}
case 'sftp_mkdir':
return {
...connectionConfig,
remotePath: params.remotePath,
recursive: params.mkdirRecursive !== false,
}
default:
return {
...connectionConfig,
remotePath: params.remotePath,
}
}
},
},
},
inputs: {
operation: { type: 'string', description: 'SFTP operation to perform' },
host: { type: 'string', description: 'SFTP server hostname' },
port: { type: 'number', description: 'SFTP server port' },
username: { type: 'string', description: 'SFTP username' },
authMethod: { type: 'string', description: 'Authentication method (password or privateKey)' },
password: { type: 'string', description: 'Password for authentication' },
privateKey: { type: 'string', description: 'Private key for authentication' },
passphrase: { type: 'string', description: 'Passphrase for encrypted key' },
remotePath: { type: 'string', description: 'Remote path on the SFTP server' },
files: { type: 'array', description: 'Files to upload (UserFile array)' },
fileContent: { type: 'string', description: 'Direct content to upload' },
fileName: { type: 'string', description: 'File name for direct content' },
overwrite: { type: 'boolean', description: 'Overwrite existing files' },
permissions: { type: 'string', description: 'File permissions (e.g., 0644)' },
encoding: { type: 'string', description: 'Output encoding for download' },
detailed: { type: 'boolean', description: 'Show detailed file info' },
recursive: { type: 'boolean', description: 'Recursive delete' },
mkdirRecursive: { type: 'boolean', description: 'Create parent directories' },
},
outputs: {
success: { type: 'boolean', description: 'Whether the operation was successful' },
uploadedFiles: { type: 'json', description: 'Array of uploaded file details' },
file: { type: 'file', description: 'Downloaded file stored in execution files' },
fileName: { type: 'string', description: 'Downloaded file name' },
content: { type: 'string', description: 'Downloaded file content' },
size: { type: 'number', description: 'File size in bytes' },
entries: { type: 'json', description: 'Directory listing entries' },
count: { type: 'number', description: 'Number of entries' },
deletedPath: { type: 'string', description: 'Path that was deleted' },
createdPath: { type: 'string', description: 'Directory that was created' },
message: { type: 'string', description: 'Operation status message' },
error: { type: 'string', description: 'Error message if operation failed' },
},
}
export const SftpBlockMeta = {
tags: ['document-processing', 'automation'],
templates: [
{
icon: Download,
title: 'Pull new files from a remote drop folder',
prompt:
'Build a workflow that runs on a schedule, lists a remote SFTP drop folder, downloads any new files, and passes their contents into the workflow for processing.',
modules: ['scheduled', 'files', 'workflows'],
category: 'operations',
tags: ['files', 'automation', 'sftp'],
},
{
icon: Upload,
title: 'Push a generated report to a partner SFTP',
prompt:
'Build a workflow that generates a report file and uploads it to a partner SFTP server under a dated remote path.',
modules: ['files', 'workflows'],
category: 'operations',
tags: ['files', 'upload', 'sftp'],
},
{
icon: Server,
title: 'Mirror a local export to a remote directory',
prompt:
'Build a workflow that lists a remote SFTP directory, compares it to the files produced by an earlier block, and uploads any missing files to keep the remote directory in sync.',
modules: ['files', 'scheduled', 'workflows'],
category: 'operations',
tags: ['files', 'sync', 'sftp'],
},
{
icon: TrashOutline,
title: 'Archive and delete old files on a schedule',
prompt:
'Build a workflow that runs nightly, lists an SFTP directory, downloads files older than a threshold to archive them, and then deletes the originals from the remote server.',
modules: ['scheduled', 'files', 'workflows'],
category: 'operations',
tags: ['files', 'cleanup', 'sftp'],
},
{
icon: ClipboardList,
title: 'Notify Slack when new files land on SFTP',
prompt:
'Build a workflow that checks an SFTP inbox folder on a schedule and sends a Slack message listing any new files that have arrived since the last run.',
modules: ['scheduled', 'files', 'agent'],
category: 'operations',
tags: ['files', 'notifications', 'sftp'],
alsoIntegrations: ['slack'],
},
{
icon: Search,
title: 'Inventory a remote directory listing',
prompt:
'Build a workflow that lists a remote SFTP directory with detailed metadata and records the file names, sizes, and timestamps for auditing.',
modules: ['files', 'workflows', 'tables'],
category: 'operations',
tags: ['files', 'audit', 'sftp'],
},
{
icon: File,
title: 'Write a manifest file to a remote server',
prompt:
'Build a workflow that assembles a manifest of processed records and creates a manifest.txt file on a remote SFTP path so downstream systems know the batch is ready.',
modules: ['files', 'workflows'],
category: 'operations',
tags: ['files', 'manifest', 'sftp'],
},
{
icon: Download,
title: 'Download a remote file and summarize it',
prompt:
'Build a workflow that downloads a file from an SFTP server and passes its contents to an agent that summarizes the key points.',
modules: ['files', 'agent', 'workflows'],
category: 'operations',
tags: ['files', 'summarize', 'sftp'],
},
],
skills: [
{
name: 'pull-remote-drop-folder',
description: 'Poll a remote SFTP drop folder on a schedule and ingest any new files.',
content:
'# Pull Remote Drop Folder\n\nPeriodically fetch newly arrived files from a remote SFTP directory into a workflow.\n\n## Steps\n1. Use the List Directory operation to read the remote drop folder and inspect `entries`.\n2. Filter for files newer than the last processed timestamp.\n3. For each new file, use the Download File operation and read `file`/`content`.\n4. Hand the contents to downstream blocks for parsing.\n\n## Output\nNew remote files are downloaded and their contents are available for processing each run.',
},
{
name: 'push-report-to-partner',
description: 'Upload a generated report to a partner SFTP server under a dated path.',
content:
'# Push Report To Partner\n\nDeliver a generated file to an external partner over SFTP.\n\n## Steps\n1. Produce the report file in an earlier block.\n2. Use the Upload Files operation with the partner `remotePath` (e.g. `/outbound/2026-07-01/`).\n3. Enable overwrite only if same-day re-delivery is expected.\n4. Confirm delivery from `uploadedFiles`.\n\n## Output\nThe report lands on the partner SFTP server at the intended remote path.',
},
{
name: 'archive-and-cleanup',
description: 'Download aging remote files to archive them, then delete the originals.',
content:
'# Archive And Cleanup\n\nKeep a remote SFTP directory tidy by archiving and removing old files.\n\n## Steps\n1. List the target directory and identify files past the retention window.\n2. Download each stale file to archive it elsewhere.\n3. Use the Delete File/Directory operation to remove the original and check `deletedPath`.\n4. Schedule the workflow to run nightly.\n\n## Output\nAging files are preserved in an archive and cleared from the live remote directory.',
},
{
name: 'remote-directory-inventory',
description: 'Capture a detailed listing of a remote SFTP directory for auditing.',
content:
'# Remote Directory Inventory\n\nRecord what currently exists in a remote SFTP path.\n\n## Steps\n1. Use the List Directory operation with detailed info enabled.\n2. Read `entries` for names, sizes, and timestamps.\n3. Store the inventory in a table or log for auditing.\n\n## Output\nA point-in-time inventory of the remote directory is captured.',
},
],
} as const satisfies BlockMeta