FlyDrive

repository·2.x·Indexed 41 days ago

https://github.com/flydrive-js/core

A Node.js file storage library providing a unified API to manage files across multiple cloud storage providers and local filesystems. Version 2.1.0 supports S3, Cloudflare R2, Google Cloud Storage (GCS), and the local file system via a driver-agnostic interface. It includes a DriveManager for orchestrating multiple disks, support for signed URLs, and built-in fake drivers for unit testing.

Tokens
7.9K
Snippets
31
Records
37
Agent score
52%

What's inside FlyDrive

  1. Overview of FlyDrive

    2.x

    FlyDrive is a multi-driver storage library for Node.js. It provides a unified API to interact with different storage backends, allowing you to switch between the local file system and cloud storage solutions without changing your application logic.

    Supported storage solutions include:

    • Local File System
    • S3 (Amazon Simple Storage Service)
    • R2 (Cloudflare R2)
    • GCS (Google Cloud Storage)
  2. Use the FlyDrive core API

    2.x

    The flydrive package provides a unified interface for managing files and directories across different storage drivers. The main entry points are:

    • DriveManager: The central orchestrator for managing multiple storage drives.
    • Disk: Represents a specific storage drive (e.g., S3, Local, FTP) and provides methods for file and directory operations.
    • DriveFile: Represents a file within a drive.
    • DriveDirectory: Represents a directory within a drive.
    • KeyNormalizer: A utility for normalizing file paths/keys.
    • errors: A namespace containing all library-specific error classes.
    import { DriveManager, Disk, DriveFile, DriveDirectory } from 'flydrive';
  3. Understand FileSnapshot for database persistence

    2.x

    A FileSnapshot is a lightweight representation of a file that can be stored in a database to avoid frequent driver calls. It contains the essential metadata needed to identify and describe a file without storing the actual content.

    type FileSnapshot = {
      key: string
      name: string
      contentLength: number
      lastModified: string
      etag: string
      contentType?: string
    }
  4. Perform partial reads with RangeRequest

    2.x

    To read specific byte ranges of a file, use the range option within ReadOptions (passed to getStream or getBytes).

    RangeRequest requires:

    • start: A positive integer representing the inclusive start byte position (0-indexed).
    • end: A positive integer representing the inclusive end byte position (0-indexed).
    const options = {
      range: {
        start: 0,
        end: 1024
      }
    };
    
    const bytes = await driver.getBytes('file.txt', options);
  5. Use DriveFile to interact with files in storage

    2.x

    The DriveFile class acts as a pointer to an object within a storage drive. It allows you to lazily perform operations like reading contents, retrieving metadata, or generating URLs without needing to interact with the driver directly. You can also convert a DriveFile into a FileSnapshot to persist file information in a database, which can later be used to reconstruct the file instance.

    // Example conceptual usage
    const file = drive.file('path/to/file.txt');
    
    // Check existence
    if (await file.exists()) {
      // Get contents as string
      const content = await file.get();
      
      // Get metadata
      const meta = await file.getMetaData();
      console.log(meta.contentType);
    }
  6. Mock storage services for testing using fake()

    2.x

    You can swap real storage drivers with FakeDisk instances to facilitate testing. When you call .fake(service), any subsequent calls to .use(service) will return the fake instance instead of the real one.

    Requirement: You must include a fakes property in your DriveManagerOptions when initializing the manager, otherwise calling .fake() will throw a RuntimeException.

    To return to the real storage implementation after a test, call .restore(service).

    // 1. Setup manager with fakes config
    const drive = new DriveManager({
      default: 'local',
      services: { local: () => localDriver },
      fakes: { /* fake driver settings */ }
    })
    
    // 2. Deploy the fake
    const fakeDisk = drive.fake('local')
    
    // 3. Subsequent calls to .use() return the fake
    const disk = drive.use('local') // returns FakeDisk
    
    // 4. Restore the real disk
    drive.restore('local')
    const realDisk = drive.use('local') // returns real Disk
  7. Configure fakes for testing

    2.x

    When using fakes provided by the DriveManager, you can configure the fakes option to specify where files are persisted and how URLs are generated.

    • location: A URL or string representing the storage location for fake files.
    • urlBuilder.generateURL: A custom function to generate public URLs.
    • urlBuilder.generateSignedURL: A custom function to generate signed/temporary URLs.
    const options: DriveManagerOptions = {
      default: 'fake',
      services: { fake: () => new FakeDriver() },
      fakes: {
        location: './test-storage',
        urlBuilder: {
          generateURL: async (key, filePath) => `https://fake.com/${filePath}`,
          generateSignedURL: async (key, filePath, options) => `https://fake.com/signed/${filePath}`
        }
      }
    };
  8. Get file metadata and existence

    2.x

    Check file status and properties:

    • exists(key): Returns true if the file exists, false otherwise. Note: This cannot check for the existence of directories.
    • getMetaData(key): Returns an ObjectMetaData object containing file details.
    • getVisibility(key): Returns the current ObjectVisibility of the file.
    if (await disk.exists('data.csv')) {
      const meta = await disk.getMetaData('data.csv');
      console.log(meta.contentType);
    }
  9. Check if an object is a valid range request with isRangeRequest

    2.x

    The isRangeRequest utility function acts as a type guard to determine if a provided object is a functional RangeRequest. It returns true only if the object is defined and contains at least one bound (start or end). This prevents empty range objects from being incorrectly processed as ranged reads.

    import { isRangeRequest, type RangeRequest } from 'flydrive';
    
    const maybeRange: RangeRequest | undefined = { start: 0 };
    
    if (isRangeRequest(maybeRange)) {
      // maybeRange is narrowed to RangeRequest and is guaranteed to have bounds
      console.log(maybeRange.start);
    }
  10. Manage file visibility and URLs

    2.x

    The Disk class allows you to manage access control and retrieve URLs:

    • setVisibility(key, visibility): Updates the file's visibility (e.g., public or private).
    • getUrl(key): Returns the public URL of the file.
    • getSignedUrl(key, options?): Returns a signed/temporary URL for access.
    • getSignedUploadUrl(key, options?): Returns a signed/temporary URL that allows direct uploading of file contents to the storage provider.
    // Set visibility
    await disk.setVisibility('secret.txt', 'private');
    
    // Get URLs
    const publicUrl = await disk.getUrl('avatar.png');
    const tempUrl = await disk.getSignedUrl('report.pdf', { expiresIn: 3600 });
    const uploadUrl = await disk.getSignedUploadUrl('new-file.txt');
  11. Generate URLs with DriveFile

    2.x

    The DriveFile class provides methods to generate different types of URLs:

    • getUrl(): Returns the public URL of the file.
    • getSignedUrl(options?: SignedURLOptions): Returns a signed or temporary URL.
    • getSignedUploadUrl(options?: SignedURLOptions): Returns a signed/temporary URL that can be used to directly upload file contents to the storage.
    // Get public URL
    const url = await file.getUrl();
    
    // Get signed URL for downloading
    const signedUrl = await file.getSignedUrl({ expiresIn: 3600 });
    
    // Get signed URL for direct client-side upload
    const uploadUrl = await file.getSignedUploadUrl();
  12. Write and upload files using Disk

    2.x

    You can create or update files using the following methods:

    • put(key, contents, options?): Writes a string or Uint8Array to the specified key.
    • putStream(key, contents, options?): Writes a Readable stream to the specified key.
    • copyFromFs(source, destination, options?): Copies a file from the local filesystem to the storage provider.

    If a write operation fails, the E_CANNOT_WRITE_FILE error is thrown.

    // Write string
    await disk.put('hello.txt', 'content');
    
    // Write stream
    import { Readable } from 'node:stream';
    const stream = Readable.from(['stream content']);
    await disk.putStream('stream.txt', stream);
    
    // Copy from local filesystem
    await disk.copyFromFs('./local-file.txt', 'remote-file.txt');