svelte-firebase-upload
Version:
Enterprise-grade file upload manager for Svelte with Firebase Storage integration, featuring concurrent uploads, resumable transfers, validation, health monitoring, and plugin system
385 lines (384 loc) • 11.9 kB
TypeScript
export type { FirebaseStorage } from 'firebase/storage';
import type { FirebaseStorage } from 'firebase/storage';
/**
* Status of an individual upload item.
*
* - `queued`: File is waiting to be uploaded
* - `uploading`: File is currently being uploaded
* - `completed`: File upload completed successfully
* - `failed`: File upload failed (may be retried)
* - `paused`: File upload is temporarily paused
*/
export type UploadStatus = 'queued' | 'uploading' | 'completed' | 'failed' | 'paused';
export interface UploadManagerInterface {
config: UploadManagerConfig;
queue: UploadItem[];
active: Map<string, UploadItem>;
completed: Map<string, UploadItem>;
failed: Map<string, UploadItem>;
paused: Set<string>;
isProcessing: boolean;
isPaused: boolean;
totalFiles: number;
totalSize: number;
uploadedSize: number;
startTime: number | null;
estimatedTimeRemaining: number | null;
currentSpeed: number;
successCount: number;
failureCount: number;
totalProgress: number;
isActive: boolean;
hasQueuedFiles: boolean;
hasCompletedFiles: boolean;
hasFailedFiles: boolean;
isIdle: boolean;
averageSpeed: number;
queueStats: {
totalFiles: number;
totalSize: number;
sizeDistribution: {
small: number;
medium: number;
large: number;
veryLarge: number;
};
estimatedCompletionTime: number;
quickWinsAvailable: number;
};
addFiles(fileList: FileList | File[], options?: UploadManagerOptions): Promise<number>;
start(): Promise<void>;
pause(): Promise<void>;
resume(): Promise<void>;
stop(): Promise<void>;
destroy(): Promise<void>;
removeFile(fileId: string): Promise<void>;
retryFailed(): void;
clearCompleted(): Promise<void>;
clearFailed(): void;
getFile(fileId: string): UploadItem | undefined;
getAllFiles(statusFilter?: UploadStatus | null): UploadItem[];
validateFiles(files: File[], rules?: Partial<ValidationRule>): Promise<Map<File, ValidationResult>>;
validateFile(file: File, rules?: Partial<ValidationRule>): Promise<ValidationResult>;
detectDuplicates(files: File[]): Promise<Map<string, File[]>>;
getFileMetadata(file: File): Promise<{
size: number;
type: string;
lastModified: number;
hash: string;
dimensions?: {
width: number;
height: number;
};
duration?: number;
}>;
checkForResumableUpload(file: File): Promise<ResumableUploadState | null>;
resumeIncompleteUploads(): Promise<void>;
addFilesWithValidation(files: File[], options?: UploadManagerOptions & {
validate?: boolean;
validationRules?: Partial<ValidationRule>;
skipDuplicates?: boolean;
checkResume?: boolean;
}): Promise<{
added: number;
validated: number;
duplicates: number;
resumed: number;
errors: string[];
}>;
registerPlugin(plugin: UploadPlugin, config?: Partial<PluginConfig>): Promise<void>;
unregisterPlugin(pluginName: string): Promise<void>;
getAllPlugins(): Array<{
name: string;
plugin: UploadPlugin;
config: PluginConfig;
}>;
getEnabledPlugins(): Array<{
name: string;
plugin: UploadPlugin;
config: PluginConfig;
}>;
setPluginEnabled(pluginName: string, enabled: boolean): Promise<void>;
performHealthCheck(): Promise<HealthCheckResult>;
startWithHealthCheck(): Promise<{
canStart: boolean;
healthResult: HealthCheckResult;
}>;
getHealthStatus(): HealthStatus;
getLastHealthCheck(): HealthCheckResult | null;
forceHealthCheck(): Promise<HealthCheckResult>;
setStorage(storageInstance: FirebaseStorage): void;
getBandwidthStats(): {
current: number;
average: number;
peak: number;
limit: number;
utilization: number;
};
getNetworkQuality(): 'excellent' | 'good' | 'poor' | 'unknown';
getRecommendedSettings(): {
maxConcurrent: number;
chunkSize: number;
timeout: number;
};
setSmartScheduling(enabled: boolean): void;
isSmartSchedulingEnabled(): boolean;
optimizeQueue(): void;
getQueueStats(): {
totalFiles: number;
totalSize: number;
sizeDistribution: {
small: number;
medium: number;
large: number;
veryLarge: number;
};
estimatedCompletionTime: number;
quickWinsAvailable: number;
};
}
/**
* Core configuration for the Firebase Upload Manager.
*
* Most properties are readonly after initialization to prevent
* accidental modification. Use updateConfig() method for safe runtime changes.
*/
export interface UploadManagerConfig {
readonly maxConcurrentUploads: number;
readonly chunkSize: number;
readonly retryAttempts: number;
readonly retryDelay: number;
readonly autoStart: boolean;
readonly maxBandwidthMbps?: number;
readonly adaptiveBandwidth?: boolean;
readonly maxMemoryItems?: number;
readonly enablePersistence?: boolean;
enableSmartScheduling: boolean;
}
/**
* Represents a single file in the upload queue with all metadata and status information.
*
* Contains both file information and upload progress tracking.
*/
export interface UploadItem {
readonly id: string;
readonly file: File;
readonly path: string;
readonly metadata: Readonly<Record<string, any>>;
readonly priority: number;
status: UploadStatus;
progress: number;
uploadedBytes: number;
readonly totalBytes: number;
error: string | null;
attempts: number;
readonly createdAt: number;
startedAt?: number;
completedAt?: number;
downloadURL?: string;
_interval?: number | NodeJS.Timeout;
hash?: string;
validationResult?: ValidationResult;
}
export interface SpeedSample {
time: number;
uploaded: number;
}
export interface UploadTask {
pause?: () => void;
resume?: () => void;
cancel?: () => void;
}
/**
* Configuration options for initializing the Firebase Upload Manager.
*
* All properties are optional with sensible defaults.
* Can also be used for per-file upload options in addFiles().
*/
export interface UploadManagerOptions {
maxConcurrentUploads?: number;
chunkSize?: number;
retryAttempts?: number;
retryDelay?: number;
autoStart?: boolean;
path?: string;
metadata?: Record<string, any>;
priority?: number;
enableSmartScheduling?: boolean;
enableHealthChecks?: boolean;
maxBandwidthMbps?: number;
adaptiveBandwidth?: boolean;
maxMemoryItems?: number;
enablePersistence?: boolean;
resumeState?: ResumableUploadState;
[key: string]: any;
}
export interface UploadPlugin {
name: string;
version: string;
description?: string;
onInitialize?: (manager: UploadManagerInterface) => Promise<void> | void;
onDestroy?: () => Promise<void> | void;
beforeFileAdd?: (file: File, options: any) => Promise<{
file: File;
options: any;
}> | {
file: File;
options: any;
};
afterFileAdd?: (item: UploadItem) => Promise<void> | void;
beforeValidation?: (file: File, rules: any) => Promise<{
file: File;
rules: any;
}> | {
file: File;
rules: any;
};
afterValidation?: (file: File, result: ValidationResult) => Promise<void> | void;
beforeUpload?: (item: UploadItem) => Promise<UploadItem> | UploadItem;
onUploadStart?: (item: UploadItem) => Promise<void> | void;
onUploadProgress?: (item: UploadItem, progress: number) => Promise<void> | void;
onUploadComplete?: (item: UploadItem, result: any) => Promise<void> | void;
onUploadError?: (item: UploadItem, error: Error) => Promise<void> | void;
beforeQueueProcess?: (queue: UploadItem[]) => Promise<UploadItem[]> | UploadItem[];
afterQueueProcess?: (queue: UploadItem[]) => Promise<void> | void;
onStatusChange?: (item: UploadItem, oldStatus: UploadStatus, newStatus: UploadStatus) => Promise<void> | void;
onManagerStateChange?: (state: any) => Promise<void> | void;
onError?: (error: Error, context: any) => Promise<void> | void;
[key: string]: any;
}
export interface VirtualQueueConfig {
maxMemoryItems: number;
batchSize: number;
persistenceKey?: string;
}
export interface FileBatch {
id: string;
files: File[];
processed: boolean;
createdAt: number;
}
export interface NetworkMonitor {
isOnline: boolean;
connectionType?: string;
effectiveType?: string;
downlink?: number;
onOnline: (callback: () => void) => void;
onOffline: (callback: () => void) => void;
disconnect: () => void;
}
export interface RetryConfig {
maxAttempts: number;
baseDelay: number;
maxDelay: number;
backoffMultiplier: number;
jitter: boolean;
}
export interface BandwidthConfig {
maxBandwidthMbps: number;
adaptiveBandwidth: boolean;
throttleInterval: number;
}
export interface ThrottleInfo {
bytesPerSecond: number;
lastUpdate: number;
queue: Array<() => void>;
}
export interface ValidationRule {
maxSize?: number;
allowedTypes?: readonly string[];
customValidator?: (file: File) => Promise<boolean>;
}
export interface ValidationResult {
readonly valid: boolean;
readonly errors: readonly string[];
readonly warnings: readonly string[];
}
export interface UploadMetrics {
averageSpeed: number;
successRate: number;
commonErrors: Map<string, number>;
peakConcurrency: number;
totalBandwidthUsed: number;
uploadCount: number;
failureCount: number;
startTime: number;
endTime?: number;
}
export interface HealthStatus {
healthy: boolean;
issues: string[];
storageQuota?: number;
networkStatus: 'online' | 'offline' | 'unknown';
permissionsValid: boolean;
}
export interface HealthCheckResult {
status: HealthStatus;
timestamp: number;
duration: number;
checks: {
connection: boolean;
storage: boolean;
permissions: boolean;
network: boolean;
memory: boolean;
bandwidth: boolean;
};
details: {
connectionLatency?: number;
storageQuota?: StorageQuota;
permissionStatus?: PermissionStatus;
networkQuality?: string;
memoryUsage?: number;
bandwidthStats?: any;
};
}
export interface StorageQuota {
usage: number;
quota: number;
percentage: number;
available: number;
}
export interface PermissionStatus {
storage: boolean;
network: boolean;
notifications?: boolean;
details: string[];
}
export interface ResumableUploadState {
fileId: string;
fileName: string;
fileSize: number;
uploadedBytes: number;
chunks: ChunkState[];
metadata: Record<string, any>;
createdAt: number;
lastUpdated: number;
}
export interface ChunkState {
index: number;
start: number;
end: number;
uploaded: boolean;
hash?: string;
}
export interface ResumeOptions {
chunkSize?: number;
verifyChunks?: boolean;
parallelChunks?: number;
}
export interface DuplicateInfo {
hash: string;
files: File[];
count: number;
}
export interface PluginConfig {
enabled: boolean;
priority: number;
options?: Record<string, any>;
}
export interface PluginRegistryEntry {
plugin: UploadPlugin;
config: PluginConfig;
}
export type PluginEventType = 'initialize' | 'destroy' | 'beforeFileAdd' | 'afterFileAdd' | 'beforeValidation' | 'afterValidation' | 'beforeUpload' | 'onUploadStart' | 'onUploadProgress' | 'onUploadComplete' | 'onUploadError' | 'beforeQueueProcess' | 'afterQueueProcess' | 'onStatusChange' | 'onManagerStateChange' | 'onError';