@@ -7,7 +7,7 @@ import { AttachmentErrorHandler } from './AttachmentErrorHandler.js';
77import { AttachmentService } from './AttachmentService.js' ;
88import { AttachmentTransportAdapter } from './AttachmentTransportAdapter.js' ;
99import { BufferedAttachmentTransport } from './BufferedAttachmentTransport.js' ;
10- import { AttachmentData , LocalStorageAdapter } from './LocalStorageAdapter.js' ;
10+ import { AttachmentData , LocalStorageAdapter , StreamingLocalStorageAdapter } from './LocalStorageAdapter.js' ;
1111import { RemoteStorageAdapter } from './RemoteStorageAdapter.js' ;
1212import { ATTACHMENT_TABLE , AttachmentRecord , AttachmentState } from './Schema.js' ;
1313import { SyncingService } from './SyncingService.js' ;
@@ -20,15 +20,17 @@ import { CommonPowerSyncDatabase } from '../client/CommonPowerSyncDatabase.js';
2020 * @experimental
2121 * @alpha This is currently experimental and may change without a major version bump.
2222 */
23- export interface BaseAttachmentQueueOptions {
23+ export interface BaseAttachmentQueueOptions < TLocal extends LocalStorageAdapter = LocalStorageAdapter > {
2424 /**
2525 * PowerSync database instance
2626 */
2727 db : CommonPowerSyncDatabase ;
2828 /**
29- * Local storage adapter for file persistence
29+ * Local storage adapter for file persistence. Its type determines whether
30+ * {@link AttachmentQueue.saveFileFromUri} is available (a
31+ * {@link StreamingLocalStorageAdapter} enables it).
3032 */
31- localStorage : LocalStorageAdapter ;
33+ localStorage : TLocal ;
3234 /**
3335 * Callback for monitoring attachment changes in your data model
3436 */
@@ -77,11 +79,12 @@ export interface BaseAttachmentQueueOptions {
7779 * @experimental
7880 * @alpha This is currently experimental and may change without a major version bump.
7981 */
80- export type AttachmentQueueOptions = BaseAttachmentQueueOptions &
81- (
82- | { remoteStorage : RemoteStorageAdapter ; transportAdapter ?: never }
83- | { transportAdapter : AttachmentTransportAdapter ; remoteStorage ?: never }
84- ) ;
82+ export type AttachmentQueueOptions < TLocal extends LocalStorageAdapter = LocalStorageAdapter > =
83+ BaseAttachmentQueueOptions < TLocal > &
84+ (
85+ | { remoteStorage : RemoteStorageAdapter ; transportAdapter ?: never }
86+ | { transportAdapter : AttachmentTransportAdapter ; remoteStorage ?: never }
87+ ) ;
8588
8689/**
8790 * Fields shared by {@link AttachmentQueue.saveFile} and {@link AttachmentQueue.saveFileFromUri}.
@@ -116,15 +119,15 @@ type AttachmentSource = { kind: 'data'; data: AttachmentData } | { kind: 'uri';
116119 * @experimental
117120 * @alpha This is currently experimental and may change without a major version bump.
118121 */
119- export class AttachmentQueue {
122+ export class AttachmentQueue < TLocal extends LocalStorageAdapter = LocalStorageAdapter > {
120123 /** Timer for periodic synchronization operations */
121124 private periodicSyncTimer ?: ReturnType < typeof setInterval > ;
122125
123126 /** Service for synchronizing attachments between local and remote storage */
124127 private readonly syncingService : SyncingService ;
125128
126129 /** Adapter for local file storage operations */
127- readonly localStorage : LocalStorageAdapter ;
130+ readonly localStorage : TLocal ;
128131
129132 /**
130133 * Callback function to watch for changes in attachment references in your data model.
@@ -208,7 +211,7 @@ export class AttachmentQueue {
208211 downloadAttachments = true ,
209212 archivedCacheLimit = 100 ,
210213 errorHandler
211- } : AttachmentQueueOptions ) {
214+ } : AttachmentQueueOptions < TLocal > ) {
212215 this . db = db ;
213216 this . syncLoopMutex = db . createMutex ( ) ;
214217 this . localStorage = localStorage ;
@@ -470,10 +473,13 @@ export class AttachmentQueue {
470473 if ( source . kind === 'data' ) {
471474 size = await this . localStorage . saveFile ( localUri , source . data ) ;
472475 } else {
473- if ( ! this . localStorage . moveFile ) {
476+ // saveFileFromUri is only exposed for streaming-capable local adapters; guard at
477+ // runtime too for plain-JS callers.
478+ const localStorage = this . localStorage as Partial < StreamingLocalStorageAdapter > ;
479+ if ( ! localStorage . moveFile ) {
474480 throw new Error ( 'The configured local storage adapter does not support moveFile, required by saveFileFromUri.' ) ;
475481 }
476- size = await this . localStorage . moveFile ( source . localUri , localUri ) ;
482+ size = await localStorage . moveFile ( source . localUri , localUri ) ;
477483 }
478484
479485 const attachment : AttachmentRecord = {
@@ -516,11 +522,16 @@ export class AttachmentQueue {
516522 * (recordings, videos): it avoids reading the file into an `ArrayBuffer` just to write
517523 * it back to disk. Requires the local storage adapter to implement `moveFile`.
518524 *
525+ * Only available when the queue is configured with a {@link StreamingLocalStorageAdapter}
526+ * (one that implements `moveFile`).
527+ *
519528 * @param options - The existing file's `localUri` plus {@link SaveAttachmentOptions}
520529 * @returns Promise resolving to the created attachment record
521- * @throws Error if the local storage adapter does not support moving files
522530 */
523- async saveFileFromUri ( options : SaveAttachmentOptions & { localUri : string } ) : Promise < AttachmentRecord > {
531+ async saveFileFromUri (
532+ this : AttachmentQueue < StreamingLocalStorageAdapter > ,
533+ options : SaveAttachmentOptions & { localUri : string }
534+ ) : Promise < AttachmentRecord > {
524535 return this . createUploadAttachment ( options , { kind : 'uri' , localUri : options . localUri } ) ;
525536 }
526537
0 commit comments