File Management

Manage your uploaded files with list, get, and delete operations.

List Files

Retrieve a paginated list of files with filtering and sorting options.

Basic Listing

import { DropperClient } from '@dropper/core'

const client = new DropperClient({
  publishableKey: 'pk_dropper_test_xxx',
})

const response = await client.listFiles()

console.log(`Total files: ${response.total}`)
response.data.forEach((file) => {
  console.log(`- ${file.originalFilename} (${file.size} bytes)`)
})

ListFilesParams

interface ListFilesParams {
  folderId?: string                                    // Filter by folder
  search?: string                                      // Search by filename
  mimeType?: string                                    // Filter by MIME type
  sortBy?: 'name' | 'size' | 'createdAt' | 'updatedAt' // Sort field
  sortOrder?: 'asc' | 'desc'                          // Sort direction
  page?: number                                        // Page number (default: 1)
  limit?: number                                       // Items per page (default: 20)
}

ListFilesResponse

interface ListFilesResponse {
  data: FileResponseDto[]  // Array of files
  total: number           // Total number of files
  page: number            // Current page
  limit: number           // Items per page
}

Filtering Files

By Folder

List files in a specific folder:

const response = await client.listFiles({
  folderId: 'folder_abc123',
})

By MIME Type

Filter files by type:

// Images only
const images = await client.listFiles({
  mimeType: 'image/*',
})

// PDFs only
const pdfs = await client.listFiles({
  mimeType: 'application/pdf',
})

// Videos only
const videos = await client.listFiles({
  mimeType: 'video/*',
})

By Search Query

Search files by filename:

const response = await client.listFiles({
  search: 'invoice',
})

Sorting Files

Sort by Name

const response = await client.listFiles({
  sortBy: 'name',
  sortOrder: 'asc',
})

Sort by Size

const response = await client.listFiles({
  sortBy: 'size',
  sortOrder: 'desc', // Largest first
})

Sort by Date

// Most recent first
const response = await client.listFiles({
  sortBy: 'createdAt',
  sortOrder: 'desc',
})

// Oldest first
const response = await client.listFiles({
  sortBy: 'updatedAt',
  sortOrder: 'asc',
})

Pagination

Handle large file lists with pagination:

const page = 1
const limit = 20

const response = await client.listFiles({
  page,
  limit,
})

console.log(`Showing ${response.data.length} of ${response.total} files`)
console.log(`Page ${response.page} of ${Math.ceil(response.total / response.limit)}`)

Load More Pattern

let page = 1
const limit = 20
const allFiles: FileResponseDto[] = []

while (true) {
  const response = await client.listFiles({ page, limit })
  allFiles.push(...response.data)
  
  if (allFiles.length >= response.total) {
    break
  }
  
  page++
}

console.log(`Loaded ${allFiles.length} files`)

Get Single File

Retrieve details for a specific file:

const file = await client.getFile('file_abc123')

console.log('File details:')
console.log(`- Name: ${file.originalFilename}`)
console.log(`- Size: ${file.size} bytes`)
console.log(`- Type: ${file.mimeType}`)
console.log(`- URL: ${file.url}`)
console.log(`- Created: ${file.createdAt}`)

Delete File

Remove a file from storage:

await client.deleteFile('file_abc123')
console.log('File deleted successfully')

With Error Handling

try {
  await client.deleteFile('file_abc123')
  console.log('File deleted successfully')
} catch (error) {
  if (error.statusCode === 404) {
    console.error('File not found')
  } else if (error.statusCode === 403) {
    console.error('Permission denied')
  } else {
    console.error('Delete failed:', error.message)
  }
}

FileResponseDto

The file object returned by the API:

interface FileResponseDto {
  id: string                    // Unique file ID
  originalFilename: string      // Original filename
  mimeType: string             // MIME type (e.g., "image/jpeg")
  size: number                 // File size in bytes
  storagePath: string          // Storage path
  isPublic: boolean            // Public access flag
  extension?: string           // File extension (e.g., "jpg")
  virtualPath?: string         // Virtual path
  width?: number               // Image width (if image)
  height?: number              // Image height (if image)
  duration?: number            // Video duration (if video)
  url: string                  // Public URL
  thumbnailUrl?: string        // Thumbnail URL (if image/video)
  folderId?: string            // Parent folder ID
  appId: string                // App ID
  metadata?: Record<string, unknown> // Custom metadata
  createdAt: string            // ISO timestamp
  updatedAt: string            // ISO timestamp
}

Complete Examples

File Gallery

import { DropperClient, formatFileSize } from '@dropper/core'

const client = new DropperClient({
  publishableKey: process.env.DROPPER_KEY!,
})

async function loadImageGallery() {
  const response = await client.listFiles({
    mimeType: 'image/*',
    sortBy: 'createdAt',
    sortOrder: 'desc',
    limit: 50,
  })
  
  console.log(`Found ${response.total} images`)
  
  response.data.forEach((file) => {
    console.log(`Image: ${file.originalFilename}`)
    console.log(`  Size: ${formatFileSize(file.size)}`)
    console.log(`  Dimensions: ${file.width}x${file.height}`)
    console.log(`  URL: ${file.url}`)
    console.log(`  Thumbnail: ${file.thumbnailUrl}`)
    console.log()
  })
}

File Search

async function searchFiles(query: string) {
  const response = await client.listFiles({
    search: query,
    sortBy: 'name',
    sortOrder: 'asc',
  })
  
  if (response.total === 0) {
    console.log(`No files found for "${query}"`)
    return []
  }
  
  console.log(`Found ${response.total} files matching "${query}"`)
  return response.data
}

Bulk Delete

async function deleteMultipleFiles(fileIds: string[]) {
  const results = await Promise.allSettled(
    fileIds.map((id) => client.deleteFile(id))
  )
  
  const successful = results.filter((r) => r.status === 'fulfilled').length
  const failed = results.filter((r) => r.status === 'rejected').length
  
  console.log(`Deleted ${successful} files`)
  if (failed > 0) {
    console.error(`Failed to delete ${failed} files`)
  }
}

File Statistics

async function getFileStatistics() {
  const response = await client.listFiles({
    limit: 1000, // Get more files for accurate stats
  })
  
  const totalSize = response.data.reduce((sum, file) => sum + file.size, 0)
  const avgSize = totalSize / response.data.length
  
  const byType = response.data.reduce((acc, file) => {
    const category = file.mimeType.split('/')[0]
    acc[category] = (acc[category] || 0) + 1
    return acc
  }, {} as Record<string, number>)
  
  console.log('File Statistics:')
  console.log(`Total files: ${response.total}`)
  console.log(`Total size: ${formatFileSize(totalSize)}`)
  console.log(`Average size: ${formatFileSize(avgSize)}`)
  console.log('By type:', byType)
}

Best Practices

1. Use Pagination

Always use pagination for large file lists:

const response = await client.listFiles({
  page: 1,
  limit: 20,
})

2. Filter Early

Apply filters to reduce data transfer:

// Good: Filter on server
const images = await client.listFiles({
  mimeType: 'image/*',
})

// Bad: Filter on client
const all = await client.listFiles()
const images = all.data.filter(f => f.mimeType.startsWith('image/'))

3. Cache Results

Cache file lists to reduce API calls:

let cachedFiles: FileResponseDto[] | null = null
let cacheTime: number = 0
const CACHE_DURATION = 60000 // 1 minute

async function getFiles() {
  const now = Date.now()
  
  if (cachedFiles && now - cacheTime < CACHE_DURATION) {
    return cachedFiles
  }
  
  const response = await client.listFiles()
  cachedFiles = response.data
  cacheTime = now
  
  return cachedFiles
}

4. Handle Errors

Always handle errors when deleting files:

try {
  await client.deleteFile(fileId)
  showSuccess('File deleted')
} catch (error) {
  showError(`Failed to delete: ${error.message}`)
}

Next Steps