import { AbstractPowerSyncDatabase } from '../client/AbstractPowerSyncDatabase.js'; import { ILogger } from '../utils/Logger.js'; import { Transaction } from '../db/DBAdapter.js'; import { AttachmentData, LocalStorageAdapter } from './LocalStorageAdapter.js'; import { RemoteStorageAdapter } from './RemoteStorageAdapter.js'; import { AttachmentRecord } from './Schema.js'; import { WatchedAttachmentItem } from './WatchedAttachmentItem.js'; import { AttachmentErrorHandler } from './AttachmentErrorHandler.js'; /** * AttachmentQueue manages the lifecycle and synchronization of attachments * between local and remote storage. * Provides automatic synchronization, upload/download queuing, attachment monitoring, * verification and repair of local files, and cleanup of archived attachments. * * @experimental * @alpha This is currently experimental and may change without a major version bump. */ export declare class AttachmentQueue { /** Timer for periodic synchronization operations */ private periodicSyncTimer?; /** Service for synchronizing attachments between local and remote storage */ private readonly syncingService; /** Adapter for local file storage operations */ readonly localStorage: LocalStorageAdapter; /** Adapter for remote file storage operations */ readonly remoteStorage: RemoteStorageAdapter; /** * Callback function to watch for changes in attachment references in your data model. * * This should be implemented by the user of AttachmentQueue to monitor changes in your application's * data that reference attachments. When attachments are added, removed, or modified, * this callback should trigger the onUpdate function with the current set of attachments. */ private readonly watchAttachments; /** Name of the database table storing attachment records */ readonly tableName: string; /** Logger instance for diagnostic information */ readonly logger: ILogger; /** Interval in milliseconds between periodic sync operations. Acts as a polling timer to retry * failed uploads/downloads, especially after the app goes offline. Default: 30000 (30 seconds) */ readonly syncIntervalMs: number; /** Throttle duration in milliseconds for the reactive watch query on the attachments table. * When attachment records change, a watch query detects the change and triggers a sync. * This throttle prevents the sync from firing too rapidly when many changes happen in * quick succession (e.g., bulk inserts). This is distinct from syncIntervalMs — it controls * how quickly the queue reacts to changes, while syncIntervalMs controls how often it polls * for retries. Default: 30 (from DEFAULT_WATCH_THROTTLE_MS) */ readonly syncThrottleDuration: number; /** Whether to automatically download remote attachments. Default: true */ readonly downloadAttachments: boolean; /** Maximum number of archived attachments to keep before cleanup. Default: 100 */ readonly archivedCacheLimit: number; /** Service for managing attachment-related database operations */ private readonly attachmentService; /** PowerSync database instance */ private readonly db; /** Cleanup function for status change listener */ private statusListenerDispose?; private watchActiveAttachments; private watchAttachmentsAbortController; /** * Creates a new AttachmentQueue instance. * * @param options - Configuration options * @param options.db - PowerSync database instance * @param options.remoteStorage - Remote storage adapter for upload/download operations * @param options.localStorage - Local storage adapter for file persistence * @param options.watchAttachments - Callback for monitoring attachment changes in your data model * @param options.tableName - Name of the table to store attachment records. Default: 'ps_attachment_queue' * @param options.logger - Logger instance. Defaults to db.logger * @param options.syncIntervalMs - Periodic polling interval in milliseconds for retrying failed uploads/downloads. Default: 30000 * @param options.syncThrottleDuration - Throttle duration in milliseconds for the reactive watch query that detects attachment changes. Prevents rapid-fire syncs during bulk changes. Default: 30 * @param options.downloadAttachments - Whether to automatically download remote attachments. Default: true * @param options.archivedCacheLimit - Maximum archived attachments before cleanup. Default: 100 */ constructor({ db, localStorage, remoteStorage, watchAttachments, logger, tableName, syncIntervalMs, syncThrottleDuration, downloadAttachments, archivedCacheLimit, errorHandler }: { db: AbstractPowerSyncDatabase; remoteStorage: RemoteStorageAdapter; localStorage: LocalStorageAdapter; watchAttachments: (onUpdate: (attachment: WatchedAttachmentItem[]) => Promise, signal: AbortSignal) => void; tableName?: string; logger?: ILogger; syncIntervalMs?: number; syncThrottleDuration?: number; downloadAttachments?: boolean; archivedCacheLimit?: number; errorHandler?: AttachmentErrorHandler; }); /** * Generates a new attachment ID using a SQLite UUID function. * * @returns Promise resolving to the new attachment ID */ generateAttachmentId(): Promise; /** * Starts the attachment synchronization process. * * This method: * - Stops any existing sync operations * - Sets up periodic synchronization based on syncIntervalMs * - Registers listeners for active attachment changes * - Processes watched attachments to queue uploads/downloads * - Handles state transitions for archived and new attachments */ startSync(): Promise; /** * Synchronizes all active attachments between local and remote storage. * * This is called automatically at regular intervals when sync is started, * but can also be called manually to trigger an immediate sync. */ syncStorage(): Promise; /** * Stops the attachment synchronization process. * * Clears the periodic sync timer and closes all active attachment watchers. */ stopSync(): Promise; /** * Saves a file to local storage and queues it for upload to remote storage. * * @param options - File save options * @param options.data - The file data as ArrayBuffer, Blob, or base64 string * @param options.fileExtension - File extension (e.g., 'jpg', 'pdf') * @param options.mediaType - MIME type of the file (e.g., 'image/jpeg') * @param options.metaData - Optional metadata to associate with the attachment * @param options.id - Optional custom ID. If not provided, a UUID will be generated * @param options.updateHook - Optional callback to execute additional database operations * within the same transaction as the attachment creation * @returns Promise resolving to the created attachment record */ saveFile({ data, fileExtension, mediaType, metaData, id, updateHook }: { data: AttachmentData; fileExtension: string; mediaType?: string; metaData?: string; id?: string; updateHook?: (transaction: Transaction, attachment: AttachmentRecord) => Promise; }): Promise; deleteFile({ id, updateHook }: { id: string; updateHook?: (transaction: Transaction, attachment: AttachmentRecord) => Promise; }): Promise; expireCache(): Promise; clearQueue(): Promise; /** * Verifies the integrity of all attachment records and repairs inconsistencies. * * This method checks each attachment record against the local filesystem and: * - Updates localUri if the file exists at a different path * - Archives attachments with missing local files that haven't been uploaded * - Requeues synced attachments for download if their local files are missing */ verifyAttachments(): Promise; }