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

// 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/');

Hierarchy (view full)

Constructors

Properties

_accessKeyId: string

AWS access key ID

_bucket: string

The S3 bucket name

_bucketName: string

S3 bucket name (for IsConfigured check)

_client: S3Client

The S3 client instance

_keyPrefix: string

The key prefix to prepend to all object keys

_secretAccessKey: string

AWS secret access key

providerName: "AWS S3" = 'AWS S3'

The name of this storage provider, used in error messages

Accessors

Methods

  • 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.

    Parameters

    • sourceObjectName: string

      The name of the object to copy

    • destinationObjectName: string

      The name to assign to the copied object

    Returns Promise<boolean>

    A Promise resolving to a boolean indicating success

    Example

    // 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');
    }
  • 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.

    Parameters

    • directoryPath: string

      The path of the directory to create

    Returns Promise<boolean>

    A Promise resolving to a boolean indicating success

    Example

    // 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');
    }
  • 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.

    Parameters

    • objectName: string

      The name of the object to download (including any path/directory)

    Returns Promise<string>

    A Promise resolving to the download URL

    Example

    // 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);
  • 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.

    Parameters

    • objectName: string

      The name of the object to upload (including any path/directory)

    Returns Promise<CreatePreAuthUploadUrlPayload>

    A Promise resolving to an object with the upload URL

    Example

    // 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);
  • 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.

    Parameters

    • directoryPath: string

      The path of the directory to delete

    • recursive: boolean = false

      If true, deletes all contents recursively (default: false)

    Returns Promise<boolean>

    A Promise resolving to a boolean indicating success

    Example

    // 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);
  • Deletes an object from S3.

    This method attempts to delete the specified object. It returns true if the operation was successful, false otherwise.

    Parameters

    • objectName: string

      The name of the object to delete (including any path/directory)

    Returns Promise<boolean>

    A Promise resolving to a boolean indicating success

    Example

    // 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');
    }
  • 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

    Parameters

    • directoryPath: string

      The path of the directory to check

    Returns Promise<boolean>

    A Promise resolving to a boolean indicating if the directory exists

    Example

    // 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);
  • 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.

    Parameters

    • params: GetObjectParams

      Object identifier (objectId and fullPath are equivalent for S3)

    Returns Promise<Buffer>

    A Promise resolving to a Buffer containing the object's data

    Throws

    Error if the object doesn't exist or cannot be downloaded

    Example

    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);
    }
  • 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.

    Parameters

    Returns Promise<StorageObjectMetadata>

    A Promise resolving to a StorageObjectMetadata object

    Throws

    Error if the object doesn't exist or cannot be accessed

    Example

    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');
    }
  • 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.

    Parameters

    • prefix: string

      The path prefix to list objects from (e.g., 'documents/')

    • delimiter: string = '/'

      The character used to simulate directory structure, defaults to '/'

    Returns Promise<StorageListResult>

    A Promise resolving to a StorageListResult containing objects and prefixes

    Example

    // 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}`);
    }
  • 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.

    Parameters

    • oldObjectName: string

      The current name/path of the object

    • newObjectName: string

      The new name/path for the object

    Returns Promise<boolean>

    A Promise resolving to a boolean indicating success

    Example

    // 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');
    }
  • 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.

    Parameters

    • objectName: string

      The name of the object to check

    Returns Promise<boolean>

    A Promise resolving to a boolean indicating if the object exists

    Example

    // 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');
    }
  • 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.

    Parameters

    • objectName: string

      The name to assign to the uploaded object

    • data: Buffer

      The Buffer containing the data to upload

    • Optional contentType: string

      Optional MIME type for the object (inferred from name if not provided)

    • Optional metadata: Record<string, string>

      Optional key-value pairs of custom metadata to associate with the object

    Returns Promise<boolean>

    A Promise resolving to a boolean indicating success

    Example

    // 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');
    }
  • 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

    Parameters

    • query: string

      The search query (not used)

    • Optional options: FileSearchOptions

      Search options (not used)

    Returns Promise<FileSearchResultSet>

    Throws

    UnsupportedOperationError always

  • Private

    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.

    Parameters

    • objectName: string

      The object name to normalize

    Returns string

    The normalized object name with the proper prefix

  • Private

    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.

    Parameters

    • key: string

      The full key including the prefix

    Returns string

    The object name without the prefix

  • Optional initialization method for storage providers that require async setup.

    This method can be overridden by subclasses that need to perform async initialization after construction, such as setting up access tokens, establishing connections, or verifying permissions.

    The default implementation does nothing and resolves immediately. Storage provider implementations should override this method if they need to perform async setup.

    Returns Promise<void>

    A Promise that resolves when initialization is complete.

    Example

    // In a specific provider implementation:
    public async initialize(): Promise<void> {
    // Set up OAuth tokens or other async initialization
    await this.refreshAccessToken();
    await this.verifyBucketAccess();
    }

    // Usage:
    const storage = new MyStorageProvider();
    await storage.initialize();
    // Now the provider is ready to use
  • Helper method to throw an UnsupportedOperationError with appropriate context. This method simplifies implementation of methods not supported by specific providers.

    Parameters

    • methodName: string

      The name of the method that is not supported

    Returns never

    Throws

    UnsupportedOperationError with information about the unsupported method and provider