or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

directory-operations.mdfile-operations.mdindex.mdnetwork-operations.mdpickers.mdstreaming.mdsystem-paths.md
tile.json

network-operations.mddocs/

Network Operations

Download files from URLs with progress tracking, resume capabilities, custom headers, and destination control for efficient network file operations.

Capabilities

File Download Operations

Download files from remote URLs with comprehensive options and error handling.

/**
 * Downloads a file from a URL to a specified destination
 * @param url URL of the file to download
 * @param destination Target directory or file path
 * @param options Download configuration options
 * @returns Promise resolving to the downloaded File instance
 */
static downloadFileAsync(
  url: string,
  destination: Directory | File,
  options?: DownloadOptions
): Promise<File>;

interface DownloadOptions {
  /** HTTP headers to send with the download request */
  headers?: { [key: string]: string };
}

Usage Examples:

import { File, Directory, Paths } from "expo-file-system";

// Basic file download to directory
const downloadDir = new Directory(Paths.document, "downloads");
downloadDir.create();

const imageUrl = "https://example.com/images/photo.jpg";
const downloadedImage = await File.downloadFileAsync(imageUrl, downloadDir);

console.log(`Downloaded: ${downloadedImage.name}`);
console.log(`Size: ${downloadedImage.size} bytes`);
console.log(`Location: ${downloadedImage.uri}`);

// Download to specific file path
const specificFile = new File(Paths.document, "profile-picture.jpg");
const profileImage = await File.downloadFileAsync(imageUrl, specificFile);

// Download with custom headers
const authenticatedDownload = await File.downloadFileAsync(
  "https://api.example.com/secure/document.pdf",
  downloadDir,
  {
    headers: {
      "Authorization": "Bearer your-auth-token",
      "User-Agent": "MyApp/1.0.0",
      "Accept": "application/pdf"
    }
  }
);

Download with Progress Tracking

Monitor download progress and handle large file downloads efficiently.

Usage Examples:

import { File, Directory, Paths } from "expo-file-system";

// Download with progress monitoring
async function downloadWithProgress(
  url: string,
  destination: Directory,
  onProgress?: (bytesDownloaded: number, totalBytes: number) => void
) {
  console.log(`Starting download: ${url}`);
  
  try {
    // Start download
    const downloadedFile = await File.downloadFileAsync(url, destination);
    
    // Note: Progress tracking would typically be implemented with
    // custom networking libraries or by checking file size periodically
    console.log(`Download completed: ${downloadedFile.name}`);
    console.log(`Final size: ${downloadedFile.size} bytes`);
    
    return downloadedFile;
    
  } catch (error) {
    console.error("Download failed:", error);
    throw error;
  }
}

// Download queue management
class DownloadManager {
  private downloadQueue: Array<{
    url: string;
    destination: Directory | File;
    options?: DownloadOptions;
  }> = [];
  
  private activeDownloads = 0;
  private maxConcurrentDownloads = 3;
  
  async addDownload(
    url: string, 
    destination: Directory | File, 
    options?: DownloadOptions
  ) {
    this.downloadQueue.push({ url, destination, options });
    this.processQueue();
  }
  
  private async processQueue() {
    if (this.activeDownloads >= this.maxConcurrentDownloads || this.downloadQueue.length === 0) {
      return;
    }
    
    const download = this.downloadQueue.shift()!;
    this.activeDownloads++;
    
    try {
      console.log(`Starting download: ${download.url}`);
      const file = await File.downloadFileAsync(
        download.url, 
        download.destination, 
        download.options
      );
      console.log(`Completed download: ${file.name}`);
      
    } catch (error) {
      console.error(`Download failed: ${download.url}`, error);
      
    } finally {
      this.activeDownloads--;
      // Process next item in queue
      setTimeout(() => this.processQueue(), 100);
    }
  }
}

// Usage
const downloadManager = new DownloadManager();
const downloadDir = new Directory(Paths.document, "downloads");

await downloadManager.addDownload("https://example.com/file1.zip", downloadDir);
await downloadManager.addDownload("https://example.com/file2.pdf", downloadDir);
await downloadManager.addDownload("https://example.com/file3.jpg", downloadDir);

Error Handling and Retry Logic

Robust error handling for network operations with retry mechanisms.

Usage Examples:

import { File, Directory, Paths } from "expo-file-system";

// Download with retry logic
async function downloadWithRetry(
  url: string,
  destination: Directory | File,
  options?: DownloadOptions,
  maxRetries: number = 3
): Promise<File> {
  let lastError: Error;
  
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      console.log(`Download attempt ${attempt}/${maxRetries}: ${url}`);
      
      const file = await File.downloadFileAsync(url, destination, options);
      console.log(`Download successful on attempt ${attempt}`);
      return file;
      
    } catch (error) {
      lastError = error as Error;
      console.warn(`Download attempt ${attempt} failed:`, error);
      
      if (attempt < maxRetries) {
        // Exponential backoff
        const delay = Math.pow(2, attempt) * 1000;
        console.log(`Retrying in ${delay}ms...`);
        await new Promise(resolve => setTimeout(resolve, delay));
      }
    }
  }
  
  throw new Error(`Download failed after ${maxRetries} attempts: ${lastError.message}`);
}

// Validate downloaded files
async function downloadAndValidate(
  url: string,
  destination: Directory,
  expectedSize?: number,
  expectedChecksum?: string
): Promise<File> {
  const downloadedFile = await downloadWithRetry(url, destination);
  
  // Validate file size
  if (expectedSize && downloadedFile.size !== expectedSize) {
    downloadedFile.delete();
    throw new Error(`File size mismatch: expected ${expectedSize}, got ${downloadedFile.size}`);
  }
  
  // Validate checksum
  if (expectedChecksum) {
    const fileInfo = downloadedFile.info({ md5: true });
    if (fileInfo.md5 !== expectedChecksum) {
      downloadedFile.delete();
      throw new Error(`Checksum mismatch: expected ${expectedChecksum}, got ${fileInfo.md5}`);
    }
  }
  
  console.log("File validation successful");
  return downloadedFile;
}

// Usage with validation
try {
  const validatedFile = await downloadAndValidate(
    "https://example.com/important-document.pdf",
    new Directory(Paths.document, "verified"),
    1024 * 1024, // Expected 1MB
    "5d41402abc4b2a76b9719d911017c592" // Expected MD5
  );
  
  console.log(`Verified download: ${validatedFile.name}`);
} catch (error) {
  console.error("Download validation failed:", error);
}

Batch Download Operations

Efficient batch downloading with progress tracking and error recovery.

Usage Examples:

import { File, Directory, Paths } from "expo-file-system";

interface DownloadTask {
  url: string;
  filename?: string;
  headers?: { [key: string]: string };
}

// Batch download with comprehensive tracking
async function batchDownload(
  tasks: DownloadTask[],
  destination: Directory,
  onProgress?: (completed: number, total: number, currentFile?: string) => void
): Promise<File[]> {
  const results: File[] = [];
  const errors: Array<{ task: DownloadTask; error: Error }> = [];
  
  for (let i = 0; i < tasks.length; i++) {
    const task = tasks[i];
    
    try {
      onProgress?.(i, tasks.length, task.filename || task.url);
      
      const targetFile = task.filename 
        ? new File(destination, task.filename)
        : destination;
        
      const downloadedFile = await File.downloadFileAsync(
        task.url,
        targetFile,
        { headers: task.headers }
      );
      
      results.push(downloadedFile);
      console.log(`Downloaded ${i + 1}/${tasks.length}: ${downloadedFile.name}`);
      
    } catch (error) {
      console.error(`Failed to download ${task.url}:`, error);
      errors.push({ task, error: error as Error });
    }
  }
  
  onProgress?.(tasks.length, tasks.length);
  
  if (errors.length > 0) {
    console.warn(`Batch download completed with ${errors.length} errors`);
    // Optionally retry failed downloads or report errors
  }
  
  return results;
}

// Download manifest file and process contents
async function downloadFromManifest(manifestUrl: string): Promise<File[]> {
  const manifestFile = await File.downloadFileAsync(
    manifestUrl,
    new File(Paths.cache, "download-manifest.json")
  );
  
  const manifestContent = await manifestFile.text();
  const manifest = JSON.parse(manifestContent);
  
  const downloadTasks: DownloadTask[] = manifest.files.map((item: any) => ({
    url: item.url,
    filename: item.name,
    headers: item.headers
  }));
  
  const downloadDir = new Directory(Paths.document, "manifest-downloads");
  downloadDir.create();
  
  const downloadedFiles = await batchDownload(
    downloadTasks,
    downloadDir,
    (completed, total, currentFile) => {
      console.log(`Progress: ${completed}/${total} - ${currentFile}`);
    }
  );
  
  // Clean up manifest file
  manifestFile.delete();
  
  return downloadedFiles;
}

// Smart caching with download fallback
async function getFileWithCache(
  url: string,
  cacheKey: string,
  maxAge: number = 24 * 60 * 60 * 1000 // 24 hours
): Promise<File> {
  const cacheDir = new Directory(Paths.cache, "downloaded-files");
  cacheDir.create();
  
  const cachedFile = new File(cacheDir, `${cacheKey}.cached`);
  
  // Check if cached file exists and is fresh
  if (cachedFile.exists) {
    const fileInfo = cachedFile.info();
    const age = Date.now() - (fileInfo.modificationTime || 0);
    
    if (age < maxAge) {
      console.log(`Using cached file: ${cacheKey}`);
      return cachedFile;
    } else {
      console.log(`Cache expired for: ${cacheKey}`);
      cachedFile.delete();
    }
  }
  
  // Download fresh copy
  console.log(`Downloading fresh copy: ${url}`);
  const downloadedFile = await File.downloadFileAsync(url, cachedFile);
  
  return downloadedFile;
}

// Usage examples
async function demonstrateNetworkOperations() {
  // Batch download example
  const downloadTasks: DownloadTask[] = [
    { 
      url: "https://example.com/image1.jpg", 
      filename: "image1.jpg" 
    },
    { 
      url: "https://api.example.com/data.json", 
      filename: "api-data.json",
      headers: { "Authorization": "Bearer token123" }
    },
    { 
      url: "https://example.com/document.pdf", 
      filename: "document.pdf" 
    }
  ];
  
  const downloadDir = new Directory(Paths.document, "batch-downloads");
  downloadDir.create();
  
  const downloadedFiles = await batchDownload(downloadTasks, downloadDir);
  console.log(`Successfully downloaded ${downloadedFiles.length} files`);
  
  // Smart caching example
  const apiData = await getFileWithCache(
    "https://api.example.com/config.json",
    "app-config",
    30 * 60 * 1000 // 30 minutes cache
  );
  
  const config = JSON.parse(await apiData.text());
  console.log("Loaded configuration:", config);
}

Authentication and Headers

Handle authenticated downloads and custom HTTP headers for API access.

Usage Examples:

import { File, Directory, Paths } from "expo-file-system";

// Authenticated download service
class AuthenticatedDownloadService {
  private authToken: string | null = null;
  private refreshTokenUrl: string;
  
  constructor(refreshTokenUrl: string) {
    this.refreshTokenUrl = refreshTokenUrl;
  }
  
  async setAuthToken(token: string) {
    this.authToken = token;
  }
  
  async refreshAuthToken(): Promise<string> {
    // Implementation would depend on your auth system
    const response = await fetch(this.refreshTokenUrl, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ refresh_token: this.authToken })
    });
    
    const result = await response.json();
    this.authToken = result.access_token;
    return this.authToken;
  }
  
  async downloadAuthenticatedFile(
    url: string,
    destination: Directory | File,
    additionalHeaders?: Record<string, string>
  ): Promise<File> {
    let attempts = 0;
    const maxAttempts = 2;
    
    while (attempts < maxAttempts) {
      try {
        const headers = {
          'Authorization': `Bearer ${this.authToken}`,
          'User-Agent': 'MyApp/1.0.0',
          ...additionalHeaders
        };
        
        return await File.downloadFileAsync(url, destination, { headers });
        
      } catch (error) {
        attempts++;
        
        // If unauthorized and we haven't tried refreshing, refresh token
        if (error && attempts === 1) {
          console.log("Auth failed, refreshing token...");
          await this.refreshAuthToken();
        } else {
          throw error;
        }
      }
    }
    
    throw new Error("Download failed after token refresh");
  }
}

// API-specific download patterns
class APIDownloadClient {
  private baseUrl: string;
  private apiKey: string;
  
  constructor(baseUrl: string, apiKey: string) {
    this.baseUrl = baseUrl;
    this.apiKey = apiKey;
  }
  
  async downloadReport(
    reportId: string,
    format: 'pdf' | 'xlsx' | 'csv',
    destination: Directory
  ): Promise<File> {
    const url = `${this.baseUrl}/reports/${reportId}/export?format=${format}`;
    const filename = `report-${reportId}.${format}`;
    
    const headers = {
      'X-API-Key': this.apiKey,
      'Accept': this.getContentType(format),
      'X-Request-ID': this.generateRequestId()
    };
    
    const targetFile = new File(destination, filename);
    return await File.downloadFileAsync(url, targetFile, { headers });
  }
  
  async downloadWithRateLimit(
    url: string,
    destination: Directory | File,
    rateLimitDelay: number = 1000
  ): Promise<File> {
    // Implement rate limiting
    await new Promise(resolve => setTimeout(resolve, rateLimitDelay));
    
    const headers = {
      'X-API-Key': this.apiKey,
      'X-Rate-Limit': 'respect'
    };
    
    return await File.downloadFileAsync(url, destination, { headers });
  }
  
  private getContentType(format: string): string {
    const types = {
      'pdf': 'application/pdf',
      'xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
      'csv': 'text/csv'
    };
    return types[format as keyof typeof types] || 'application/octet-stream';
  }
  
  private generateRequestId(): string {
    return Math.random().toString(36).substring(2, 15);
  }
}

// Usage examples
async function demonstrateAuthenticatedDownloads() {
  // Authenticated service usage
  const authService = new AuthenticatedDownloadService("https://api.example.com/auth/refresh");
  await authService.setAuthToken("initial-token");
  
  const protectedFile = await authService.downloadAuthenticatedFile(
    "https://api.example.com/protected/document.pdf",
    new Directory(Paths.document, "secure")
  );
  
  // API client usage
  const apiClient = new APIDownloadClient("https://api.example.com", "your-api-key");
  const reportsDir = new Directory(Paths.document, "reports");
  reportsDir.create();
  
  const pdfReport = await apiClient.downloadReport("report-123", "pdf", reportsDir);
  const excelReport = await apiClient.downloadReport("report-456", "xlsx", reportsDir);
  
  console.log(`Downloaded reports: ${pdfReport.name}, ${excelReport.name}`);
}