mirror of
https://github.com/simstudioai/sim.git
synced 2026-02-03 03:04:57 -05:00
fix types
This commit is contained in:
@@ -12,6 +12,33 @@ export const dynamic = 'force-dynamic'
|
||||
|
||||
const logger = createLogger('GitHubLatestCommitAPI')
|
||||
|
||||
interface GitHubErrorResponse {
|
||||
message?: string
|
||||
}
|
||||
|
||||
interface GitHubCommitResponse {
|
||||
sha: string
|
||||
html_url: string
|
||||
commit: {
|
||||
message: string
|
||||
author: { name: string; email: string; date: string }
|
||||
committer: { name: string; email: string; date: string }
|
||||
}
|
||||
author?: { login: string; avatar_url: string; html_url: string }
|
||||
committer?: { login: string; avatar_url: string; html_url: string }
|
||||
stats?: { additions: number; deletions: number; total: number }
|
||||
files?: Array<{
|
||||
filename: string
|
||||
status: string
|
||||
additions: number
|
||||
deletions: number
|
||||
changes: number
|
||||
patch?: string
|
||||
raw_url?: string
|
||||
blob_url?: string
|
||||
}>
|
||||
}
|
||||
|
||||
const GitHubLatestCommitSchema = z.object({
|
||||
owner: z.string().min(1, 'Owner is required'),
|
||||
repo: z.string().min(1, 'Repo is required'),
|
||||
@@ -61,7 +88,7 @@ export async function POST(request: NextRequest) {
|
||||
})
|
||||
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json().catch(() => ({}))
|
||||
const errorData = (await response.json().catch(() => ({}))) as GitHubErrorResponse
|
||||
logger.error(`[${requestId}] GitHub API error`, {
|
||||
status: response.status,
|
||||
error: errorData,
|
||||
@@ -72,7 +99,7 @@ export async function POST(request: NextRequest) {
|
||||
)
|
||||
}
|
||||
|
||||
const data = await response.json()
|
||||
const data = (await response.json()) as GitHubCommitResponse
|
||||
|
||||
const content = `Latest commit: "${data.commit.message}" by ${data.commit.author.name} on ${data.commit.author.date}. SHA: ${data.sha}`
|
||||
|
||||
|
||||
@@ -19,6 +19,21 @@ export const dynamic = 'force-dynamic'
|
||||
|
||||
const logger = createLogger('GoogleDriveDownloadAPI')
|
||||
|
||||
/** Google API error response structure */
|
||||
interface GoogleApiErrorResponse {
|
||||
error?: {
|
||||
message?: string
|
||||
code?: number
|
||||
status?: string
|
||||
}
|
||||
}
|
||||
|
||||
/** Google Drive revisions list response */
|
||||
interface GoogleDriveRevisionsResponse {
|
||||
revisions?: GoogleDriveRevision[]
|
||||
nextPageToken?: string
|
||||
}
|
||||
|
||||
const GoogleDriveDownloadSchema = z.object({
|
||||
accessToken: z.string().min(1, 'Access token is required'),
|
||||
fileId: z.string().min(1, 'File ID is required'),
|
||||
@@ -76,7 +91,9 @@ export async function POST(request: NextRequest) {
|
||||
)
|
||||
|
||||
if (!metadataResponse.ok) {
|
||||
const errorDetails = await metadataResponse.json().catch(() => ({}))
|
||||
const errorDetails = (await metadataResponse
|
||||
.json()
|
||||
.catch(() => ({}))) as GoogleApiErrorResponse
|
||||
logger.error(`[${requestId}] Failed to get file metadata`, {
|
||||
status: metadataResponse.status,
|
||||
error: errorDetails,
|
||||
@@ -87,7 +104,7 @@ export async function POST(request: NextRequest) {
|
||||
)
|
||||
}
|
||||
|
||||
const metadata: GoogleDriveFile = await metadataResponse.json()
|
||||
const metadata = (await metadataResponse.json()) as GoogleDriveFile
|
||||
const fileMimeType = metadata.mimeType
|
||||
|
||||
let fileBuffer: Buffer
|
||||
@@ -119,7 +136,9 @@ export async function POST(request: NextRequest) {
|
||||
)
|
||||
|
||||
if (!exportResponse.ok) {
|
||||
const exportError = await exportResponse.json().catch(() => ({}))
|
||||
const exportError = (await exportResponse
|
||||
.json()
|
||||
.catch(() => ({}))) as GoogleApiErrorResponse
|
||||
logger.error(`[${requestId}] Failed to export file`, {
|
||||
status: exportResponse.status,
|
||||
error: exportError,
|
||||
@@ -154,7 +173,9 @@ export async function POST(request: NextRequest) {
|
||||
)
|
||||
|
||||
if (!downloadResponse.ok) {
|
||||
const downloadError = await downloadResponse.json().catch(() => ({}))
|
||||
const downloadError = (await downloadResponse
|
||||
.json()
|
||||
.catch(() => ({}))) as GoogleApiErrorResponse
|
||||
logger.error(`[${requestId}] Failed to download file`, {
|
||||
status: downloadResponse.status,
|
||||
error: downloadError,
|
||||
@@ -182,8 +203,8 @@ export async function POST(request: NextRequest) {
|
||||
)
|
||||
|
||||
if (revisionsResponse.ok) {
|
||||
const revisionsData = await revisionsResponse.json()
|
||||
metadata.revisions = revisionsData.revisions as GoogleDriveRevision[]
|
||||
const revisionsData = (await revisionsResponse.json()) as GoogleDriveRevisionsResponse
|
||||
metadata.revisions = revisionsData.revisions
|
||||
logger.info(`[${requestId}] Fetched file revisions`, {
|
||||
fileId,
|
||||
revisionCount: metadata.revisions?.length || 0,
|
||||
|
||||
@@ -68,14 +68,14 @@ export async function GET(request: NextRequest) {
|
||||
|
||||
const contentType = imageResponse.headers.get('content-type') || 'image/jpeg'
|
||||
|
||||
const imageBlob = await imageResponse.blob()
|
||||
const imageArrayBuffer = await imageResponse.arrayBuffer()
|
||||
|
||||
if (imageBlob.size === 0) {
|
||||
logger.error(`[${requestId}] Empty image blob received`)
|
||||
if (imageArrayBuffer.byteLength === 0) {
|
||||
logger.error(`[${requestId}] Empty image received`)
|
||||
return new NextResponse('Empty image received', { status: 404 })
|
||||
}
|
||||
|
||||
return new NextResponse(imageBlob, {
|
||||
return new NextResponse(imageArrayBuffer, {
|
||||
headers: {
|
||||
'Content-Type': contentType,
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
|
||||
@@ -10,6 +10,24 @@ import { generateRequestId } from '@/lib/core/utils/request'
|
||||
|
||||
export const dynamic = 'force-dynamic'
|
||||
|
||||
/** Microsoft Graph API error response structure */
|
||||
interface GraphApiError {
|
||||
error?: {
|
||||
code?: string
|
||||
message?: string
|
||||
}
|
||||
}
|
||||
|
||||
/** Microsoft Graph API drive item metadata response */
|
||||
interface DriveItemMetadata {
|
||||
id?: string
|
||||
name?: string
|
||||
folder?: Record<string, unknown>
|
||||
file?: {
|
||||
mimeType?: string
|
||||
}
|
||||
}
|
||||
|
||||
const logger = createLogger('OneDriveDownloadAPI')
|
||||
|
||||
const OneDriveDownloadSchema = z.object({
|
||||
@@ -61,7 +79,7 @@ export async function POST(request: NextRequest) {
|
||||
)
|
||||
|
||||
if (!metadataResponse.ok) {
|
||||
const errorDetails = await metadataResponse.json().catch(() => ({}))
|
||||
const errorDetails = (await metadataResponse.json().catch(() => ({}))) as GraphApiError
|
||||
logger.error(`[${requestId}] Failed to get file metadata`, {
|
||||
status: metadataResponse.status,
|
||||
error: errorDetails,
|
||||
@@ -72,7 +90,7 @@ export async function POST(request: NextRequest) {
|
||||
)
|
||||
}
|
||||
|
||||
const metadata = await metadataResponse.json()
|
||||
const metadata = (await metadataResponse.json()) as DriveItemMetadata
|
||||
|
||||
if (metadata.folder && !metadata.file) {
|
||||
logger.error(`[${requestId}] Attempted to download a folder`, {
|
||||
@@ -110,7 +128,7 @@ export async function POST(request: NextRequest) {
|
||||
)
|
||||
|
||||
if (!downloadResponse.ok) {
|
||||
const downloadError = await downloadResponse.json().catch(() => ({}))
|
||||
const downloadError = (await downloadResponse.json().catch(() => ({}))) as GraphApiError
|
||||
logger.error(`[${requestId}] Failed to download file`, {
|
||||
status: downloadResponse.status,
|
||||
error: downloadError,
|
||||
|
||||
@@ -5,7 +5,6 @@ import { z } from 'zod'
|
||||
import { checkInternalAuth } from '@/lib/auth/hybrid'
|
||||
import {
|
||||
secureFetchWithPinnedIP,
|
||||
validateMicrosoftGraphId,
|
||||
validateUrlWithDNS,
|
||||
} from '@/lib/core/security/input-validation.server'
|
||||
import { generateRequestId } from '@/lib/core/utils/request'
|
||||
@@ -41,6 +40,48 @@ const OneDriveUploadSchema = z.object({
|
||||
conflictBehavior: z.enum(['fail', 'replace', 'rename']).optional().nullable(),
|
||||
})
|
||||
|
||||
/** Microsoft Graph DriveItem response */
|
||||
interface OneDriveFileData {
|
||||
id: string
|
||||
name: string
|
||||
size: number
|
||||
webUrl: string
|
||||
createdDateTime: string
|
||||
lastModifiedDateTime: string
|
||||
file?: { mimeType: string }
|
||||
parentReference?: { id: string; path: string }
|
||||
'@microsoft.graph.downloadUrl'?: string
|
||||
}
|
||||
|
||||
/** Microsoft Graph Excel range response */
|
||||
interface ExcelRangeData {
|
||||
address?: string
|
||||
addressLocal?: string
|
||||
values?: unknown[][]
|
||||
}
|
||||
|
||||
/** Validates Microsoft Graph item IDs (alphanumeric with some special chars) */
|
||||
function validateMicrosoftGraphId(
|
||||
id: string,
|
||||
paramName: string
|
||||
): { isValid: boolean; error?: string } {
|
||||
// Microsoft Graph IDs are typically alphanumeric, may include hyphens and exclamation marks
|
||||
const validIdPattern = /^[a-zA-Z0-9!-]+$/
|
||||
if (!validIdPattern.test(id)) {
|
||||
return {
|
||||
isValid: false,
|
||||
error: `Invalid ${paramName}: contains invalid characters`,
|
||||
}
|
||||
}
|
||||
if (id.length > 256) {
|
||||
return {
|
||||
isValid: false,
|
||||
error: `Invalid ${paramName}: exceeds maximum length`,
|
||||
}
|
||||
}
|
||||
return { isValid: true }
|
||||
}
|
||||
|
||||
async function secureFetchGraph(
|
||||
url: string,
|
||||
options: {
|
||||
@@ -215,7 +256,7 @@ export async function POST(request: NextRequest) {
|
||||
)
|
||||
}
|
||||
|
||||
const fileData = await uploadResponse.json()
|
||||
const fileData = (await uploadResponse.json()) as OneDriveFileData
|
||||
|
||||
let excelWriteResult: any | undefined
|
||||
const shouldWriteExcelContent =
|
||||
@@ -241,7 +282,7 @@ export async function POST(request: NextRequest) {
|
||||
)
|
||||
|
||||
if (sessionResp.ok) {
|
||||
const sessionData = await sessionResp.json()
|
||||
const sessionData = (await sessionResp.json()) as { id?: string }
|
||||
workbookSessionId = sessionData?.id
|
||||
}
|
||||
|
||||
@@ -262,7 +303,7 @@ export async function POST(request: NextRequest) {
|
||||
'listUrl'
|
||||
)
|
||||
if (listResp.ok) {
|
||||
const listData = await listResp.json()
|
||||
const listData = (await listResp.json()) as { value?: Array<{ name?: string }> }
|
||||
const firstSheetName = listData?.value?.[0]?.name
|
||||
if (firstSheetName) {
|
||||
sheetName = firstSheetName
|
||||
@@ -348,7 +389,7 @@ export async function POST(request: NextRequest) {
|
||||
details: errorText,
|
||||
}
|
||||
} else {
|
||||
const writeData = await excelWriteResponse.json()
|
||||
const writeData = (await excelWriteResponse.json()) as ExcelRangeData
|
||||
const addr = writeData.address || writeData.addressLocal
|
||||
const v = writeData.values || []
|
||||
excelWriteResult = {
|
||||
@@ -356,7 +397,7 @@ export async function POST(request: NextRequest) {
|
||||
updatedRange: addr,
|
||||
updatedRows: Array.isArray(v) ? v.length : undefined,
|
||||
updatedColumns: Array.isArray(v) && v[0] ? v[0].length : undefined,
|
||||
updatedCells: Array.isArray(v) && v[0] ? v.length * (v[0] as any[]).length : undefined,
|
||||
updatedCells: Array.isArray(v) && v[0] ? v.length * v[0].length : undefined,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,18 @@ export const dynamic = 'force-dynamic'
|
||||
|
||||
const logger = createLogger('PipedriveGetFilesAPI')
|
||||
|
||||
interface PipedriveFile {
|
||||
id?: number
|
||||
name?: string
|
||||
url?: string
|
||||
}
|
||||
|
||||
interface PipedriveApiResponse {
|
||||
success: boolean
|
||||
data?: PipedriveFile[]
|
||||
error?: string
|
||||
}
|
||||
|
||||
const PipedriveGetFilesSchema = z.object({
|
||||
accessToken: z.string().min(1, 'Access token is required'),
|
||||
deal_id: z.string().optional().nullable(),
|
||||
@@ -70,7 +82,7 @@ export async function POST(request: NextRequest) {
|
||||
},
|
||||
})
|
||||
|
||||
const data = await response.json()
|
||||
const data = (await response.json()) as PipedriveApiResponse
|
||||
|
||||
if (!data.success) {
|
||||
logger.error(`[${requestId}] Pipedrive API request failed`, { data })
|
||||
|
||||
@@ -3,10 +3,9 @@ import { createLogger } from '@sim/logger'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { z } from 'zod'
|
||||
import { checkInternalAuth } from '@/lib/auth/hybrid'
|
||||
import { validateAwsRegion, validateS3BucketName } from '@/lib/core/security/input-validation'
|
||||
import {
|
||||
secureFetchWithPinnedIP,
|
||||
validateAwsRegion,
|
||||
validateS3BucketName,
|
||||
validateUrlWithDNS,
|
||||
} from '@/lib/core/security/input-validation.server'
|
||||
import { generateRequestId } from '@/lib/core/utils/request'
|
||||
|
||||
@@ -13,6 +13,36 @@ export const dynamic = 'force-dynamic'
|
||||
|
||||
const logger = createLogger('TwilioGetRecordingAPI')
|
||||
|
||||
interface TwilioRecordingResponse {
|
||||
sid?: string
|
||||
call_sid?: string
|
||||
duration?: string
|
||||
status?: string
|
||||
channels?: number
|
||||
source?: string
|
||||
price?: string
|
||||
price_unit?: string
|
||||
uri?: string
|
||||
error_code?: number
|
||||
message?: string
|
||||
error_message?: string
|
||||
}
|
||||
|
||||
interface TwilioErrorResponse {
|
||||
message?: string
|
||||
}
|
||||
|
||||
interface TwilioTranscription {
|
||||
transcription_text?: string
|
||||
status?: string
|
||||
price?: string
|
||||
price_unit?: string
|
||||
}
|
||||
|
||||
interface TwilioTranscriptionsResponse {
|
||||
transcriptions?: TwilioTranscription[]
|
||||
}
|
||||
|
||||
const TwilioGetRecordingSchema = z.object({
|
||||
accountSid: z.string().min(1, 'Account SID is required'),
|
||||
authToken: z.string().min(1, 'Auth token is required'),
|
||||
@@ -67,7 +97,7 @@ export async function POST(request: NextRequest) {
|
||||
})
|
||||
|
||||
if (!infoResponse.ok) {
|
||||
const errorData = await infoResponse.json().catch(() => ({}))
|
||||
const errorData = (await infoResponse.json().catch(() => ({}))) as TwilioErrorResponse
|
||||
logger.error(`[${requestId}] Twilio API error`, {
|
||||
status: infoResponse.status,
|
||||
error: errorData,
|
||||
@@ -78,7 +108,7 @@ export async function POST(request: NextRequest) {
|
||||
)
|
||||
}
|
||||
|
||||
const data = await infoResponse.json()
|
||||
const data = (await infoResponse.json()) as TwilioRecordingResponse
|
||||
|
||||
if (data.error_code) {
|
||||
return NextResponse.json({
|
||||
@@ -126,7 +156,8 @@ export async function POST(request: NextRequest) {
|
||||
)
|
||||
|
||||
if (transcriptionResponse.ok) {
|
||||
const transcriptionData = await transcriptionResponse.json()
|
||||
const transcriptionData =
|
||||
(await transcriptionResponse.json()) as TwilioTranscriptionsResponse
|
||||
|
||||
if (transcriptionData.transcriptions && transcriptionData.transcriptions.length > 0) {
|
||||
const transcription = transcriptionData.transcriptions[0]
|
||||
|
||||
@@ -13,6 +13,40 @@ export const dynamic = 'force-dynamic'
|
||||
|
||||
const logger = createLogger('ZoomGetRecordingsAPI')
|
||||
|
||||
interface ZoomRecordingFile {
|
||||
id?: string
|
||||
meeting_id?: string
|
||||
recording_start?: string
|
||||
recording_end?: string
|
||||
file_type?: string
|
||||
file_extension?: string
|
||||
file_size?: number
|
||||
play_url?: string
|
||||
download_url?: string
|
||||
status?: string
|
||||
recording_type?: string
|
||||
}
|
||||
|
||||
interface ZoomRecordingsResponse {
|
||||
uuid?: string
|
||||
id?: string | number
|
||||
account_id?: string
|
||||
host_id?: string
|
||||
topic?: string
|
||||
type?: number
|
||||
start_time?: string
|
||||
duration?: number
|
||||
total_size?: number
|
||||
recording_count?: number
|
||||
share_url?: string
|
||||
recording_files?: ZoomRecordingFile[]
|
||||
}
|
||||
|
||||
interface ZoomErrorResponse {
|
||||
message?: string
|
||||
code?: number
|
||||
}
|
||||
|
||||
const ZoomGetRecordingsSchema = z.object({
|
||||
accessToken: z.string().min(1, 'Access token is required'),
|
||||
meetingId: z.string().min(1, 'Meeting ID is required'),
|
||||
@@ -72,7 +106,7 @@ export async function POST(request: NextRequest) {
|
||||
})
|
||||
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json().catch(() => ({}))
|
||||
const errorData = (await response.json().catch(() => ({}))) as ZoomErrorResponse
|
||||
logger.error(`[${requestId}] Zoom API error`, {
|
||||
status: response.status,
|
||||
error: errorData,
|
||||
@@ -83,7 +117,7 @@ export async function POST(request: NextRequest) {
|
||||
)
|
||||
}
|
||||
|
||||
const data = await response.json()
|
||||
const data = (await response.json()) as ZoomRecordingsResponse
|
||||
const files: Array<{
|
||||
name: string
|
||||
mimeType: string
|
||||
@@ -152,7 +186,7 @@ export async function POST(request: NextRequest) {
|
||||
total_size: data.total_size,
|
||||
recording_count: data.recording_count,
|
||||
share_url: data.share_url,
|
||||
recording_files: (data.recording_files || []).map((file: any) => ({
|
||||
recording_files: (data.recording_files || []).map((file: ZoomRecordingFile) => ({
|
||||
id: file.id,
|
||||
meeting_id: file.meeting_id,
|
||||
recording_start: file.recording_start,
|
||||
|
||||
@@ -779,7 +779,7 @@ export const DiscordBlock: BlockConfig<DiscordResponse> = {
|
||||
reason: { type: 'string', description: 'Reason for moderation action' },
|
||||
archived: { type: 'string', description: 'Archive status (true/false)' },
|
||||
attachmentFiles: { type: 'json', description: 'Files to attach (UI upload)' },
|
||||
files: { type: 'file[]', description: 'Files to attach (UserFile array)' },
|
||||
files: { type: 'array', description: 'Files to attach (UserFile array)' },
|
||||
limit: { type: 'number', description: 'Message limit' },
|
||||
autoArchiveDuration: { type: 'number', description: 'Thread auto-archive duration in minutes' },
|
||||
channelType: { type: 'number', description: 'Discord channel type (0=text, 2=voice, etc.)' },
|
||||
|
||||
@@ -924,10 +924,10 @@ const googleSlidesV2SubBlocks = (GoogleSlidesBlock.subBlocks || []).flatMap((sub
|
||||
{
|
||||
id: 'imageFileReference',
|
||||
title: 'Image',
|
||||
type: 'short-input',
|
||||
type: 'short-input' as const,
|
||||
canonicalParamId: 'imageFile',
|
||||
placeholder: 'Reference image from previous blocks',
|
||||
mode: 'advanced',
|
||||
mode: 'advanced' as const,
|
||||
required: true,
|
||||
condition: { field: 'operation', value: 'add_image' },
|
||||
},
|
||||
@@ -950,9 +950,9 @@ export const GoogleSlidesV2Block: BlockConfig<GoogleSlidesResponse> = {
|
||||
hideFromToolbar: false,
|
||||
subBlocks: googleSlidesV2SubBlocks,
|
||||
tools: {
|
||||
...GoogleSlidesBlock.tools,
|
||||
access: GoogleSlidesBlock.tools!.access,
|
||||
config: {
|
||||
...GoogleSlidesBlock.tools?.config,
|
||||
tool: GoogleSlidesBlock.tools!.config!.tool,
|
||||
params: (params) => {
|
||||
const baseParams = GoogleSlidesBlock.tools?.config?.params
|
||||
if (!baseParams) {
|
||||
|
||||
@@ -1025,7 +1025,7 @@ Return ONLY the comment text - no explanations.`,
|
||||
commentId: { type: 'string', description: 'Comment ID for update/delete operations' },
|
||||
// Attachment operation inputs
|
||||
attachmentFiles: { type: 'json', description: 'Files to attach (UI upload)' },
|
||||
files: { type: 'file[]', description: 'Files to attach (UserFile array)' },
|
||||
files: { type: 'array', description: 'Files to attach (UserFile array)' },
|
||||
attachmentId: { type: 'string', description: 'Attachment ID for delete operation' },
|
||||
// Worklog operation inputs
|
||||
timeSpentSeconds: {
|
||||
|
||||
@@ -392,7 +392,7 @@ export const OutlookBlock: BlockConfig<OutlookResponse> = {
|
||||
body: { type: 'string', description: 'Email content' },
|
||||
contentType: { type: 'string', description: 'Content type (Text or HTML)' },
|
||||
attachmentFiles: { type: 'json', description: 'Files to attach (UI upload)' },
|
||||
attachments: { type: 'file[]', description: 'Files to attach (UserFile array)' },
|
||||
attachments: { type: 'array', description: 'Files to attach (UserFile array)' },
|
||||
// Forward operation inputs
|
||||
messageId: { type: 'string', description: 'Message ID to forward' },
|
||||
comment: { type: 'string', description: 'Optional comment for forwarding' },
|
||||
|
||||
@@ -600,7 +600,7 @@ Return ONLY the HTML content.`,
|
||||
mailTemplateId: { type: 'string', description: 'Template ID for sending mail' },
|
||||
dynamicTemplateData: { type: 'json', description: 'Dynamic template data' },
|
||||
attachmentFiles: { type: 'json', description: 'Files to attach (UI upload)' },
|
||||
attachments: { type: 'file[]', description: 'Files to attach (UserFile array)' },
|
||||
attachments: { type: 'array', description: 'Files to attach (UserFile array)' },
|
||||
// Contact inputs
|
||||
email: { type: 'string', description: 'Contact email' },
|
||||
firstName: { type: 'string', description: 'Contact first name' },
|
||||
|
||||
@@ -279,7 +279,7 @@ export const SftpBlock: BlockConfig<SftpUploadResult> = {
|
||||
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: 'file[]', description: 'Files to upload (UserFile array)' },
|
||||
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' },
|
||||
|
||||
@@ -196,7 +196,7 @@ export const SmtpBlock: BlockConfig<SmtpSendMailResult> = {
|
||||
cc: { type: 'string', description: 'CC recipients (comma-separated)' },
|
||||
bcc: { type: 'string', description: 'BCC recipients (comma-separated)' },
|
||||
replyTo: { type: 'string', description: 'Reply-to email address' },
|
||||
attachments: { type: 'file[]', description: 'Files to attach (UserFile array)' },
|
||||
attachments: { type: 'array', description: 'Files to attach (UserFile array)' },
|
||||
},
|
||||
|
||||
outputs: {
|
||||
|
||||
@@ -351,7 +351,7 @@ export const TelegramBlock: BlockConfig<TelegramResponse> = {
|
||||
type: 'json',
|
||||
description: 'Files to attach (UI upload)',
|
||||
},
|
||||
files: { type: 'file[]', description: 'Files to attach (UserFile array)' },
|
||||
files: { type: 'array', description: 'Files to attach (UserFile array)' },
|
||||
caption: { type: 'string', description: 'Caption for media' },
|
||||
messageId: { type: 'string', description: 'Message ID to delete' },
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user