import { Storage } from '@angular/fire/storage'; import { Observable } from 'rxjs'; import { StorageListResult, StorageMetadata, UploadProgress, UploadResult } from './types'; import * as i0 from "@angular/core"; /** * Servicio para Firebase Storage. * * @example * ```typescript * @Component({...}) * export class FileUploadComponent { * private storage = inject(StorageService); * * uploadProgress = signal(0); * downloadUrl = signal(null); * * async onFileSelected(event: Event) { * const file = (event.target as HTMLInputElement).files?.[0]; * if (!file) return; * * // Upload con progreso * this.storage.upload(`uploads/${file.name}`, file).subscribe({ * next: (progress) => this.uploadProgress.set(progress.percentage), * complete: async () => { * const url = await this.storage.getDownloadUrl(`uploads/${file.name}`); * this.downloadUrl.set(url); * } * }); * } * } * ``` */ export declare class StorageService { private storage; private config; constructor(storage: Storage); /** * Prefija el path de storage con el appId si está configurado. * Si no hay appId o skipPrefix es true, retorna el path sin modificar. * * @param path - Ruta original * @param skipPrefix - Si es true, no aplica el prefix (útil para paths compartidos como avatares) * @internal */ private prefixStoragePath; /** * Sube un archivo con tracking de progreso. * * @param path - Ruta en Storage donde guardar el archivo * @param file - Archivo a subir (File o Blob) * @param metadata - Metadata opcional (contentType, customMetadata) * @returns Observable que emite el progreso y completa cuando termina * * @example * ```typescript * // Upload básico * storage.upload('images/photo.jpg', file).subscribe({ * next: (progress) => console.log(`${progress.percentage}%`), * complete: () => console.log('Upload completado') * }); * * // Con metadata * storage.upload('docs/report.pdf', file, { * contentType: 'application/pdf', * customMetadata: { uploadedBy: 'user123' } * }).subscribe(...); * ``` */ upload(path: string, file: File | Blob, metadata?: StorageMetadata): Observable; /** * Lee el archivo COMPLETO a memoria y devuelve un Blob autocontenido. * * No es una copia por gusto: en Safari, un `File` que no está plenamente * materializado en disco — típico de fotos llegadas del iPhone vía * Fotos/iCloud — hace fallar la lectura del SDK de Storage en el envío, por * sus dos caminos (uploadBytes y uploadBytesResumable), con un * `storage/unknown` opaco. El mismo Safari sube sin problema archivos locales * de otra procedencia, así que el bug aparece "a veces" y sin mensaje útil. * `arrayBuffer()` fuerza la lectura completa; el Blob resultante ya no * depende del backing file. Caso real: bingo image-picker, 2026-08-05. * * Un Blob (no-File) ya nació en memoria — se devuelve tal cual. * @internal */ private materialize; /** * Reintento por REST cuando el SDK falla la subida. * * El SDK va por XMLHttpRequest y su detalle de error es `xhr.statusText`, que * sobre HTTP/2 viene siempre vacío — un fallo del SDK es ilegible y, en los * entornos donde algo interfiere con XHR, además evitable: este camino usa * `fetch` con `uploadType=media` (cuerpo binario simple). La URL se arma con * el downloadToken de la respuesta porque getDownloadURL también va por XHR. * * Devuelve null si tampoco pudo — el caller reporta el error original del SDK. * @internal */ private uploadViaRest; /** * Sube un archivo y retorna la URL de descarga al completar. * * Robustecido para el caso Safari/iPhone (ver `materialize`): lee el archivo * a memoria antes de subirlo, verifica que el tamaño guardado coincida y, si * el SDK falla, reintenta una vez por REST antes de rechazar. * * @param path - Ruta en Storage * @param file - Archivo a subir * @param metadata - Metadata opcional * @returns Resultado del upload con URL de descarga * * @example * ```typescript * const result = await storage.uploadAndGetUrl('avatars/user123.jpg', file); * console.log('URL:', result.downloadUrl); * ``` */ uploadAndGetUrl(path: string, file: File | Blob, metadata?: StorageMetadata): Promise; /** * Sube un archivo desde una Data URL (base64). * * @param path - Ruta en Storage * @param dataUrl - Data URL (ej: 'data:image/png;base64,...') * @param metadata - Metadata opcional * @returns Resultado del upload * * @example * ```typescript * // Desde canvas * const dataUrl = canvas.toDataURL('image/png'); * const result = await storage.uploadFromDataUrl('images/drawing.png', dataUrl); * ``` */ uploadFromDataUrl(path: string, dataUrl: string, metadata?: StorageMetadata): Promise; /** * Obtiene la URL de descarga de un archivo. * * @param path - Ruta del archivo en Storage * @returns URL de descarga * * @example * ```typescript * const url = await storage.getDownloadUrl('images/photo.jpg'); * // Usar en * ``` */ getDownloadUrl(path: string): Promise; /** * Obtiene la metadata de un archivo. * * @param path - Ruta del archivo * @returns Metadata del archivo */ getMetadata(path: string): Promise; /** * Elimina un archivo. * * @param path - Ruta del archivo a eliminar * @param options.skipPrefix - Si es true, no aplica el prefix de appId (para * borrar un archivo subido con `uploadAndGetUrl(path, file, { skipPrefix: * true })` hay que pasar el mismo flag, o el path queda mal armado y el * delete falla contra un objeto que no existe). * * @example * ```typescript * await storage.delete('images/old-photo.jpg'); * await storage.delete('apps/merotz/orgs/x/public/images/parts/y/z.png', { skipPrefix: true }); * ``` */ delete(path: string, options?: { skipPrefix?: boolean; }): Promise; /** * Elimina múltiples archivos. * * @param paths - Array de rutas a eliminar * * @example * ```typescript * await storage.deleteMultiple([ * 'images/photo1.jpg', * 'images/photo2.jpg' * ]); * ``` */ deleteMultiple(paths: string[]): Promise; /** * Lista archivos en un directorio. * * @param path - Ruta del directorio * @returns Lista de rutas de archivos * * @example * ```typescript * const result = await storage.list('images/'); * console.log(result.items); // ['images/photo1.jpg', 'images/photo2.jpg'] * ``` */ list(path: string): Promise; /** * Genera un nombre de archivo único con timestamp. * * @param originalName - Nombre original del archivo * @param prefix - Prefijo opcional * @returns Nombre único * * @example * ```typescript * const uniqueName = storage.generateFileName('photo.jpg', 'user123'); * // => 'user123_1703091234567_photo.jpg' * ``` */ generateFileName(originalName: string, prefix?: string): string; /** * Genera una ruta única para un archivo. * * @param directory - Directorio base * @param originalName - Nombre original * @param prefix - Prefijo opcional * @returns Ruta completa única * * @example * ```typescript * const path = storage.generatePath('uploads', 'photo.jpg', 'user123'); * // => 'uploads/user123_1703091234567_photo.jpg' * ``` */ generatePath(directory: string, originalName: string, prefix?: string): string; /** * Obtiene la extensión de un archivo. * * @param filename - Nombre del archivo * @returns Extensión (sin el punto) */ getExtension(filename: string): string; /** * Verifica si un archivo es una imagen basándose en su extensión. */ isImage(filename: string): boolean; /** * Verifica si un archivo es un documento. */ isDocument(filename: string): boolean; /** * Construye la URL de avatar de un usuario. * * Los avatares se almacenan en paths predecibles: `users/{userId}/avatar.jpg` * Esto permite que cualquier app pueda mostrar avatares sin pedir la URL al backend, * solo necesita el userId. * * @param userId - ID del usuario (ULID) * @param type - 'avatar' para imagen completa, 'thumb' para thumbnail * @returns URL directa de Firebase Storage * * @example * ```typescript * // Mostrar avatar de cualquier usuario * const avatarUrl = storage.getUserAvatarUrl('01ABCD...'); * const thumbUrl = storage.getUserAvatarUrl('01ABCD...', 'thumb'); * * // Con cache-busting * const freshUrl = storage.getUserAvatarUrl(userId) + `&t=${Date.now()}`; * ``` */ getUserAvatarUrl(userId: string, type?: 'avatar' | 'thumb'): string; /** * Mapea el estado de la tarea de upload */ private mapTaskState; /** * Convierte errores de Storage a mensajes en español */ private getErrorMessage; static ɵfac: i0.ɵɵFactoryDeclaration; static ɵprov: i0.ɵɵInjectableDeclaration; }