import { CreatePreAuthUploadUrlPayload, FileSearchOptions, FileSearchResultSet, FileStorageBase, GetObjectParams, GetObjectMetadataParams, GetObjectStreamParams, ObjectStreamResult, StorageListResult, StorageObjectMetadata } from '../generic/FileStorageBase.js'; import { StorageProviderConfig } from '../generic/FileStorageBase.js'; /** * Configuration interface for AWS S3 file storage. * Extends StorageProviderConfig to include accountId and accountName. */ interface AWSS3Config extends StorageProviderConfig { region?: string; accessKeyID?: string; secretAccessKey?: string; defaultBucket?: string; keyPrefix?: string; } /** * AWS S3 implementation of the FileStorageBase interface. * * This class provides methods for interacting with Amazon S3 as a file storage provider. * It implements all the abstract methods defined in FileStorageBase and handles AWS-specific * authentication, authorization, and file operations. * * It requires the following environment variables to be set: * - STORAGE_AWS_REGION: The AWS region (e.g., 'us-east-1') * - STORAGE_AWS_BUCKET_NAME: The S3 bucket name * - STORAGE_AWS_ACCESS_KEY_ID: The AWS access key ID * - STORAGE_AWS_SECRET_ACCESS_KEY: The AWS secret access key * - STORAGE_AWS_KEY_PREFIX: (Optional) Prefix for all object keys, defaults to '/' * * @example * ```typescript * // Create an instance of AWSFileStorage * const s3Storage = new AWSFileStorage(); * * // Generate a pre-authenticated upload URL * const { UploadUrl } = await s3Storage.CreatePreAuthUploadUrl('documents/report.pdf'); * * // Generate a pre-authenticated download URL * const downloadUrl = await s3Storage.CreatePreAuthDownloadUrl('documents/report.pdf'); * * // List files in a directory * const files = await s3Storage.ListObjects('documents/'); * ``` */ export declare class AWSFileStorage extends FileStorageBase { /** The name of this storage provider, used in error messages */ protected readonly providerName = "AWS S3"; /** The S3 bucket name */ private _bucket; /** The key prefix to prepend to all object keys */ private _keyPrefix; /** The S3 client instance */ private _client; /** AWS access key ID */ private _accessKeyId; /** AWS secret access key */ private _secretAccessKey; /** S3 bucket name (for IsConfigured check) */ private _bucketName; /** * Creates a new instance of AWSFileStorage. * * Initializes the connection to AWS S3 using environment variables. * Throws an error if any required environment variables are missing. */ constructor(); /** * Initialize AWS S3 storage provider. * * **Always call this method** after creating an instance. * * @example Simple Deployment (Environment Variables) * ```typescript * const storage = new AWSFileStorage(); // Constructor loads env vars * await storage.initialize(); // No config - uses env vars * await storage.ListObjects('/'); * ``` * * @example Multi-Tenant (Database Credentials) * ```typescript * const storage = new AWSFileStorage(); * await storage.initialize({ * accountId: '12345', * accountName: 'AWS Account', * accessKeyID: '...', // From database * secretAccessKey: '...', * region: 'us-east-1', * defaultBucket: 'bucket' * }); * await storage.ListObjects('/'); * ``` * * @param config - Optional. Omit to use env vars, provide to override with database creds. */ initialize(config?: AWSS3Config): Promise; /** * Checks if AWS S3 provider is properly configured. * Returns true if access credentials and bucket name are present. * Logs detailed error messages if configuration is incomplete. */ get IsConfigured(): boolean; /** * Normalizes the object name by ensuring it has the proper key prefix. * * This is a helper method used internally to ensure all object keys have * the configured prefix. It handles cases where the object name already * includes the prefix or has leading slashes. * * @param objectName - The object name to normalize * @returns The normalized object name with the proper prefix * @private */ private _normalizeKey; /** * Removes the prefix from a key to get the relative object name. * * This is a helper method used internally to convert a full S3 key * (including the prefix) back to the relative object name that * clients will recognize. * * @param key - The full key including the prefix * @returns The object name without the prefix * @private */ private _removePrefix; /** * Creates a pre-authenticated upload URL for an object in S3. * * This method generates a pre-signed URL that allows for uploading * an object to S3 without needing AWS credentials. The URL is valid * for 10 minutes and includes the content type based on the file extension. * * @param objectName - The name of the object to upload (including any path/directory) * @returns A Promise resolving to an object with the upload URL * * @example * ```typescript * // Generate a pre-authenticated upload URL for a PDF file * const { UploadUrl } = await s3Storage.CreatePreAuthUploadUrl('documents/report.pdf'); * * // The URL can be used with fetch or other HTTP clients to upload the file * console.log(UploadUrl); * ``` */ CreatePreAuthUploadUrl(objectName: string): Promise; /** * Creates a pre-authenticated download URL for an object in S3. * * This method generates a pre-signed URL that allows for downloading * an object from S3 without needing AWS credentials. The URL is valid * for 10 minutes and can be shared with clients. * * @param objectName - The name of the object to download (including any path/directory) * @returns A Promise resolving to the download URL * * @example * ```typescript * // Generate a pre-authenticated download URL for a PDF file * const downloadUrl = await s3Storage.CreatePreAuthDownloadUrl('documents/report.pdf'); * * // The URL can be shared with users or used in applications for direct download * console.log(downloadUrl); * ``` */ CreatePreAuthDownloadUrl(objectName: string): Promise; /** * Moves an object from one location to another within S3. * * Since S3 doesn't provide a native move operation, this method * implements move as a copy followed by a delete operation. * It first copies the object to the new location, and if successful, * deletes the object from the original location. * * @param oldObjectName - The current name/path of the object * @param newObjectName - The new name/path for the object * @returns A Promise resolving to a boolean indicating success * * @example * ```typescript * // Move a file from drafts to published folder * const success = await s3Storage.MoveObject( * 'drafts/report.docx', * 'published/final-report.docx' * ); * * if (success) { * console.log('File successfully moved'); * } else { * console.log('Failed to move file'); * } * ``` */ MoveObject(oldObjectName: string, newObjectName: string): Promise; /** * Deletes an object from S3. * * This method attempts to delete the specified object. It returns true * if the operation was successful, false otherwise. * * @param objectName - The name of the object to delete (including any path/directory) * @returns A Promise resolving to a boolean indicating success * * @example * ```typescript * // Delete a temporary file * const deleted = await s3Storage.DeleteObject('temp/report-draft.pdf'); * * if (deleted) { * console.log('File successfully deleted'); * } else { * console.log('Failed to delete file'); * } * ``` */ DeleteObject(objectName: string): Promise; /** * Lists objects with the specified prefix in S3. * * This method returns a list of objects (files) and common prefixes (directories) * under the specified path prefix. It uses the S3 ListObjectsV2 API which supports * delimiter-based hierarchy simulation. * * @param prefix - The path prefix to list objects from (e.g., 'documents/') * @param delimiter - The character used to simulate directory structure, defaults to '/' * @returns A Promise resolving to a StorageListResult containing objects and prefixes * * @example * ```typescript * // List all files and directories in the documents folder * const result = await s3Storage.ListObjects('documents/'); * * // Process files * for (const file of result.objects) { * console.log(`File: ${file.name}, Size: ${file.size}, Type: ${file.contentType}`); * } * * // Process subdirectories * for (const dir of result.prefixes) { * console.log(`Directory: ${dir}`); * } * ``` */ ListObjects(prefix: string, delimiter?: string): Promise; /** * Creates a directory (virtual) in S3. * * Since S3 doesn't have a native directory concept, this method creates * a zero-byte object with a trailing slash to simulate a directory. * The object has a special content type to indicate it's a directory. * * @param directoryPath - The path of the directory to create * @returns A Promise resolving to a boolean indicating success * * @example * ```typescript * // Create a new directory structure * const created = await s3Storage.CreateDirectory('documents/reports/annual/'); * * if (created) { * console.log('Directory created successfully'); * } else { * console.log('Failed to create directory'); * } * ``` */ CreateDirectory(directoryPath: string): Promise; /** * Deletes a directory (virtual) and optionally its contents from S3. * * For non-recursive deletion, this method simply deletes the directory * placeholder object. For recursive deletion, it lists all objects with * the directory path as prefix and deletes them using the DeleteObjects API, * which allows for deleting up to 1000 objects in a single request. * * Note: This implementation doesn't handle pagination for directories with * more than 1000 objects. In a production environment, you might want to * enhance this to handle such cases. * * @param directoryPath - The path of the directory to delete * @param recursive - If true, deletes all contents recursively (default: false) * @returns A Promise resolving to a boolean indicating success * * @example * ```typescript * // Delete an empty directory * const deleted = await s3Storage.DeleteDirectory('documents/temp/'); * * // Delete a directory and all its contents * const recursivelyDeleted = await s3Storage.DeleteDirectory('documents/old_projects/', true); * ``` */ DeleteDirectory(directoryPath: string, recursive?: boolean): Promise; /** * Retrieves metadata for a specific object in S3. * * This method fetches the properties of an object using the HeadObject API, * which doesn't download the object content. This is more efficient for * checking file attributes like size, content type, and last modified date. * * @param params - Object identifier (objectId and fullPath are equivalent for S3) * @returns A Promise resolving to a StorageObjectMetadata object * @throws Error if the object doesn't exist or cannot be accessed * * @example * ```typescript * try { * // For S3, objectId and fullPath are the same (both are the S3 key) * const metadata = await s3Storage.GetObjectMetadata({ fullPath: 'documents/report.pdf' }); * // Or equivalently: * const metadata2 = await s3Storage.GetObjectMetadata({ objectId: 'documents/report.pdf' }); * * console.log(`File: ${metadata.name}`); * console.log(`Size: ${metadata.size} bytes`); * console.log(`Last modified: ${metadata.lastModified}`); * } catch (error) { * console.error('File does not exist or cannot be accessed'); * } * ``` */ GetObjectMetadata(params: GetObjectMetadataParams): Promise; /** * Downloads an object's content from S3. * * This method retrieves the full content of an object using the GetObject API * and returns it as a Buffer for processing in memory. * * @param params - Object identifier (objectId and fullPath are equivalent for S3) * @returns A Promise resolving to a Buffer containing the object's data * @throws Error if the object doesn't exist or cannot be downloaded * * @example * ```typescript * try { * // For S3, objectId and fullPath are the same (both are the S3 key) * const content = await s3Storage.GetObject({ fullPath: 'documents/config.json' }); * // Or equivalently: * const content2 = await s3Storage.GetObject({ objectId: 'documents/config.json' }); * * // Parse the JSON content * const config = JSON.parse(content.toString('utf8')); * console.log('Configuration loaded:', config); * } catch (error) { * console.error('Failed to download file:', error.message); * } * ``` */ GetObject(params: GetObjectParams): Promise; /** * S3 supports ranged streaming via the GetObject API's `Range` parameter. */ get SupportsStreaming(): boolean; /** * Streams an object's content from S3, optionally honoring a byte range. * * Uses the S3 `GetObjectCommand` with the `Range` parameter so large objects are * served as a Node.js readable stream without buffering in memory. The S3 response * carries `ContentType`, `ContentLength`, and (for ranged reads) `ContentRange`, * which are mapped directly onto the {@link ObjectStreamResult}. * * @param params - Object identifier (objectId and fullPath are equivalent for S3) plus optional Range. * @returns A Promise resolving to an {@link ObjectStreamResult}. * @throws Error if the object doesn't exist or cannot be streamed. */ GetObjectStream(params: GetObjectStreamParams): Promise; /** * Parses an S3 `Content-Range` header value (`bytes start-end/total`) into the * structured form used by {@link ObjectStreamResult.ContentRange}. * * @param contentRange - The raw `ContentRange` value from the S3 response, if present. * @returns The parsed range, or undefined when no (valid) range header was returned. */ private _parseS3ContentRange; /** * Uploads data to an object in S3. * * This method directly uploads a Buffer of data to an object with the specified name. * It's useful for server-side operations where you already have the data in memory. * * @param objectName - The name to assign to the uploaded object * @param data - The Buffer containing the data to upload * @param contentType - Optional MIME type for the object (inferred from name if not provided) * @param metadata - Optional key-value pairs of custom metadata to associate with the object * @returns A Promise resolving to a boolean indicating success * * @example * ```typescript * // Upload a text file * const content = Buffer.from('Hello, World!', 'utf8'); * const uploaded = await s3Storage.PutObject( * 'documents/hello.txt', * content, * 'text/plain', * { author: 'John Doe', department: 'Engineering' } * ); * * if (uploaded) { * console.log('File uploaded successfully'); * } else { * console.log('Failed to upload file'); * } * ``` */ PutObject(objectName: string, data: Buffer, contentType?: string, metadata?: Record): Promise; /** * Copies an object within S3. * * This method creates a copy of an object at a new location without removing the original. * It uses the CopyObject API, which allows for copying objects within the same bucket. * * @param sourceObjectName - The name of the object to copy * @param destinationObjectName - The name to assign to the copied object * @returns A Promise resolving to a boolean indicating success * * @example * ```typescript * // Create a backup copy of an important file * const copied = await s3Storage.CopyObject( * 'documents/contract.pdf', * 'backups/contract_2024-05-16.pdf' * ); * * if (copied) { * console.log('File copied successfully'); * } else { * console.log('Failed to copy file'); * } * ``` */ CopyObject(sourceObjectName: string, destinationObjectName: string): Promise; /** * Checks if an object exists in S3. * * This method verifies the existence of an object using the HeadObject API, * which doesn't download the object content. This is efficient for validation purposes. * * @param objectName - The name of the object to check * @returns A Promise resolving to a boolean indicating if the object exists * * @example * ```typescript * // Check if a file exists before attempting to use it * const exists = await s3Storage.ObjectExists('documents/report.pdf'); * * if (exists) { * console.log('File exists, proceeding with download'); * const content = await s3Storage.GetObject('documents/report.pdf'); * // Process the content... * } else { * console.log('File does not exist'); * } * ``` */ ObjectExists(objectName: string): Promise; /** * Checks if a directory (virtual) exists in S3. * * Since S3 doesn't have a native directory concept, this method checks for either: * 1. The existence of a directory placeholder object (zero-byte object with trailing slash) * 2. The existence of any objects with the directory path as a prefix * * @param directoryPath - The path of the directory to check * @returns A Promise resolving to a boolean indicating if the directory exists * * @example * ```typescript * // Check if a directory exists before trying to save files to it * const exists = await s3Storage.DirectoryExists('documents/reports/'); * * if (!exists) { * console.log('Directory does not exist, creating it first'); * await s3Storage.CreateDirectory('documents/reports/'); * } * * // Now safe to use the directory * await s3Storage.PutObject('documents/reports/new-report.pdf', fileData); * ``` */ DirectoryExists(directoryPath: string): Promise; /** * Search is not supported by AWS S3. * S3 is an object storage service without built-in search capabilities. * * To search S3 objects, consider: * - Using AWS Athena to query S3 data * - Maintaining a separate search index (Elasticsearch, OpenSearch, etc.) * - Using S3 Select for querying individual objects * - Using S3 Inventory for listing and filtering objects * * @param query - The search query (not used) * @param options - Search options (not used) * @throws UnsupportedOperationError always */ SearchFiles(query: string, options?: FileSearchOptions): Promise; } export {}; //# sourceMappingURL=AWSFileStorage.d.ts.map