CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-uppy

Extensible JavaScript file upload widget with support for drag&drop, resumable uploads, previews, restrictions, file processing/encoding, remote providers like Instagram, Dropbox, Google Drive, S3 and more.

Pending
Overview
Eval results
Files

upload-handlers.mddocs/

Upload Handlers

Upload handler plugins manage the actual file upload process, supporting various protocols and destinations including resumable uploads, traditional HTTP uploads, and cloud storage services.

Capabilities

Resumable Uploads

Protocols that support resumable uploads for reliability and performance.

/**
 * Tus resumable upload protocol implementation
 */
class Tus<M extends Meta = {}, B extends Body = {}> extends BasePlugin<TusOptions> {
  constructor(uppy: Uppy<M, B>, options?: TusOptions);
}

interface TusOptions {
  endpoint: string;
  headers?: { [key: string]: string };
  chunkSize?: number;
  withCredentials?: boolean;
  overridePatchMethod?: boolean;
  retryDelays?: number[];
  parallelUploads?: number;
  removeFingerprintOnSuccess?: boolean;
  uploadDataDuringCreation?: boolean;
  urlStorage?: TusUrlStorage;
  fileReader?: TusFileReader;
  onBeforeRequest?: (req: HttpRequest) => void;
  onAfterResponse?: (req: HttpRequest, res: HttpResponse) => void;
  limit?: number;
  onShouldRetry?: (err: Error, retryAttempt: number, options: TusOptions) => boolean;
  metaFields?: string[];
  allowedMetaFields?: string[];
  locale?: Locale;
}

interface TusUrlStorage {
  findAllUploads(): Promise<{ [key: string]: string }>;
  findUploadsByFingerprint(fingerprint: string): Promise<string[]>;
  removeUpload(urlStorageKey: string): Promise<void>;
  addUpload(fingerprint: string, upload: { uploadUrl: string; urlStorageKey: string }): Promise<void>;
}

interface TusFileReader {
  slice(file: Blob, start: number, end: number): Blob;
}

Usage Example:

import { Uppy, Tus } from "uppy";

const uppy = new Uppy()
  .use(Tus, {
    endpoint: 'https://tusd.tusdemo.net/files/',
    chunkSize: 1024 * 1024, // 1MB chunks
    retryDelays: [0, 1000, 3000, 5000],
    parallelUploads: 3,
    removeFingerprintOnSuccess: true,
    headers: {
      'Authorization': 'Bearer ' + authToken
    },
    onBeforeRequest: (req) => {
      // Modify request before sending
      req.setHeader('X-Custom-Header', 'value');
    },
    onAfterResponse: (req, res) => {
      // Handle response
      console.log('Upload progress response:', res.getStatus());
    }
  });

Traditional HTTP Uploads

Standard HTTP upload implementations using XMLHttpRequest or fetch.

/**
 * XHR upload implementation for standard HTTP endpoints
 */
class XHRUpload<M extends Meta = {}, B extends Body = {}> extends BasePlugin<XHRUploadOptions<M, B>> {
  constructor(uppy: Uppy<M, B>, options?: XHRUploadOptions<M, B>);
}

interface XHRUploadOptions<M extends Meta = {}, B extends Body = {}> {
  endpoint: string;
  method?: 'POST' | 'PUT' | 'PATCH';
  formData?: boolean;
  fieldName?: string;
  allowedMetaFields?: string[];
  headers?: { [key: string]: string } | ((file: UppyFile<M, B>) => { [key: string]: string });
  bundle?: boolean;
  withCredentials?: boolean;
  timeout?: number;
  limit?: number;
  responseType?: '' | 'text' | 'json' | 'blob' | 'document' | 'arraybuffer';
  responseUrlFieldName?: string;
  getResponseData?: (responseText: string, response: XMLHttpRequest) => B;
  getResponseError?: (responseText: string, response: XMLHttpRequest) => Error;
  onBeforeRequest?: (xhr: XMLHttpRequest, file: UppyFile<M, B>) => void;
  validateStatus?: (status: number, responseText: string, response: XMLHttpRequest) => boolean;
  locale?: Locale;
}

Usage Examples:

// Standard form data upload
uppy.use(XHRUpload, {
  endpoint: '/api/upload',
  method: 'POST',
  formData: true,
  fieldName: 'file',
  headers: {
    'X-CSRF-Token': csrfToken
  },
  allowedMetaFields: ['name', 'caption', 'description'],
  limit: 5, // Max 5 concurrent uploads
  timeout: 30000, // 30 second timeout
  
  onBeforeRequest: (xhr, file) => {
    // Add file-specific headers
    xhr.setRequestHeader('X-File-Name', file.name);
    xhr.setRequestHeader('X-File-Size', file.size.toString());
  },
  
  getResponseData: (responseText, response) => {
    // Parse custom response format
    return JSON.parse(responseText);
  },
  
  validateStatus: (status, responseText, response) => {
    // Custom success validation
    return status >= 200 && status < 300;
  }
});

// JSON upload with custom headers per file
uppy.use(XHRUpload, {
  endpoint: '/api/files',
  method: 'PUT',
  formData: false,
  headers: (file) => ({
    'Content-Type': file.type,
    'X-File-ID': file.id,
    'Authorization': `Bearer ${getTokenForFile(file)}`
  }),
  responseType: 'json'
});

Cloud Storage Direct Upload

Direct upload to cloud storage services bypassing your server.

/**
 * AWS S3 direct upload implementation
 */
class AwsS3<M extends Meta = {}, B extends Body = {}> extends BasePlugin<AwsS3Options> {
  constructor(uppy: Uppy<M, B>, options?: AwsS3Options);
}

interface AwsS3Options {
  companionUrl?: string;
  companionHeaders?: { [key: string]: string };
  companionCookiesRule?: string;
  getUploadParameters?: (file: UppyFile<any, any>) => Promise<S3UploadParameters> | S3UploadParameters;
  timeout?: number;
  limit?: number;
  metaFields?: string[];
  allowedMetaFields?: string[];
  locale?: Locale;
}

interface S3UploadParameters {
  method?: 'POST' | 'PUT';
  url: string;
  fields?: { [key: string]: string };
  headers?: { [key: string]: string };
}

Usage Examples:

// S3 upload with companion server
uppy.use(AwsS3, {
  companionUrl: 'https://companion.uppy.io',
  limit: 3,
  timeout: 60000
});

// S3 upload with custom parameters
uppy.use(AwsS3, {
  getUploadParameters: async (file) => {
    // Get signed URL from your server
    const response = await fetch('/api/s3-params', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        filename: file.name,
        contentType: file.type,
        size: file.size
      })
    });
    
    const data = await response.json();
    
    return {
      method: 'POST',
      url: data.url,
      fields: data.fields,
      headers: data.headers
    };
  },
  
  allowedMetaFields: ['caption', 'description'],
  limit: 5
});

Processing Services

Upload handlers that integrate with file processing and encoding services.

/**
 * Transloadit encoding service integration
 */
class Transloadit<M extends Meta = {}, B extends Body = {}> extends BasePlugin<TransloaditOptions> {
  constructor(uppy: Uppy<M, B>, options?: TransloaditOptions);
}

interface TransloaditOptions {
  assemblyOptions?: AssemblyOptions | ((file: UppyFile<M, B>) => AssemblyOptions);
  waitForEncoding?: boolean;
  waitForMetadata?: boolean;
  alwaysRunAssembly?: boolean;
  importFromUploadURLs?: boolean;
  signature?: string;
  params?: AssemblyParameters | ((file: UppyFile<M, B>) => AssemblyParameters);
  fields?: { [key: string]: string } | ((file: UppyFile<M, B>) => { [key: string]: string });
  limit?: number;
  locale?: Locale;
}

interface AssemblyOptions {
  params: AssemblyParameters;
  signature?: string;
  fields?: { [key: string]: string };
}

interface AssemblyParameters {
  auth: {
    key: string;
    expires?: string;
  };
  template_id?: string;
  steps?: { [key: string]: StepOptions };
  notify_url?: string;
}

interface StepOptions {
  robot: string;
  use?: string | string[];
  [key: string]: any;
}

Usage Example:

// Transloadit with template
uppy.use(Transloadit, {
  params: {
    auth: { key: 'YOUR_TRANSLOADIT_KEY' },
    template_id: 'YOUR_TEMPLATE_ID'
  },
  waitForEncoding: true,
  
  // Dynamic assembly options per file
  assemblyOptions: (file) => ({
    params: {
      auth: { key: 'YOUR_TRANSLOADIT_KEY' },
      steps: {
        resize: {
          robot: '/image/resize',
          width: file.meta.targetWidth || 800,
          height: file.meta.targetHeight || 600,
          resize_strategy: 'fit'
        },
        optimize: {
          robot: '/image/optimize',
          use: 'resize'
        }
      }
    }
  })
});

Upload Handler Events

// Upload lifecycle events
interface UploadHandlerEvents<M extends Meta = {}, B extends Body = {}> {
  'upload-started': (file: UppyFile<M, B>) => void;
  'upload-progress': (file: UppyFile<M, B>, progress: FileProgress) => void;
  'upload-success': (file: UppyFile<M, B>, response: UploadSuccessResponse<B>) => void;
  'upload-error': (file: UppyFile<M, B>, error: Error, response?: UploadErrorResponse<M, B>) => void;
  'upload-retry': (file: UppyFile<M, B>) => void;
}

// Tus-specific events
interface TusEvents<M extends Meta = {}, B extends Body = {}> {
  'tus:upload-created': (file: UppyFile<M, B>, upload: { uploadURL: string }) => void;
  'tus:chunk-uploaded': (file: UppyFile<M, B>, chunk: { chunkNumber: number, chunkSize: number }) => void;
}

// S3-specific events
interface AwsS3Events<M extends Meta = {}, B extends Body = {}> {
  's3:upload-created': (file: UppyFile<M, B>, upload: S3Upload) => void;
  's3:upload-progress': (file: UppyFile<M, B>, progress: S3Progress) => void;
}

Response Types

interface UploadSuccessResponse<B extends Body = {}> {
  status: number;
  body: B;
  uploadURL?: string;
}

interface UploadErrorResponse<M extends Meta = {}, B extends Body = {}> {
  status: number;
  body: any;
  message?: string;
  details?: string;
}

interface HttpRequest {
  getMethod(): string;
  getURL(): string;
  setHeader(name: string, value: string): void;
  getHeader(name: string): string | undefined;
  setProgressHandler(handler: (bytesSent: number, bytesTotal: number) => void): void;
}

interface HttpResponse {
  getStatus(): number;
  getHeader(name: string): string | undefined;
  getBody(): string;
}

Install with Tessl CLI

npx tessl i tessl/npm-uppy

docs

cloud-providers.md

core-uppy.md

file-sources.md

index.md

plugin-architecture.md

typescript-support.md

ui-plugins.md

upload-handlers.md

utility-plugins.md

tile.json