import { CreatePreAuthUploadUrlPayload, FileSearchOptions, FileSearchResultSet, FileStorageBase, GetObjectParams, GetObjectMetadataParams, GetObjectStreamParams, ObjectStreamResult, StorageListResult, StorageObjectMetadata } from '../generic/FileStorageBase.js'; import { StorageProviderConfig } from '../generic/FileStorageBase.js'; /** * Configuration interface for Dropbox file storage. * Extends StorageProviderConfig to include accountId and accountName. * Supports both standard OAuth naming (clientID/clientSecret) and Dropbox naming (appKey/appSecret). */ interface DropboxConfig extends StorageProviderConfig { accessToken?: string; refreshToken?: string; /** OAuth client ID (standard naming) */ clientID?: string; /** OAuth client secret (standard naming) */ clientSecret?: string; /** Dropbox app key (alternative to clientID) */ appKey?: string; /** Dropbox app secret (alternative to clientSecret) */ appSecret?: string; selectUser?: string; rootPath?: string; } /** * FileStorageBase implementation for Dropbox cloud storage * * This provider allows working with files stored in Dropbox. It supports * authentication via access token or refresh token with app credentials. * * @remarks * This implementation requires one of the following authentication methods: * * 1. Access Token: * - STORAGE_DROPBOX_ACCESS_TOKEN - A valid Dropbox API access token * * 2. Refresh Token: * - STORAGE_DROPBOX_REFRESH_TOKEN - A valid Dropbox API refresh token * - STORAGE_DROPBOX_APP_KEY - Your Dropbox application key (client ID) * - STORAGE_DROPBOX_APP_SECRET - Your Dropbox application secret * * Optional configuration: * - STORAGE_DROPBOX_ROOT_PATH - Path within Dropbox to use as the root (defaults to empty which is the root) * * @example * ```typescript * // Set required environment variables * process.env.STORAGE_DROPBOX_ACCESS_TOKEN = 'your-access-token'; * * // Create the provider * const storage = new DropboxFileStorage(); * * // Upload a file * const fileContent = Buffer.from('Hello, Dropbox!'); * await storage.PutObject('documents/hello.txt', fileContent, 'text/plain'); * * // Download a file * const downloadedContent = await storage.GetObject('documents/hello.txt'); * * // Get a temporary download URL * const downloadUrl = await storage.CreatePreAuthDownloadUrl('documents/hello.txt'); * ``` */ export declare class DropboxFileStorage extends FileStorageBase { /** * The name of this storage provider */ protected readonly providerName = "Dropbox"; /** * Dropbox API client instance */ private _client; /** * Access token for Dropbox authentication */ private _accessToken; /** * Root path within Dropbox to use as the storage root */ private _rootPath; /** * Creates a new DropboxFileStorage instance * * This constructor initializes the Dropbox client using the provided credentials * from environment variables. * * @throws Error if neither access token nor refresh token with app credentials are provided */ constructor(); /** * Initialize Dropbox storage provider. * * **Always call this method** after creating an instance. * * @example Simple Deployment (Environment Variables) * const storage = new DropboxFileStorage(); // Constructor loads env vars * await storage.initialize(); // No config - uses env vars * await storage.ListObjects('/'); * * @example Multi-Tenant (Database Credentials) * const storage = new DropboxFileStorage(); * await storage.initialize({ * accountId: '12345', * accountName: 'Dropbox Account', * clientID: '...', * clientSecret: '...', * refreshToken: '...', * rootPath: '/optional-root-path' * }); * * @param config - Optional. Omit to use env vars, provide to override with database creds. */ initialize(config?: DropboxConfig): Promise; /** * Checks if Dropbox provider is properly configured. * Returns true if access token is present. * Logs detailed error messages if configuration is incomplete. */ get IsConfigured(): boolean; /** * Normalizes a path to be compatible with Dropbox API * * This helper method ensures paths are formatted correctly for the Dropbox API, * including proper handling of the root path prefix. * * @private * @param path - The path to normalize * @returns A normalized path string suitable for Dropbox API calls */ private _normalizePath; /** * Gets metadata for a file or folder from Dropbox * * This helper method retrieves metadata for a file or folder using the Dropbox API. * * @private * @param path - The path to get metadata for * @returns A Promise that resolves to the Dropbox metadata object * @throws Error if the item doesn't exist or cannot be accessed */ private _getMetadata; /** * Converts a Dropbox file/folder to StorageObjectMetadata * * This helper method transforms Dropbox-specific metadata into the * standard StorageObjectMetadata format used by FileStorageBase. * * @private * @param item - The Dropbox item metadata * @param parentPath - Optional parent path string * @returns A StorageObjectMetadata object */ private _convertToMetadata; /** * Creates a pre-authenticated upload URL (not supported in Dropbox) * * This method is not supported for Dropbox storage as Dropbox doesn't provide * a way to generate pre-authenticated upload URLs like object storage services. * Instead, use the PutObject method for file uploads. * * @param objectName - The object name (path) to create a pre-auth URL for * @throws UnsupportedOperationError always, as this operation is not supported * @example * ```typescript * // This will throw an UnsupportedOperationError * try { * await storage.CreatePreAuthUploadUrl('documents/report.docx'); * } catch (error) { * if (error instanceof UnsupportedOperationError) { * console.log('Pre-authenticated upload URLs are not supported in Dropbox.'); * // Use PutObject instead * await storage.PutObject('documents/report.docx', fileContent); * } * } * ``` */ /** * Creates a pre-authenticated upload URL for a file * * This method generates a time-limited URL that can be used to upload * a file directly to Dropbox without additional authentication. * * @param objectName - Path where the file should be uploaded (e.g., 'documents/report.pdf') * @returns A Promise that resolves to an object containing the upload URL and provider key * @throws Error if URL creation fails * * @remarks * - Dropbox temporary upload links typically expire after 4 hours * - Maximum file size for upload via temporary link is 150MB * - The upload must use Content-Type: application/octet-stream * - The URL is for one-time use only * * @example * ```typescript * try { * // Generate a pre-authenticated upload URL * const uploadPayload = await storage.CreatePreAuthUploadUrl('documents/financial-report.pdf'); * * console.log(`Upload the file to this URL: ${uploadPayload.UploadUrl}`); * * // Use the URL to upload file directly from client * // POST request with Content-Type: application/octet-stream * } catch (error) { * console.error('Error creating upload URL:', error.message); * } * ``` */ CreatePreAuthUploadUrl(objectName: string): Promise; /** * Creates a pre-authenticated download URL for a file * * This method generates a time-limited URL that can be used to download * a file without authentication. * * @param objectName - Path to the file to download (e.g., 'documents/report.pdf') * @returns A Promise that resolves to the download URL string * @throws Error if the file doesn't exist or URL creation fails * * @remarks * - Dropbox temporary download links typically expire after 4 hours * - Generated URLs can be shared with users who don't have Dropbox access * * @example * ```typescript * try { * // Generate a pre-authenticated download URL * const downloadUrl = await storage.CreatePreAuthDownloadUrl('documents/financial-report.pdf'); * * console.log(`Download the file using this URL: ${downloadUrl}`); * * // The URL can be shared or used in a browser to download the file * // without requiring Dropbox authentication * } catch (error) { * console.error('Error creating download URL:', error.message); * } * ``` */ CreatePreAuthDownloadUrl(objectName: string): Promise; /** * Moves a file or folder from one location to another * * This method moves a file or folder to a new location in Dropbox. * It handles both renaming and changing the parent folder. * * @param oldObjectName - Current path of the object (e.g., 'old-folder/document.docx') * @param newObjectName - New path for the object (e.g., 'new-folder/renamed-document.docx') * @returns A Promise that resolves to true if successful, false otherwise * * @remarks * - Works with both files and folders * - For folders, all contents will move with the folder * - If the destination already exists, the operation will fail * * @example * ```typescript * // Move a file to a different folder and rename it * const moveResult = await storage.MoveObject( * 'documents/old-report.pdf', * 'archive/2023/annual-report.pdf' * ); * * if (moveResult) { * console.log('File moved successfully'); * } else { * console.error('Failed to move file'); * } * ``` */ MoveObject(oldObjectName: string, newObjectName: string): Promise; /** * Deletes a file or folder from Dropbox * * This method permanently deletes a file or folder from Dropbox storage. * * @param objectName - Path to the object to delete (e.g., 'documents/old-report.docx') * @returns A Promise that resolves to true if successful, false if an error occurs * * @remarks * - Returns true if the object doesn't exist (for idempotency) * - Dropbox puts deleted items in the trash, where they can be recovered for a limited time * - For deleting folders with contents, use DeleteDirectory with recursive=true * * @example * ```typescript * // Delete a file * const deleteResult = await storage.DeleteObject('temp/draft-document.docx'); * * if (deleteResult) { * console.log('File deleted successfully or already didn\'t exist'); * } else { * console.error('Failed to delete file'); * } * ``` */ DeleteObject(objectName: string): Promise; /** * Lists files and folders in a given directory * * This method retrieves all files and subfolders in the specified directory. * It returns both a list of object metadata and a list of directory prefixes. * * @param prefix - Path to the directory to list (e.g., 'documents/reports') * @param delimiter - Optional delimiter character (default: '/') * @returns A Promise that resolves to a StorageListResult containing objects and prefixes * * @remarks * - The `objects` array includes both files and folders * - The `prefixes` array includes only folder paths (with trailing slashes) * - Returns empty arrays if the directory doesn't exist or an error occurs * - The delimiter parameter is included for interface compatibility but not used internally * * @example * ```typescript * // List all files and folders in the 'documents' directory * const result = await storage.ListObjects('documents'); * * // Process files and folders * console.log(`Found ${result.objects.length} items:`); * for (const obj of result.objects) { * console.log(`- ${obj.name} (${obj.isDirectory ? 'Folder' : 'File'}, ${obj.size} bytes)`); * } * * // List subfolders only * console.log(`Found ${result.prefixes.length} subfolders:`); * for (const prefix of result.prefixes) { * console.log(`- ${prefix}`); * } * ``` */ ListObjects(prefix: string, delimiter?: string): Promise; /** * Creates a new directory (folder) in Dropbox * * This method creates a folder at the specified path. * * @param directoryPath - Path where the directory should be created (e.g., 'documents/reports/2023') * @returns A Promise that resolves to true if successful, false if an error occurs * * @remarks * - Returns true if the directory already exists (idempotent operation) * - Trailing slashes in the path are automatically removed * - Parent directories must already exist; this method doesn't create them recursively * * @example * ```typescript * // Create a new folder * const createResult = await storage.CreateDirectory('documents/reports/2023'); * * if (createResult) { * console.log('Directory created successfully'); * * // Now we can put files in this directory * await storage.PutObject( * 'documents/reports/2023/annual-summary.xlsx', * fileContent, * 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' * ); * } else { * console.error('Failed to create directory'); * } * ``` */ CreateDirectory(directoryPath: string): Promise; /** * Deletes a directory from Dropbox * * This method deletes a folder and optionally ensures it's empty first. * Note that Dropbox API always deletes folders recursively, so we perform * an additional check when recursive=false to protect against accidental deletion. * * @param directoryPath - Path to the directory to delete (e.g., 'documents/old-reports') * @param recursive - If true, delete the directory and all its contents; if false, only delete if empty * @returns A Promise that resolves to true if successful, false if an error occurs * * @remarks * - Returns true if the directory doesn't exist (idempotent operation) * - If recursive=false and the directory contains files, the operation will fail * - Dropbox puts deleted folders in the trash, where they can be recovered for a limited time * - Trailing slashes in the path are automatically removed * * @example * ```typescript * // Attempt to delete an empty folder * const deleteResult = await storage.DeleteDirectory('temp/empty-folder', false); * * // Delete a folder and all its contents * const recursiveDeleteResult = await storage.DeleteDirectory('archive/old-data', true); * * if (recursiveDeleteResult) { * console.log('Folder and all its contents deleted successfully'); * } else { * console.error('Failed to delete folder'); * } * ``` */ DeleteDirectory(directoryPath: string, recursive?: boolean): Promise; /** * Gets metadata for a file or folder * * This method retrieves metadata information about a file or folder, such as * its name, size, content type, and last modified date. * * @param params - Object identifier (prefer objectId for performance, fallback to fullPath) * @returns A Promise that resolves to a StorageObjectMetadata object * @throws Error if the object doesn't exist or cannot be accessed * * @example * ```typescript * try { * // Fast path: Use objectId (Dropbox file ID) * const metadata = await storage.GetObjectMetadata({ objectId: 'id:a4ayc_80_OEAAAAAAAAAXw' }); * * // Slow path: Use path * const metadata2 = await storage.GetObjectMetadata({ fullPath: 'presentations/quarterly-update.pptx' }); * * console.log(`Name: ${metadata.name}`); * console.log(`Path: ${metadata.path}`); * console.log(`Size: ${metadata.size} bytes`); * console.log(`Content Type: ${metadata.contentType}`); * console.log(`Last Modified: ${metadata.lastModified}`); * console.log(`Is Directory: ${metadata.isDirectory}`); * * // Dropbox-specific metadata is available in customMetadata * console.log(`Dropbox ID: ${metadata.customMetadata.id}`); * console.log(`Revision: ${metadata.customMetadata.rev}`); * } catch (error) { * console.error('Error getting metadata:', error.message); * } * ``` */ GetObjectMetadata(params: GetObjectMetadataParams): Promise; /** * Downloads a file's contents * * This method retrieves the raw content of a file as a Buffer. * * @param params - Object identifier (prefer objectId for performance, fallback to fullPath) * @returns A Promise that resolves to a Buffer containing the file's contents * @throws Error if the file doesn't exist or cannot be downloaded * * @remarks * - This method will throw an error if the object is a folder * - For large files, consider using CreatePreAuthDownloadUrl instead * * @example * ```typescript * try { * // Fast path: Use objectId (Dropbox file ID) * const fileContent = await storage.GetObject({ objectId: 'id:a4ayc_80_OEAAAAAAAAAXw' }); * * // Slow path: Use path * const fileContent2 = await storage.GetObject({ fullPath: 'documents/notes.txt' }); * * // Convert Buffer to string for text files * const textContent = fileContent.toString('utf8'); * console.log('File content:', textContent); * * // For binary files, you can write the buffer to disk * // or process it as needed * } catch (error) { * console.error('Error downloading file:', error.message); * } * ``` */ GetObject(params: GetObjectParams): Promise; /** * Dropbox supports ranged streaming: `filesGetTemporaryLink` returns a short-lived * pre-authenticated content URL that honors the HTTP `Range` header. */ get SupportsStreaming(): boolean; /** * Streams a file's content from Dropbox, optionally honoring a byte range. * * The Dropbox SDK's `filesDownload` returns the entire file binary in memory and exposes no * Range seam, so this method instead requests a short-lived temporary content link via * `filesGetTemporaryLink` and `fetch`es it with the inclusive `Range` encoded by * {@link BuildHttpRangeHeader}. The Dropbox content endpoint honors the `Range` header. The fetch * response body is a web `ReadableStream`, converted to a Node {@link Readable} via * `Readable.fromWeb` so the file is never fully buffered. `Content-Type`/`Content-Length`/ * `Content-Range` are read off the HTTP response headers; the total object size falls back to the * link's `metadata.size` when the server omits `Content-Range`. * * @param params - Object identifier (prefer objectId) plus optional Range. * @returns A Promise resolving to an {@link ObjectStreamResult}. * @throws Error if the file doesn't exist or cannot be streamed. */ GetObjectStream(params: GetObjectStreamParams): Promise; /** * Parses an HTTP `Content-Range` header value (`bytes start-end/total`) into the structured * form used by {@link ObjectStreamResult.ContentRange}. * * @param contentRange - The raw `Content-Range` header value from the download response, if present. * @returns The parsed range, or undefined when no (valid) range header was returned. */ private _parseDropboxContentRange; /** * Uploads a file to Dropbox * * This method uploads a file to the specified path in Dropbox. It automatically * determines whether to use a simple upload or chunked upload based on file size. * * @param objectName - Path where the file should be uploaded (e.g., 'documents/report.pdf') * @param data - Buffer containing the file content * @param contentType - Optional MIME type of the file (not used in Dropbox implementation) * @param metadata - Optional metadata to associate with the file (not used in Dropbox implementation) * @returns A Promise that resolves to true if successful, false if an error occurs * * @remarks * - Files smaller than 150MB use a simple upload * - Files 150MB or larger use a chunked upload process * - If a file with the same name exists, it will be overwritten * - Parent folders must exist before uploading files to them * * @example * ```typescript * // Upload a simple text file * const textContent = Buffer.from('This is a sample document', 'utf8'); * const uploadResult = await storage.PutObject('documents/sample.txt', textContent); * * // Upload a large file using chunked upload * const largeFileBuffer = fs.readFileSync('/path/to/large-presentation.pptx'); * const largeUploadResult = await storage.PutObject( * 'presentations/quarterly-results.pptx', * largeFileBuffer * ); * * if (largeUploadResult) { * console.log('Large file uploaded successfully'); * } else { * console.error('Failed to upload large file'); * } * ``` */ PutObject(objectName: string, data: Buffer, contentType?: string, metadata?: Record): Promise; /** * Copies a file or folder from one location to another * * This method creates a copy of a file or folder at a new location. * The original file or folder remains unchanged. * * @param sourceObjectName - Path to the source object (e.g., 'templates/report-template.docx') * @param destinationObjectName - Path where the copy should be created (e.g., 'documents/new-report.docx') * @returns A Promise that resolves to true if successful, false if an error occurs * * @remarks * - Works with both files and folders * - If the destination already exists, the operation will fail * - Parent directories must exist in the destination path * * @example * ```typescript * // Copy a template file to a new location with a different name * const copyResult = await storage.CopyObject( * 'templates/financial-report.xlsx', * 'reports/2023/q1-financial-report.xlsx' * ); * * if (copyResult) { * console.log('File copied successfully'); * } else { * console.error('Failed to copy file'); * } * ``` */ CopyObject(sourceObjectName: string, destinationObjectName: string): Promise; /** * Checks if a file or folder exists * * This method verifies whether an object (file or folder) exists at the specified path. * * @param objectName - Path to check (e.g., 'documents/report.pdf') * @returns A Promise that resolves to true if the object exists, false otherwise * * @example * ```typescript * // Check if a file exists before attempting to download it * const exists = await storage.ObjectExists('presentations/quarterly-update.pptx'); * * if (exists) { * // File exists, proceed with download * const fileContent = await storage.GetObject('presentations/quarterly-update.pptx'); * // Process the file... * } else { * console.log('File does not exist'); * } * ``` */ ObjectExists(objectName: string): Promise; /** * Checks if a directory exists * * This method verifies whether a folder exists at the specified path. * Unlike ObjectExists, this method also checks that the item is a folder. * * @param directoryPath - Path to check (e.g., 'documents/reports') * @returns A Promise that resolves to true if the directory exists, false otherwise * * @remarks * - Returns false if the path exists but points to a file instead of a folder * - Trailing slashes in the path are automatically removed * * @example * ```typescript * // Check if a directory exists before creating a file in it * const dirExists = await storage.DirectoryExists('documents/reports'); * * if (!dirExists) { * // Create the directory first * await storage.CreateDirectory('documents/reports'); * } * * // Now we can safely put a file in this directory * await storage.PutObject('documents/reports/annual-summary.pdf', fileContent); * ``` */ DirectoryExists(directoryPath: string): Promise; /** * Search files in Dropbox using Dropbox Search API v2. * * Dropbox provides full-text search capabilities across file names and content. * The search API supports natural language queries and can search both filenames * and file content based on the searchContent option. * * @param query - The search query string (supports natural language and quoted phrases) * @param options - Search options for filtering and limiting results * @returns A Promise resolving to search results * * @remarks * - Content search (searchContent: true) searches both filename and file content * - Filename search (searchContent: false, default) searches only filenames * - File type filtering converts extensions to Dropbox file categories * - Date filters use server_modified timestamp * - Path prefix restricts search to a specific folder and its subfolders * * @example * ```typescript * // Simple filename search * const results = await storage.SearchFiles('quarterly report'); * * // Search with file type filter * const pdfResults = await storage.SearchFiles('budget', { * fileTypes: ['pdf'], * modifiedAfter: new Date('2024-01-01') * }); * * // Content search within a specific folder * const contentResults = await storage.SearchFiles('machine learning', { * searchContent: true, * pathPrefix: 'documents/research', * maxResults: 50 * }); * ``` */ SearchFiles(query: string, options?: FileSearchOptions): Promise; /** * Extracts file extensions from fileTypes array. * Converts MIME types to extensions and removes duplicates. * * @private * @param fileTypes - Array of file types (extensions or MIME types) * @returns Array of file extensions without leading dots */ private _extractFileExtensions; /** * Extracts the relative path from a Dropbox absolute path. * Removes the root path prefix if configured. * * @private * @param dropboxPath - The absolute Dropbox path * @returns The relative path without root prefix */ private _extractRelativePath; /** * Checks if a filename contains the search query. * Performs case-insensitive matching. * * @private * @param filename - The filename to check * @param query - The search query * @returns True if the filename contains the query */ private _checkFilenameMatch; } export {}; //# sourceMappingURL=DropboxFileStorage.d.ts.map