FileStorageBase implementation for Microsoft SharePoint using the Microsoft Graph API

This provider allows working with files stored in SharePoint document libraries. It uses the Microsoft Graph API and client credentials authentication flow to securely access and manipulate SharePoint files and folders.

Remarks

This implementation requires the following environment variables:

  • STORAGE_SHAREPOINT_CLIENT_ID - Azure AD application (client) ID
  • STORAGE_SHAREPOINT_CLIENT_SECRET - Azure AD application client secret
  • STORAGE_SHAREPOINT_TENANT_ID - Azure AD tenant ID
  • STORAGE_SHAREPOINT_SITE_ID - The SharePoint site ID
  • STORAGE_SHAREPOINT_DRIVE_ID - The ID of the document library (drive)
  • STORAGE_SHAREPOINT_ROOT_FOLDER_ID (optional) - ID of a subfolder to use as the root

To use this provider, you need to:

  1. Register an Azure AD application with appropriate Microsoft Graph API permissions (typically Files.ReadWrite.All and Sites.ReadWrite.All)
  2. Create a client secret for the application
  3. Grant admin consent for the permissions
  4. Find your SharePoint site ID and document library (drive) ID using the Microsoft Graph Explorer

Example

// Set required environment variables before creating the provider
process.env.STORAGE_SHAREPOINT_CLIENT_ID = 'your-client-id';
process.env.STORAGE_SHAREPOINT_CLIENT_SECRET = 'your-client-secret';
process.env.STORAGE_SHAREPOINT_TENANT_ID = 'your-tenant-id';
process.env.STORAGE_SHAREPOINT_SITE_ID = 'your-site-id';
process.env.STORAGE_SHAREPOINT_DRIVE_ID = 'your-drive-id';

// Create the provider
const storage = new SharePointFileStorage();

// Upload a file
const fileContent = Buffer.from('Hello, SharePoint!');
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');

Hierarchy (view full)

Constructors

Properties

_client: Client

Microsoft Graph API client

_driveId: string

The ID of the SharePoint document library (drive)

_rootFolderId?: string

Optional ID of a subfolder to use as the root folder (if specified)

_siteId: string

The ID of the SharePoint site

providerName: "SharePoint" = 'SharePoint'

The name of this storage provider

Accessors

Methods

  • Copies a file from one location to another

    This method creates a copy of a file at a new location. The original file remains unchanged.

    Parameters

    • sourceObjectName: string

      Path to the source file (e.g., 'templates/report-template.docx')

    • destinationObjectName: string

      Path where the copy should be created (e.g., 'documents/new-report.docx')

    Returns Promise<boolean>

    A Promise that resolves to true if successful, false if an error occurs

    Remarks

    • The parent folder of the destination must exist
    • Both files and folders can be copied
    • The operation is asynchronous in SharePoint and may not complete immediately

    Example

    // Copy a file to a new location with a different name
    const copyResult = await storage.CopyObject(
    'templates/financial-report.xlsx',
    'reports/2024/q1-financial-report.xlsx'
    );

    if (copyResult) {
    console.log('File copied successfully');
    } else {
    console.error('Failed to copy file');
    }
  • Creates a directory (folder) in SharePoint

    This method creates a new folder at the specified path. The parent directory must already exist.

    Parameters

    • directoryPath: string

      Path where the directory should be created (e.g., 'documents/new-folder')

    Returns Promise<boolean>

    A Promise that resolves to true if successful, false if an error occurs

    Remarks

    • If a folder with the same name already exists, the operation will fail
    • The parent directory must exist for the operation to succeed
    • Trailing slashes in the path are automatically removed

    Example

    // Create a new folder
    const createResult = await storage.CreateDirectory('documents/2024-reports');

    if (createResult) {
    console.log('Folder created successfully');

    // Now we can put files in this folder
    await storage.PutObject(
    'documents/2024-reports/q1-results.xlsx',
    fileContent,
    'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
    );
    } else {
    console.error('Failed to create folder');
    }
  • Creates a pre-authenticated download URL for an object

    This method generates a time-limited, publicly accessible URL that can be used to download a file without authentication. The URL expires after 10 minutes.

    Parameters

    • objectName: string

      Path to the object to create a download URL for (e.g., 'documents/report.pdf')

    Returns Promise<string>

    A Promise that resolves to the pre-authenticated download URL

    Throws

    Error if the object doesn't exist or the URL creation fails

    Example

    // Generate a pre-authenticated download URL that will work for 10 minutes
    const downloadUrl = await storage.CreatePreAuthDownloadUrl('presentations/quarterly-update.pptx');
    console.log(`Download the file using this URL: ${downloadUrl}`);

    // You can share this URL with users who don't have SharePoint access
    // The URL will expire after 10 minutes
  • Creates a pre-authenticated upload URL (not supported in SharePoint)

    This method is not supported for SharePoint storage as SharePoint doesn't provide a way to generate pre-authenticated upload URLs like object storage services. Instead, use the PutObject method for file uploads.

    Parameters

    • objectName: string

      The object name (path) to create a pre-auth URL for

    Returns Promise<CreatePreAuthUploadUrlPayload>

    Throws

    UnsupportedOperationError always, as this operation is not supported

    Example

    // 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 SharePoint.');
    // Use PutObject instead
    await storage.PutObject('documents/report.docx', fileContent, 'application/vnd.openxmlformats-officedocument.wordprocessingml.document');
    }
    }
  • Deletes a directory (folder) and optionally its contents

    This method deletes a folder from SharePoint. By default, it will only delete empty folders unless the recursive parameter is set to true.

    Parameters

    • directoryPath: string

      Path to the directory to delete (e.g., 'archive/old-reports')

    • recursive: boolean = false

      If true, delete the directory and all its contents; if false, only delete if empty

    Returns Promise<boolean>

    A Promise that resolves to true if successful, false if an error occurs

    Remarks

    • If recursive=false and the directory contains files, the operation will fail
    • SharePoint deleted items may be recoverable from the recycle bin depending on site settings
    • Trailing slashes in the path are automatically removed

    Example

    // Attempt to delete an empty folder
    const deleteResult = await storage.DeleteDirectory('temp/empty-folder');

    // 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');
    }
  • Deletes an object (file) from SharePoint

    This method permanently deletes a file from SharePoint storage. Note that deleted files may be recoverable from the SharePoint recycle bin depending on your SharePoint configuration.

    Parameters

    • objectName: string

      Path to the object to delete (e.g., 'documents/old-report.docx')

    Returns Promise<boolean>

    A Promise that resolves to true if successful, false if an error occurs

    Remarks

    • Returns true if the object doesn't exist (for idempotency)
    • Handles 404 errors by returning true since the end result is the same

    Example

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

    Parameters

    • directoryPath: string

      Path to check (e.g., 'documents/reports')

    Returns Promise<boolean>

    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

    // 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, 'application/pdf');
  • Downloads a file's contents

    This method retrieves the raw content of a file as a Buffer.

    Parameters

    • params: GetObjectParams

      Object identifier (prefer objectId for performance, fallback to fullPath)

    Returns Promise<Buffer>

    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 uses the Graph API's download URL to retrieve the file contents
    • The method will throw an error if the object is a folder
    • For large files, consider using CreatePreAuthDownloadUrl instead

    Example

    try {
    // Fast path: Use objectId (SharePoint item ID)
    const fileContent = await storage.GetObject({ objectId: '01BYE5RZ6QN3VYRVNHHFDK2QJODWDDFR4E' });

    // 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 a local file
    // or process it as needed
    } catch (error) {
    console.error('Error downloading file:', error.message);
    }
  • 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.

    Parameters

    Returns Promise<StorageObjectMetadata>

    A Promise that resolves to a StorageObjectMetadata object

    Throws

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

    Example

    try {
    // Fast path: Use objectId (SharePoint item ID)
    const metadata = await storage.GetObjectMetadata({ objectId: '01BYE5RZ6QN3VYRVNHHFDK2QJODWDDFR4E' });

    // Slow path: Use path
    const metadata2 = await storage.GetObjectMetadata({ fullPath: 'presentations/quarterly-update.pptx' });

    console.log(`Name: ${metadata.name}`);
    console.log(`Size: ${metadata.size} bytes`);
    console.log(`Content Type: ${metadata.contentType}`);
    console.log(`Last Modified: ${metadata.lastModified}`);
    console.log(`Is Directory: ${metadata.isDirectory}`);
    } catch (error) {
    console.error('Error getting metadata:', error.message);
    }
  • Lists objects in a given directory (folder)

    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.

    Parameters

    • prefix: string

      Path to the directory to list (e.g., 'documents/reports')

    • Optional delimiter: string

      Optional delimiter character (not used in this implementation)

    Returns Promise<StorageListResult>

    A Promise that resolves to a StorageListResult containing objects and prefixes

    Remarks

    • The objects array in the result 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

    Example

    // List all files and folders in the 'documents' directory
    const result = await storage.ListObjects('documents');

    // Process files
    for (const obj of result.objects) {
    console.log(`Name: ${obj.name}, Size: ${obj.size}, Type: ${obj.isDirectory ? 'Folder' : 'File'}`);
    }

    // Process subfolders
    for (const prefix of result.prefixes) {
    console.log(`Subfolder: ${prefix}`);
    }
  • Moves an object from one location to another

    This method moves a file or folder from one location in SharePoint to another. It handles both renaming and changing the parent folder.

    Parameters

    • oldObjectName: string

      Current path of the object (e.g., 'old-folder/document.docx')

    • newObjectName: string

      New path for the object (e.g., 'new-folder/renamed-document.docx')

    Returns Promise<boolean>

    A Promise that resolves to true if successful, false otherwise

    Example

    // Move a file to a different folder
    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');
    }
  • Checks if a file or folder exists

    This method verifies whether an object (file or folder) exists at the specified path.

    Parameters

    • objectName: string

      Path to check (e.g., 'documents/report.pdf')

    Returns Promise<boolean>

    A Promise that resolves to true if the object exists, false otherwise

    Example

    // 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');
    }
  • Uploads a file to SharePoint

    This method uploads a file to SharePoint at the specified path. It automatically determines whether to use a simple upload or a chunked upload based on file size.

    Parameters

    • objectName: string

      Path where the file should be uploaded (e.g., 'documents/report.pdf')

    • data: Buffer

      Buffer containing the file content

    • Optional contentType: string

      Optional MIME type of the file (if not provided, it will be guessed from the filename)

    • Optional metadata: Record<string, string>

      Optional metadata to associate with the file (not used in SharePoint implementation)

    Returns Promise<boolean>

    A Promise that resolves to true if successful, false if an error occurs

    Remarks

    • Files smaller than 4MB use a simple upload
    • Files 4MB or larger use a chunked upload session for better reliability
    • Automatically creates the parent folder structure if it doesn't exist
    • If a file with the same name exists, it will be replaced

    Example

    // Create a text file
    const textContent = Buffer.from('This is a sample document', 'utf8');
    const uploadResult = await storage.PutObject(
    'documents/sample.txt',
    textContent,
    'text/plain'
    );

    // 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,
    'application/vnd.openxmlformats-officedocument.presentationml.presentation'
    );

    if (largeUploadResult) {
    console.log('Large file uploaded successfully');
    } else {
    console.error('Failed to upload large file');
    }
  • Search files in SharePoint using Microsoft Graph Search API.

    This method provides powerful search capabilities using KQL (Keyword Query Language), SharePoint's native query language. The search can target file names, metadata, and optionally file contents.

    Parameters

    • query: string

      The search query string. Can be plain text or use KQL syntax for advanced queries.

    • Optional options: FileSearchOptions

      Optional search configuration including filters, limits, and content search

    Returns Promise<FileSearchResultSet>

    A Promise resolving to FileSearchResultSet with matched files and pagination info

    Remarks

    KQL Query Syntax Examples:

    • Simple text: "quarterly report" - searches for files containing these terms
    • Boolean operators: "budget AND 2024", "draft OR final", "report NOT internal"
    • Wildcards: "proj*" matches "project", "projection", etc.
    • Property filters: "FileType:pdf", "Author:John Smith", "Size>1000000"
    • Date filters: "Created>=2024-01-01", "LastModifiedTime<2024-12-31"
    • Proximity: "project NEAR report" - finds terms near each other
    • Exact phrases: "\"annual budget report\"" - exact phrase match

    Additional Filtering: The method automatically adds KQL filters based on the provided options:

    • fileTypes: Adds FileType filters (e.g., FileType:pdf OR FileType:docx)
    • modifiedAfter/modifiedBefore: Adds LastModifiedTime filters
    • pathPrefix: Adds Path filter to restrict search to a directory
    • searchContent: When false, restricts search to filename only

    Example

    // Simple text search in filenames
    const results = await storage.SearchFiles('quarterly report', {
    maxResults: 20
    });

    // Search for PDFs only
    const pdfResults = await storage.SearchFiles('budget', {
    fileTypes: ['pdf'],
    maxResults: 50
    });

    // Search with date range
    const recentResults = await storage.SearchFiles('meeting notes', {
    modifiedAfter: new Date('2024-01-01'),
    modifiedBefore: new Date('2024-12-31'),
    searchContent: true
    });

    // Search within specific directory
    const folderResults = await storage.SearchFiles('presentation', {
    pathPrefix: 'documents/reports',
    fileTypes: ['pptx', 'pdf']
    });

    // Advanced KQL query
    const advancedResults = await storage.SearchFiles(
    'FileType:xlsx AND Created>=2024-01-01 AND Author:"John Smith"',
    { maxResults: 100 }
    );
  • Private

    Gets a SharePoint item by its path

    This helper method retrieves a SharePoint item (file or folder) using its path. It handles path normalization and root folder redirection.

    Parameters

    • path: string

      The path of the item to retrieve (e.g., 'documents/reports/report.docx')

    Returns Promise<any>

    A Promise that resolves to the SharePoint item

    Throws

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

  • Private

    Gets the SharePoint item ID for a folder at the specified path

    This helper method navigates the folder hierarchy in SharePoint to find the folder specified by the path, returning its item ID.

    Parameters

    • path: string

      The path to get the parent folder for (e.g., 'documents/reports')

    Returns Promise<string>

    A Promise that resolves to the parent folder ID

    Throws

    Error if any folder in the path doesn't exist

  • Private

    Builds a KQL (Keyword Query Language) query string from the base query and search options.

    This helper method constructs a properly formatted KQL query by combining the user's search query with filters derived from FileSearchOptions. It handles file type filters, date range filters, path restrictions, and content search options.

    Parameters

    • baseQuery: string

      The user's search query (plain text or KQL)

    • Optional options: FileSearchOptions

      Optional search options to convert into KQL filters

    Returns string

    A complete KQL query string

  • Private

    Determines whether the search match was in the filename or content.

    This helper method analyzes the hit metadata to determine if the search term was found in the filename versus the file content.

    Parameters

    • hit: any

      The search hit object from Graph API

    Returns boolean

    True if match was in filename, false if in content, undefined if unknown

  • Private

    Extracts the file path from a SharePoint resource object.

    This helper method processes the path information from a Graph API resource, removing the drive and site prefixes to return just the file path relative to the configured root folder.

    Parameters

    • resource: any

      The resource object from Graph API search results

    Returns string

    The relative file path

  • 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

  • Private

    Transforms Microsoft Graph Search API response into FileSearchResultSet format.

    This helper method processes the raw search response from the Graph API, extracting relevant file information and converting it to the standard FileSearchResult format. It handles pagination info and calculates relevance scores.

    Parameters

    • response: any

      The raw response from Microsoft Graph Search API

    • maxResults: number

      The maximum number of results requested

    Returns FileSearchResultSet

    A FileSearchResultSet with transformed results