@powersync/common 1.56.0 → 1.57.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bundle.cjs +98 -38
- package/dist/bundle.cjs.map +1 -1
- package/dist/bundle.mjs +98 -39
- package/dist/bundle.mjs.map +1 -1
- package/dist/bundle.node.cjs +98 -38
- package/dist/bundle.node.cjs.map +1 -1
- package/dist/bundle.node.mjs +98 -39
- package/dist/bundle.node.mjs.map +1 -1
- package/dist/index.d.cts +54 -8
- package/lib/attachments/AttachmentQueue.d.ts +18 -1
- package/lib/attachments/AttachmentQueue.js +43 -7
- package/lib/attachments/AttachmentQueue.js.map +1 -1
- package/lib/attachments/Schema.d.ts +21 -2
- package/lib/attachments/Schema.js +14 -10
- package/lib/attachments/Schema.js.map +1 -1
- package/lib/attachments/SyncingService.d.ts +14 -4
- package/lib/attachments/SyncingService.js +39 -21
- package/lib/attachments/SyncingService.js.map +1 -1
- package/package.json +1 -1
- package/src/attachments/AttachmentQueue.ts +46 -7
- package/src/attachments/Schema.ts +29 -20
- package/src/attachments/SyncingService.ts +46 -23
package/dist/index.d.cts
CHANGED
|
@@ -3856,14 +3856,33 @@ declare enum AttachmentState {
|
|
|
3856
3856
|
*/
|
|
3857
3857
|
interface AttachmentTableOptions extends Omit<TableV2Options, 'name' | 'columns'> {
|
|
3858
3858
|
}
|
|
3859
|
+
/**
|
|
3860
|
+
* @alpha
|
|
3861
|
+
*/
|
|
3862
|
+
declare const ATTACHMENT_TABLE_COLUMNS: {
|
|
3863
|
+
filename: BaseColumnType<string | null>;
|
|
3864
|
+
local_uri: BaseColumnType<string | null>;
|
|
3865
|
+
timestamp: BaseColumnType<number | null>;
|
|
3866
|
+
size: BaseColumnType<number | null>;
|
|
3867
|
+
media_type: BaseColumnType<string | null>;
|
|
3868
|
+
state: BaseColumnType<number | null>;
|
|
3869
|
+
has_synced: BaseColumnType<number | null>;
|
|
3870
|
+
meta_data: BaseColumnType<string | null>;
|
|
3871
|
+
};
|
|
3859
3872
|
/**
|
|
3860
3873
|
* AttachmentTable defines the schema for the attachment queue table.
|
|
3861
3874
|
*
|
|
3862
3875
|
* @alpha
|
|
3863
3876
|
*/
|
|
3864
|
-
declare class AttachmentTable extends Table {
|
|
3877
|
+
declare class AttachmentTable extends Table<typeof ATTACHMENT_TABLE_COLUMNS> {
|
|
3865
3878
|
constructor(options?: AttachmentTableOptions);
|
|
3866
3879
|
}
|
|
3880
|
+
/**
|
|
3881
|
+
* AttachmentTableRecord represents the row type of the attachment table.
|
|
3882
|
+
*
|
|
3883
|
+
* @alpha
|
|
3884
|
+
*/
|
|
3885
|
+
type AttachmentTableRecord = RowType<AttachmentTable>;
|
|
3867
3886
|
|
|
3868
3887
|
/**
|
|
3869
3888
|
* AttachmentContext provides database operations for managing attachment records.
|
|
@@ -4198,6 +4217,19 @@ declare class AttachmentQueue {
|
|
|
4198
4217
|
private statusListenerDispose?;
|
|
4199
4218
|
private watchActiveAttachments;
|
|
4200
4219
|
private watchAttachmentsAbortController;
|
|
4220
|
+
/**
|
|
4221
|
+
* Serializes concurrent `syncStorage()` triggers (periodic timer, watch-onDiff,
|
|
4222
|
+
* status-changed). Held across the whole batch, but only contended by other
|
|
4223
|
+
* sync triggers — foreground `saveFile` / `deleteFile` / watched-attachment
|
|
4224
|
+
* processing don't take this lock and proceed in parallel via the
|
|
4225
|
+
* `AttachmentService` mutex, which is acquired only briefly per row.
|
|
4226
|
+
*/
|
|
4227
|
+
private syncLoopMutex;
|
|
4228
|
+
/**
|
|
4229
|
+
* Aborted by `stopSync()` to interrupt an in-flight batch within one
|
|
4230
|
+
* attachment's processing time. Polled between rows by `SyncingService`.
|
|
4231
|
+
*/
|
|
4232
|
+
private syncAbortController?;
|
|
4201
4233
|
/**
|
|
4202
4234
|
* Creates a new AttachmentQueue instance.
|
|
4203
4235
|
*
|
|
@@ -4226,12 +4258,16 @@ declare class AttachmentQueue {
|
|
|
4226
4258
|
*
|
|
4227
4259
|
* This is called automatically at regular intervals when sync is started,
|
|
4228
4260
|
* but can also be called manually to trigger an immediate sync.
|
|
4261
|
+
*
|
|
4262
|
+
* Concurrent invocations are serialized via `syncLoopMutex`.
|
|
4229
4263
|
*/
|
|
4230
4264
|
syncStorage(): Promise<void>;
|
|
4231
4265
|
/**
|
|
4232
4266
|
* Stops the attachment synchronization process.
|
|
4233
4267
|
*
|
|
4234
|
-
* Clears the periodic sync timer
|
|
4268
|
+
* Clears the periodic sync timer, closes all active attachment watchers, and
|
|
4269
|
+
* aborts any in-flight `syncStorage()` call so it exits within one
|
|
4270
|
+
* attachment's processing time instead of running the batch to completion.
|
|
4235
4271
|
*/
|
|
4236
4272
|
stopSync(): Promise<void>;
|
|
4237
4273
|
/**
|
|
@@ -4332,13 +4368,23 @@ declare class SyncingService {
|
|
|
4332
4368
|
constructor(attachmentService: AttachmentService, localStorage: LocalStorageAdapter, remoteStorage: RemoteStorageAdapter, logger: ILogger, errorHandler?: AttachmentErrorHandler);
|
|
4333
4369
|
/**
|
|
4334
4370
|
* Processes attachments based on their state (upload, download, or delete).
|
|
4335
|
-
*
|
|
4371
|
+
*
|
|
4372
|
+
* Each attachment's I/O runs outside the attachment-service mutex, and the row's
|
|
4373
|
+
* state transition is persisted immediately after it completes. This keeps the
|
|
4374
|
+
* mutex available to concurrent `saveFile` / `deleteFile` / watched-attachment
|
|
4375
|
+
* processing while a batch is in flight, and means consumer queries against the
|
|
4376
|
+
* attachments queue see incremental progress instead of one atomic commit at the
|
|
4377
|
+
* end of the batch.
|
|
4336
4378
|
*
|
|
4337
4379
|
* @param attachments - Array of attachment records to process
|
|
4338
|
-
* @param
|
|
4339
|
-
*
|
|
4380
|
+
* @param options - Optional controls. Pass `signal` (an `AbortSignal`) to interrupt
|
|
4381
|
+
* the batch: it is checked between attachments and, once aborted, the
|
|
4382
|
+
* loop exits early — letting `stopSync` stop a running batch within
|
|
4383
|
+
* one attachment's processing time.
|
|
4340
4384
|
*/
|
|
4341
|
-
processAttachments(attachments: AttachmentRecord[],
|
|
4385
|
+
processAttachments(attachments: AttachmentRecord[], options?: {
|
|
4386
|
+
signal?: AbortSignal;
|
|
4387
|
+
}): Promise<void>;
|
|
4342
4388
|
/**
|
|
4343
4389
|
* Uploads an attachment from local storage to remote storage.
|
|
4344
4390
|
* On success, marks as SYNCED. On failure, defers to error handler or archives.
|
|
@@ -4601,5 +4647,5 @@ interface ParsedQuery {
|
|
|
4601
4647
|
*/
|
|
4602
4648
|
declare const parseQuery: <T>(query: string | CompilableQuery<T>, parameters: any[]) => ParsedQuery;
|
|
4603
4649
|
|
|
4604
|
-
export { ATTACHMENT_TABLE, AbortOperation, AbstractPowerSyncDatabase, AbstractPowerSyncDatabaseOpenFactory, AbstractQueryProcessor, AbstractRemote, AbstractStreamingSyncImplementation, ArrayComparator, AttachmentContext, AttachmentQueue, AttachmentService, AttachmentState, AttachmentTable, BaseObserver, Column, ColumnType, ConnectionClosedError, ConnectionManager, ControlledExecutor, CrudBatch, CrudEntry, CrudTransaction, DBAdapterDefaultMixin, DBGetUtilsDefaultMixin, DEFAULT_CRUD_BATCH_LIMIT, DEFAULT_CRUD_UPLOAD_THROTTLE_MS, DEFAULT_INDEX_COLUMN_OPTIONS, DEFAULT_INDEX_OPTIONS, DEFAULT_LOCK_TIMEOUT_MS, DEFAULT_POWERSYNC_CLOSE_OPTIONS, DEFAULT_POWERSYNC_DB_OPTIONS, DEFAULT_REMOTE_LOGGER, DEFAULT_REMOTE_OPTIONS, DEFAULT_RETRY_DELAY_MS, DEFAULT_ROW_COMPARATOR, DEFAULT_STREAMING_SYNC_OPTIONS, DEFAULT_STREAM_CONNECTION_OPTIONS, DEFAULT_SYNC_CLIENT_IMPLEMENTATION, DEFAULT_TABLE_OPTIONS, DEFAULT_WATCH_QUERY_OPTIONS, DEFAULT_WATCH_THROTTLE_MS, DiffTriggerOperation, DifferentialQueryProcessor, EMPTY_DIFFERENTIAL, EncodingType, FalsyComparator, FetchImplementationProvider, FetchStrategy, GetAllQuery, Index, IndexedColumn, InvalidSQLCharacters, LockType, LogLevel, MAX_AMOUNT_OF_COLUMNS, MAX_OP_ID, MEMORY_TRIGGER_CLAIM_MANAGER, Mutex, OnChangeQueryProcessor, PSInternalTable, PowerSyncControlCommand, RowUpdateType, Schema, Semaphore, SqliteBucketStorage, SyncClientImplementation, SyncProgress, SyncStatus, SyncStreamConnectionMethod, SyncingService, Table, TableV2, TriggerManagerImpl, UpdateType, UploadQueueStats, WatchedQueryListenerEvent, attachmentFromSql, column, compilableQueryWatch, createBaseLogger, createLogger, extractTableUpdates, isBatchedUpdateNotification, isDBAdapter, isPowerSyncDatabaseOptionsWithSettings, isSQLOpenFactory, isSQLOpenOptions, parseQuery, runOnSchemaChange, sanitizeSQL, sanitizeUUID, timeoutSignal };
|
|
4605
|
-
export type { AbstractQueryProcessorOptions, AbstractRemoteOptions, AbstractStreamingSyncImplementationOptions, AdditionalConnectionOptions, ArrayComparatorOptions, ArrayQueryDefinition, AttachmentData, AttachmentErrorHandler, AttachmentQueueOptions, AttachmentRecord, AttachmentTableOptions, BaseColumnType, BaseConnectionOptions, BaseListener, BaseObserverInterface, BasePowerSyncDatabaseOptions, BaseTriggerDiffRecord, BatchedUpdateNotification, BucketStorageAdapter, BucketStorageListener, ColumnOptions, ColumnsType, CompilableQuery, CompilableQueryWatchHandler, CompiledQuery, ConnectionManagerListener, ConnectionManagerOptions, ConnectionManagerSyncImplementationResult, ConnectionPool, ControlledExecutorOptions, CreateDiffTriggerOptions, CreateLoggerOptions, CreateSyncImplementationOptions, DBAdapter, DBAdapterListener, DBGetUtils, DBLockOptions, DifferentialQueryProcessorOptions, DifferentialWatchedQuery, DifferentialWatchedQueryComparator, DifferentialWatchedQueryListener, DifferentialWatchedQueryOptions, DifferentialWatchedQuerySettings, DisconnectAndClearOptions, Disposable, ExtractColumnValueType, ExtractedTriggerDiffRecord, FetchImplementation, GetAllQueryOptions, IndexColumnOptions, IndexOptions, IndexShorthand, InternalConnectionOptions, InternalSubscriptionAdapter, LinkQueryOptions, LocalStorageAdapter, LockContext, LockOptions, MutableWatchedQueryState, OnChangeQueryProcessorOptions, OpId, ParsedQuery, PendingStatement, PendingStatementParameter, PowerSyncBackendConnector, PowerSyncCloseOptions, PowerSyncConnectionOptions, PowerSyncCredentials, PowerSyncDBListener, PowerSyncDatabaseOptions, PowerSyncDatabaseOptionsWithDBAdapter, PowerSyncDatabaseOptionsWithOpenFactory, PowerSyncDatabaseOptionsWithSettings, PowerSyncOpenFactoryOptions, ProgressWithOperations, Query, QueryParam, QueryResult, RawTableType, RemoteConnector, RemoteStorageAdapter, RequiredAdditionalConnectionOptions, RequiredPowerSyncConnectionOptions, RowType, SQLOnChangeOptions, SQLOpenFactory, SQLOpenOptions, SQLWatchOptions, SchemaTableType, SimpleAsyncIterator, SocketSyncStreamOptions, SqlExecutor, StandardWatchedQuery, StandardWatchedQueryOptions, StreamingSyncImplementation, StreamingSyncImplementationListener, StreamingSyncRequestParameterType, SubscribedStream, SyncDataFlowStatus, SyncPriorityStatus, SyncStatusOptions, SyncStream, SyncStreamDescription, SyncStreamOptions, SyncStreamStatus, SyncStreamSubscribeOptions, SyncStreamSubscription, SyncSubscriptionDescription, TableOptions, TableOrRawTableOptions, TableUpdateOperation, TableV2Options, TrackDiffOptions, TrackPreviousOptions, Transaction, TriggerClaimManager, TriggerCreationHooks, TriggerDiffDeleteRecord, TriggerDiffHandlerContext, TriggerDiffInsertRecord, TriggerDiffRecord, TriggerDiffUpdateRecord, TriggerManager, TriggerManagerConfig, TriggerRemoveCallback, TriggerRemoveCallbackOptions, UnlockFn, UpdateNotification, WatchCompatibleQuery, WatchExecuteOptions, WatchHandler, WatchOnChangeEvent, WatchOnChangeHandler, WatchedAttachmentItem, WatchedQuery, WatchedQueryComparator, WatchedQueryDifferential, WatchedQueryListener, WatchedQueryOptions, WatchedQueryRowDifferential, WatchedQuerySettings, WatchedQueryState, WithDiffOptions };
|
|
4650
|
+
export { ATTACHMENT_TABLE, ATTACHMENT_TABLE_COLUMNS, AbortOperation, AbstractPowerSyncDatabase, AbstractPowerSyncDatabaseOpenFactory, AbstractQueryProcessor, AbstractRemote, AbstractStreamingSyncImplementation, ArrayComparator, AttachmentContext, AttachmentQueue, AttachmentService, AttachmentState, AttachmentTable, BaseObserver, Column, ColumnType, ConnectionClosedError, ConnectionManager, ControlledExecutor, CrudBatch, CrudEntry, CrudTransaction, DBAdapterDefaultMixin, DBGetUtilsDefaultMixin, DEFAULT_CRUD_BATCH_LIMIT, DEFAULT_CRUD_UPLOAD_THROTTLE_MS, DEFAULT_INDEX_COLUMN_OPTIONS, DEFAULT_INDEX_OPTIONS, DEFAULT_LOCK_TIMEOUT_MS, DEFAULT_POWERSYNC_CLOSE_OPTIONS, DEFAULT_POWERSYNC_DB_OPTIONS, DEFAULT_REMOTE_LOGGER, DEFAULT_REMOTE_OPTIONS, DEFAULT_RETRY_DELAY_MS, DEFAULT_ROW_COMPARATOR, DEFAULT_STREAMING_SYNC_OPTIONS, DEFAULT_STREAM_CONNECTION_OPTIONS, DEFAULT_SYNC_CLIENT_IMPLEMENTATION, DEFAULT_TABLE_OPTIONS, DEFAULT_WATCH_QUERY_OPTIONS, DEFAULT_WATCH_THROTTLE_MS, DiffTriggerOperation, DifferentialQueryProcessor, EMPTY_DIFFERENTIAL, EncodingType, FalsyComparator, FetchImplementationProvider, FetchStrategy, GetAllQuery, Index, IndexedColumn, InvalidSQLCharacters, LockType, LogLevel, MAX_AMOUNT_OF_COLUMNS, MAX_OP_ID, MEMORY_TRIGGER_CLAIM_MANAGER, Mutex, OnChangeQueryProcessor, PSInternalTable, PowerSyncControlCommand, RowUpdateType, Schema, Semaphore, SqliteBucketStorage, SyncClientImplementation, SyncProgress, SyncStatus, SyncStreamConnectionMethod, SyncingService, Table, TableV2, TriggerManagerImpl, UpdateType, UploadQueueStats, WatchedQueryListenerEvent, attachmentFromSql, column, compilableQueryWatch, createBaseLogger, createLogger, extractTableUpdates, isBatchedUpdateNotification, isDBAdapter, isPowerSyncDatabaseOptionsWithSettings, isSQLOpenFactory, isSQLOpenOptions, parseQuery, runOnSchemaChange, sanitizeSQL, sanitizeUUID, timeoutSignal };
|
|
4651
|
+
export type { AbstractQueryProcessorOptions, AbstractRemoteOptions, AbstractStreamingSyncImplementationOptions, AdditionalConnectionOptions, ArrayComparatorOptions, ArrayQueryDefinition, AttachmentData, AttachmentErrorHandler, AttachmentQueueOptions, AttachmentRecord, AttachmentTableOptions, AttachmentTableRecord, BaseColumnType, BaseConnectionOptions, BaseListener, BaseObserverInterface, BasePowerSyncDatabaseOptions, BaseTriggerDiffRecord, BatchedUpdateNotification, BucketStorageAdapter, BucketStorageListener, ColumnOptions, ColumnsType, CompilableQuery, CompilableQueryWatchHandler, CompiledQuery, ConnectionManagerListener, ConnectionManagerOptions, ConnectionManagerSyncImplementationResult, ConnectionPool, ControlledExecutorOptions, CreateDiffTriggerOptions, CreateLoggerOptions, CreateSyncImplementationOptions, DBAdapter, DBAdapterListener, DBGetUtils, DBLockOptions, DifferentialQueryProcessorOptions, DifferentialWatchedQuery, DifferentialWatchedQueryComparator, DifferentialWatchedQueryListener, DifferentialWatchedQueryOptions, DifferentialWatchedQuerySettings, DisconnectAndClearOptions, Disposable, ExtractColumnValueType, ExtractedTriggerDiffRecord, FetchImplementation, GetAllQueryOptions, IndexColumnOptions, IndexOptions, IndexShorthand, InternalConnectionOptions, InternalSubscriptionAdapter, LinkQueryOptions, LocalStorageAdapter, LockContext, LockOptions, MutableWatchedQueryState, OnChangeQueryProcessorOptions, OpId, ParsedQuery, PendingStatement, PendingStatementParameter, PowerSyncBackendConnector, PowerSyncCloseOptions, PowerSyncConnectionOptions, PowerSyncCredentials, PowerSyncDBListener, PowerSyncDatabaseOptions, PowerSyncDatabaseOptionsWithDBAdapter, PowerSyncDatabaseOptionsWithOpenFactory, PowerSyncDatabaseOptionsWithSettings, PowerSyncOpenFactoryOptions, ProgressWithOperations, Query, QueryParam, QueryResult, RawTableType, RemoteConnector, RemoteStorageAdapter, RequiredAdditionalConnectionOptions, RequiredPowerSyncConnectionOptions, RowType, SQLOnChangeOptions, SQLOpenFactory, SQLOpenOptions, SQLWatchOptions, SchemaTableType, SimpleAsyncIterator, SocketSyncStreamOptions, SqlExecutor, StandardWatchedQuery, StandardWatchedQueryOptions, StreamingSyncImplementation, StreamingSyncImplementationListener, StreamingSyncRequestParameterType, SubscribedStream, SyncDataFlowStatus, SyncPriorityStatus, SyncStatusOptions, SyncStream, SyncStreamDescription, SyncStreamOptions, SyncStreamStatus, SyncStreamSubscribeOptions, SyncStreamSubscription, SyncSubscriptionDescription, TableOptions, TableOrRawTableOptions, TableUpdateOperation, TableV2Options, TrackDiffOptions, TrackPreviousOptions, Transaction, TriggerClaimManager, TriggerCreationHooks, TriggerDiffDeleteRecord, TriggerDiffHandlerContext, TriggerDiffInsertRecord, TriggerDiffRecord, TriggerDiffUpdateRecord, TriggerManager, TriggerManagerConfig, TriggerRemoveCallback, TriggerRemoveCallbackOptions, UnlockFn, UpdateNotification, WatchCompatibleQuery, WatchExecuteOptions, WatchHandler, WatchOnChangeEvent, WatchOnChangeHandler, WatchedAttachmentItem, WatchedQuery, WatchedQueryComparator, WatchedQueryDifferential, WatchedQueryListener, WatchedQueryOptions, WatchedQueryRowDifferential, WatchedQuerySettings, WatchedQueryState, WithDiffOptions };
|
|
@@ -109,6 +109,19 @@ export declare class AttachmentQueue {
|
|
|
109
109
|
private statusListenerDispose?;
|
|
110
110
|
private watchActiveAttachments;
|
|
111
111
|
private watchAttachmentsAbortController;
|
|
112
|
+
/**
|
|
113
|
+
* Serializes concurrent `syncStorage()` triggers (periodic timer, watch-onDiff,
|
|
114
|
+
* status-changed). Held across the whole batch, but only contended by other
|
|
115
|
+
* sync triggers — foreground `saveFile` / `deleteFile` / watched-attachment
|
|
116
|
+
* processing don't take this lock and proceed in parallel via the
|
|
117
|
+
* `AttachmentService` mutex, which is acquired only briefly per row.
|
|
118
|
+
*/
|
|
119
|
+
private syncLoopMutex;
|
|
120
|
+
/**
|
|
121
|
+
* Aborted by `stopSync()` to interrupt an in-flight batch within one
|
|
122
|
+
* attachment's processing time. Polled between rows by `SyncingService`.
|
|
123
|
+
*/
|
|
124
|
+
private syncAbortController?;
|
|
112
125
|
/**
|
|
113
126
|
* Creates a new AttachmentQueue instance.
|
|
114
127
|
*
|
|
@@ -137,12 +150,16 @@ export declare class AttachmentQueue {
|
|
|
137
150
|
*
|
|
138
151
|
* This is called automatically at regular intervals when sync is started,
|
|
139
152
|
* but can also be called manually to trigger an immediate sync.
|
|
153
|
+
*
|
|
154
|
+
* Concurrent invocations are serialized via `syncLoopMutex`.
|
|
140
155
|
*/
|
|
141
156
|
syncStorage(): Promise<void>;
|
|
142
157
|
/**
|
|
143
158
|
* Stops the attachment synchronization process.
|
|
144
159
|
*
|
|
145
|
-
* Clears the periodic sync timer
|
|
160
|
+
* Clears the periodic sync timer, closes all active attachment watchers, and
|
|
161
|
+
* aborts any in-flight `syncStorage()` call so it exits within one
|
|
162
|
+
* attachment's processing time instead of running the batch to completion.
|
|
146
163
|
*/
|
|
147
164
|
stopSync(): Promise<void>;
|
|
148
165
|
/**
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { DEFAULT_WATCH_THROTTLE_MS } from '../client/watched/WatchedQuery.js';
|
|
2
|
+
import { Mutex } from '../utils/mutex.js';
|
|
2
3
|
import { AttachmentService } from './AttachmentService.js';
|
|
3
4
|
import { ATTACHMENT_TABLE, AttachmentState } from './Schema.js';
|
|
4
5
|
import { SyncingService } from './SyncingService.js';
|
|
@@ -54,6 +55,19 @@ export class AttachmentQueue {
|
|
|
54
55
|
statusListenerDispose;
|
|
55
56
|
watchActiveAttachments;
|
|
56
57
|
watchAttachmentsAbortController;
|
|
58
|
+
/**
|
|
59
|
+
* Serializes concurrent `syncStorage()` triggers (periodic timer, watch-onDiff,
|
|
60
|
+
* status-changed). Held across the whole batch, but only contended by other
|
|
61
|
+
* sync triggers — foreground `saveFile` / `deleteFile` / watched-attachment
|
|
62
|
+
* processing don't take this lock and proceed in parallel via the
|
|
63
|
+
* `AttachmentService` mutex, which is acquired only briefly per row.
|
|
64
|
+
*/
|
|
65
|
+
syncLoopMutex = new Mutex();
|
|
66
|
+
/**
|
|
67
|
+
* Aborted by `stopSync()` to interrupt an in-flight batch within one
|
|
68
|
+
* attachment's processing time. Polled between rows by `SyncingService`.
|
|
69
|
+
*/
|
|
70
|
+
syncAbortController;
|
|
57
71
|
/**
|
|
58
72
|
* Creates a new AttachmentQueue instance.
|
|
59
73
|
*
|
|
@@ -93,6 +107,7 @@ export class AttachmentQueue {
|
|
|
93
107
|
*/
|
|
94
108
|
async startSync() {
|
|
95
109
|
await this.stopSync();
|
|
110
|
+
this.syncAbortController = new AbortController();
|
|
96
111
|
this.watchActiveAttachments = this.attachmentService.watchActiveAttachments({
|
|
97
112
|
throttleMs: this.syncThrottleDuration
|
|
98
113
|
});
|
|
@@ -207,23 +222,44 @@ export class AttachmentQueue {
|
|
|
207
222
|
*
|
|
208
223
|
* This is called automatically at regular intervals when sync is started,
|
|
209
224
|
* but can also be called manually to trigger an immediate sync.
|
|
225
|
+
*
|
|
226
|
+
* Concurrent invocations are serialized via `syncLoopMutex`.
|
|
210
227
|
*/
|
|
211
228
|
async syncStorage() {
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
await this.
|
|
217
|
-
|
|
229
|
+
const signal = this.syncAbortController?.signal;
|
|
230
|
+
if (signal?.aborted)
|
|
231
|
+
return;
|
|
232
|
+
try {
|
|
233
|
+
await this.syncLoopMutex.runExclusive(async () => {
|
|
234
|
+
const activeAttachments = await this.attachmentService.withContext((ctx) => ctx.getActiveAttachments());
|
|
235
|
+
await this.localStorage.initialize();
|
|
236
|
+
await this.syncingService.processAttachments(activeAttachments, { signal });
|
|
237
|
+
if (signal?.aborted)
|
|
238
|
+
return;
|
|
239
|
+
await this.attachmentService.withContext((ctx) => this.syncingService.deleteArchivedAttachments(ctx));
|
|
240
|
+
}, signal);
|
|
241
|
+
}
|
|
242
|
+
catch (error) {
|
|
243
|
+
// A queued batch's acquire rejects when `stopSync` aborts — expected, not an error.
|
|
244
|
+
if (signal?.aborted)
|
|
245
|
+
return;
|
|
246
|
+
throw error;
|
|
247
|
+
}
|
|
218
248
|
}
|
|
219
249
|
/**
|
|
220
250
|
* Stops the attachment synchronization process.
|
|
221
251
|
*
|
|
222
|
-
* Clears the periodic sync timer
|
|
252
|
+
* Clears the periodic sync timer, closes all active attachment watchers, and
|
|
253
|
+
* aborts any in-flight `syncStorage()` call so it exits within one
|
|
254
|
+
* attachment's processing time instead of running the batch to completion.
|
|
223
255
|
*/
|
|
224
256
|
async stopSync() {
|
|
225
257
|
clearInterval(this.periodicSyncTimer);
|
|
226
258
|
this.periodicSyncTimer = undefined;
|
|
259
|
+
if (this.syncAbortController) {
|
|
260
|
+
this.syncAbortController.abort();
|
|
261
|
+
this.syncAbortController = undefined;
|
|
262
|
+
}
|
|
227
263
|
if (this.watchActiveAttachments)
|
|
228
264
|
await this.watchActiveAttachments.close();
|
|
229
265
|
if (this.watchAttachmentsAbortController) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AttachmentQueue.js","sourceRoot":"","sources":["../../src/attachments/AttachmentQueue.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,yBAAyB,EAAE,MAAM,mCAAmC,CAAC;
|
|
1
|
+
{"version":3,"file":"AttachmentQueue.js","sourceRoot":"","sources":["../../src/attachments/AttachmentQueue.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Table } from '../db/schema/Table.js';
|
|
1
|
+
import { RowType, Table } from '../db/schema/Table.js';
|
|
2
2
|
import { TableV2Options } from '../db/schema/Table.js';
|
|
3
3
|
/**
|
|
4
4
|
* The default name of the local table storing attachment data.
|
|
@@ -48,11 +48,30 @@ export declare enum AttachmentState {
|
|
|
48
48
|
*/
|
|
49
49
|
export interface AttachmentTableOptions extends Omit<TableV2Options, 'name' | 'columns'> {
|
|
50
50
|
}
|
|
51
|
+
/**
|
|
52
|
+
* @alpha
|
|
53
|
+
*/
|
|
54
|
+
export declare const ATTACHMENT_TABLE_COLUMNS: {
|
|
55
|
+
filename: import("../db/schema/Column.js").BaseColumnType<string | null>;
|
|
56
|
+
local_uri: import("../db/schema/Column.js").BaseColumnType<string | null>;
|
|
57
|
+
timestamp: import("../db/schema/Column.js").BaseColumnType<number | null>;
|
|
58
|
+
size: import("../db/schema/Column.js").BaseColumnType<number | null>;
|
|
59
|
+
media_type: import("../db/schema/Column.js").BaseColumnType<string | null>;
|
|
60
|
+
state: import("../db/schema/Column.js").BaseColumnType<number | null>;
|
|
61
|
+
has_synced: import("../db/schema/Column.js").BaseColumnType<number | null>;
|
|
62
|
+
meta_data: import("../db/schema/Column.js").BaseColumnType<string | null>;
|
|
63
|
+
};
|
|
51
64
|
/**
|
|
52
65
|
* AttachmentTable defines the schema for the attachment queue table.
|
|
53
66
|
*
|
|
54
67
|
* @alpha
|
|
55
68
|
*/
|
|
56
|
-
export declare class AttachmentTable extends Table {
|
|
69
|
+
export declare class AttachmentTable extends Table<typeof ATTACHMENT_TABLE_COLUMNS> {
|
|
57
70
|
constructor(options?: AttachmentTableOptions);
|
|
58
71
|
}
|
|
72
|
+
/**
|
|
73
|
+
* AttachmentTableRecord represents the row type of the attachment table.
|
|
74
|
+
*
|
|
75
|
+
* @alpha
|
|
76
|
+
*/
|
|
77
|
+
export type AttachmentTableRecord = RowType<AttachmentTable>;
|
|
@@ -40,6 +40,19 @@ export var AttachmentState;
|
|
|
40
40
|
AttachmentState[AttachmentState["SYNCED"] = 3] = "SYNCED";
|
|
41
41
|
AttachmentState[AttachmentState["ARCHIVED"] = 4] = "ARCHIVED"; // Attachment has been orphaned, i.e. the associated record has been deleted
|
|
42
42
|
})(AttachmentState || (AttachmentState = {}));
|
|
43
|
+
/**
|
|
44
|
+
* @alpha
|
|
45
|
+
*/
|
|
46
|
+
export const ATTACHMENT_TABLE_COLUMNS = {
|
|
47
|
+
filename: column.text,
|
|
48
|
+
local_uri: column.text,
|
|
49
|
+
timestamp: column.integer,
|
|
50
|
+
size: column.integer,
|
|
51
|
+
media_type: column.text,
|
|
52
|
+
state: column.integer, // Corresponds to AttachmentState
|
|
53
|
+
has_synced: column.integer,
|
|
54
|
+
meta_data: column.text
|
|
55
|
+
};
|
|
43
56
|
/**
|
|
44
57
|
* AttachmentTable defines the schema for the attachment queue table.
|
|
45
58
|
*
|
|
@@ -47,16 +60,7 @@ export var AttachmentState;
|
|
|
47
60
|
*/
|
|
48
61
|
export class AttachmentTable extends Table {
|
|
49
62
|
constructor(options) {
|
|
50
|
-
super({
|
|
51
|
-
filename: column.text,
|
|
52
|
-
local_uri: column.text,
|
|
53
|
-
timestamp: column.integer,
|
|
54
|
-
size: column.integer,
|
|
55
|
-
media_type: column.text,
|
|
56
|
-
state: column.integer, // Corresponds to AttachmentState
|
|
57
|
-
has_synced: column.integer,
|
|
58
|
-
meta_data: column.text
|
|
59
|
-
}, {
|
|
63
|
+
super(ATTACHMENT_TABLE_COLUMNS, {
|
|
60
64
|
...options,
|
|
61
65
|
viewName: options?.viewName ?? ATTACHMENT_TABLE,
|
|
62
66
|
localOnly: true,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Schema.js","sourceRoot":"","sources":["../../src/attachments/Schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAChD,OAAO,
|
|
1
|
+
{"version":3,"file":"Schema.js","sourceRoot":"","sources":["../../src/attachments/Schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAChD,OAAO,EAAW,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAGvD;;;;GAIG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,aAAa,CAAC;AAmB9C;;;;;;;GAOG;AACH,MAAM,UAAU,iBAAiB,CAAC,GAAQ;IACxC,OAAO;QACL,EAAE,EAAE,GAAG,CAAC,EAAE;QACV,QAAQ,EAAE,GAAG,CAAC,QAAQ;QACtB,QAAQ,EAAE,GAAG,CAAC,SAAS;QACvB,IAAI,EAAE,GAAG,CAAC,IAAI;QACd,SAAS,EAAE,GAAG,CAAC,UAAU;QACzB,SAAS,EAAE,GAAG,CAAC,SAAS;QACxB,QAAQ,EAAE,GAAG,CAAC,SAAS;QACvB,SAAS,EAAE,GAAG,CAAC,UAAU,KAAK,CAAC;QAC/B,KAAK,EAAE,GAAG,CAAC,KAAK;KACjB,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAN,IAAY,eAMX;AAND,WAAY,eAAe;IACzB,uEAAiB,CAAA;IACjB,2EAAmB,CAAA;IACnB,uEAAiB,CAAA;IACjB,yDAAU,CAAA;IACV,6DAAY,CAAA,CAAC,4EAA4E;AAC3F,CAAC,EANW,eAAe,KAAf,eAAe,QAM1B;AAOD;;GAEG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG;IACtC,QAAQ,EAAE,MAAM,CAAC,IAAI;IACrB,SAAS,EAAE,MAAM,CAAC,IAAI;IACtB,SAAS,EAAE,MAAM,CAAC,OAAO;IACzB,IAAI,EAAE,MAAM,CAAC,OAAO;IACpB,UAAU,EAAE,MAAM,CAAC,IAAI;IACvB,KAAK,EAAE,MAAM,CAAC,OAAO,EAAE,iCAAiC;IACxD,UAAU,EAAE,MAAM,CAAC,OAAO;IAC1B,SAAS,EAAE,MAAM,CAAC,IAAI;CACvB,CAAC;AAEF;;;;GAIG;AACH,MAAM,OAAO,eAAgB,SAAQ,KAAsC;IACzE,YAAY,OAAgC;QAC1C,KAAK,CAAC,wBAAwB,EAAE;YAC9B,GAAG,OAAO;YACV,QAAQ,EAAE,OAAO,EAAE,QAAQ,IAAI,gBAAgB;YAC/C,SAAS,EAAE,IAAI;YACf,UAAU,EAAE,KAAK;SAClB,CAAC,CAAC;IACL,CAAC;CACF"}
|
|
@@ -20,13 +20,23 @@ export declare class SyncingService {
|
|
|
20
20
|
constructor(attachmentService: AttachmentService, localStorage: LocalStorageAdapter, remoteStorage: RemoteStorageAdapter, logger: ILogger, errorHandler?: AttachmentErrorHandler);
|
|
21
21
|
/**
|
|
22
22
|
* Processes attachments based on their state (upload, download, or delete).
|
|
23
|
-
*
|
|
23
|
+
*
|
|
24
|
+
* Each attachment's I/O runs outside the attachment-service mutex, and the row's
|
|
25
|
+
* state transition is persisted immediately after it completes. This keeps the
|
|
26
|
+
* mutex available to concurrent `saveFile` / `deleteFile` / watched-attachment
|
|
27
|
+
* processing while a batch is in flight, and means consumer queries against the
|
|
28
|
+
* attachments queue see incremental progress instead of one atomic commit at the
|
|
29
|
+
* end of the batch.
|
|
24
30
|
*
|
|
25
31
|
* @param attachments - Array of attachment records to process
|
|
26
|
-
* @param
|
|
27
|
-
*
|
|
32
|
+
* @param options - Optional controls. Pass `signal` (an `AbortSignal`) to interrupt
|
|
33
|
+
* the batch: it is checked between attachments and, once aborted, the
|
|
34
|
+
* loop exits early — letting `stopSync` stop a running batch within
|
|
35
|
+
* one attachment's processing time.
|
|
28
36
|
*/
|
|
29
|
-
processAttachments(attachments: AttachmentRecord[],
|
|
37
|
+
processAttachments(attachments: AttachmentRecord[], options?: {
|
|
38
|
+
signal?: AbortSignal;
|
|
39
|
+
}): Promise<void>;
|
|
30
40
|
/**
|
|
31
41
|
* Uploads an attachment from local storage to remote storage.
|
|
32
42
|
* On success, marks as SYNCED. On failure, defers to error handler or archives.
|
|
@@ -20,33 +20,51 @@ export class SyncingService {
|
|
|
20
20
|
}
|
|
21
21
|
/**
|
|
22
22
|
* Processes attachments based on their state (upload, download, or delete).
|
|
23
|
-
*
|
|
23
|
+
*
|
|
24
|
+
* Each attachment's I/O runs outside the attachment-service mutex, and the row's
|
|
25
|
+
* state transition is persisted immediately after it completes. This keeps the
|
|
26
|
+
* mutex available to concurrent `saveFile` / `deleteFile` / watched-attachment
|
|
27
|
+
* processing while a batch is in flight, and means consumer queries against the
|
|
28
|
+
* attachments queue see incremental progress instead of one atomic commit at the
|
|
29
|
+
* end of the batch.
|
|
24
30
|
*
|
|
25
31
|
* @param attachments - Array of attachment records to process
|
|
26
|
-
* @param
|
|
27
|
-
*
|
|
32
|
+
* @param options - Optional controls. Pass `signal` (an `AbortSignal`) to interrupt
|
|
33
|
+
* the batch: it is checked between attachments and, once aborted, the
|
|
34
|
+
* loop exits early — letting `stopSync` stop a running batch within
|
|
35
|
+
* one attachment's processing time.
|
|
28
36
|
*/
|
|
29
|
-
async processAttachments(attachments,
|
|
30
|
-
const
|
|
37
|
+
async processAttachments(attachments, options) {
|
|
38
|
+
const signal = options?.signal;
|
|
39
|
+
this.logger.info(`Starting processAttachments with ${attachments.length} attachments`);
|
|
31
40
|
for (const attachment of attachments) {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
41
|
+
if (signal?.aborted) {
|
|
42
|
+
this.logger.info('Sync cancelled; stopping iteration early');
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
try {
|
|
46
|
+
let updated;
|
|
47
|
+
switch (attachment.state) {
|
|
48
|
+
case AttachmentState.QUEUED_UPLOAD:
|
|
49
|
+
updated = await this.uploadAttachment(attachment);
|
|
50
|
+
break;
|
|
51
|
+
case AttachmentState.QUEUED_DOWNLOAD:
|
|
52
|
+
updated = await this.downloadAttachment(attachment);
|
|
53
|
+
break;
|
|
54
|
+
case AttachmentState.QUEUED_DELETE:
|
|
55
|
+
// `deleteAttachment` needs a context (it removes the row in a
|
|
56
|
+
// transaction); briefly re-acquire the mutex for just this row.
|
|
57
|
+
updated = await this.attachmentService.withContext((ctx) => this.deleteAttachment(attachment, ctx));
|
|
58
|
+
break;
|
|
59
|
+
default:
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
await this.attachmentService.withContext((ctx) => ctx.saveAttachments([updated]));
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
this.logger.warn(`Error during sync for ${attachment.id}`, error);
|
|
47
66
|
}
|
|
48
67
|
}
|
|
49
|
-
await context.saveAttachments(updatedAttachments);
|
|
50
68
|
}
|
|
51
69
|
/**
|
|
52
70
|
* Uploads an attachment from local storage to remote storage.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SyncingService.js","sourceRoot":"","sources":["../../src/attachments/SyncingService.ts"],"names":[],"mappings":"AAIA,OAAO,EAAoB,eAAe,EAAE,MAAM,aAAa,CAAC;AAIhE;;;;;GAKG;AACH,MAAM,OAAO,cAAc;IACjB,iBAAiB,CAAoB;IACrC,YAAY,CAAsB;IAClC,aAAa,CAAuB;IACpC,MAAM,CAAU;IAChB,YAAY,CAA0B;IAE9C,YACE,iBAAoC,EACpC,YAAiC,EACjC,aAAmC,EACnC,MAAe,EACf,YAAqC;QAErC,IAAI,CAAC,iBAAiB,GAAG,iBAAiB,CAAC;QAC3C,IAAI,CAAC,YAAY,GAAG,YAAY,CAAC;QACjC,IAAI,CAAC,aAAa,GAAG,aAAa,CAAC;QACnC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,YAAY,GAAG,YAAY,CAAC;IACnC,CAAC;IAED
|
|
1
|
+
{"version":3,"file":"SyncingService.js","sourceRoot":"","sources":["../../src/attachments/SyncingService.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { AbstractPowerSyncDatabase } from '../client/AbstractPowerSyncDatabase.js';
|
|
2
2
|
import { DEFAULT_WATCH_THROTTLE_MS } from '../client/watched/WatchedQuery.js';
|
|
3
3
|
import { DifferentialWatchedQuery } from '../client/watched/processors/DifferentialQueryProcessor.js';
|
|
4
|
+
import { Mutex } from '../utils/mutex.js';
|
|
4
5
|
import { Transaction } from '../db/DBAdapter.js';
|
|
5
6
|
import { ILogger } from '../utils/Logger.js';
|
|
6
7
|
import { AttachmentContext } from './AttachmentContext.js';
|
|
@@ -135,6 +136,21 @@ export class AttachmentQueue {
|
|
|
135
136
|
|
|
136
137
|
private watchAttachmentsAbortController!: AbortController;
|
|
137
138
|
|
|
139
|
+
/**
|
|
140
|
+
* Serializes concurrent `syncStorage()` triggers (periodic timer, watch-onDiff,
|
|
141
|
+
* status-changed). Held across the whole batch, but only contended by other
|
|
142
|
+
* sync triggers — foreground `saveFile` / `deleteFile` / watched-attachment
|
|
143
|
+
* processing don't take this lock and proceed in parallel via the
|
|
144
|
+
* `AttachmentService` mutex, which is acquired only briefly per row.
|
|
145
|
+
*/
|
|
146
|
+
private syncLoopMutex = new Mutex();
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Aborted by `stopSync()` to interrupt an in-flight batch within one
|
|
150
|
+
* attachment's processing time. Polled between rows by `SyncingService`.
|
|
151
|
+
*/
|
|
152
|
+
private syncAbortController?: AbortController;
|
|
153
|
+
|
|
138
154
|
/**
|
|
139
155
|
* Creates a new AttachmentQueue instance.
|
|
140
156
|
*
|
|
@@ -195,6 +211,8 @@ export class AttachmentQueue {
|
|
|
195
211
|
async startSync(): Promise<void> {
|
|
196
212
|
await this.stopSync();
|
|
197
213
|
|
|
214
|
+
this.syncAbortController = new AbortController();
|
|
215
|
+
|
|
198
216
|
this.watchActiveAttachments = this.attachmentService.watchActiveAttachments({
|
|
199
217
|
throttleMs: this.syncThrottleDuration
|
|
200
218
|
});
|
|
@@ -325,24 +343,45 @@ export class AttachmentQueue {
|
|
|
325
343
|
*
|
|
326
344
|
* This is called automatically at regular intervals when sync is started,
|
|
327
345
|
* but can also be called manually to trigger an immediate sync.
|
|
346
|
+
*
|
|
347
|
+
* Concurrent invocations are serialized via `syncLoopMutex`.
|
|
328
348
|
*/
|
|
329
349
|
async syncStorage(): Promise<void> {
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
await this.
|
|
335
|
-
|
|
350
|
+
const signal = this.syncAbortController?.signal;
|
|
351
|
+
if (signal?.aborted) return;
|
|
352
|
+
|
|
353
|
+
try {
|
|
354
|
+
await this.syncLoopMutex.runExclusive(async () => {
|
|
355
|
+
const activeAttachments = await this.attachmentService.withContext((ctx) => ctx.getActiveAttachments());
|
|
356
|
+
await this.localStorage.initialize();
|
|
357
|
+
|
|
358
|
+
await this.syncingService.processAttachments(activeAttachments, { signal });
|
|
359
|
+
|
|
360
|
+
if (signal?.aborted) return;
|
|
361
|
+
|
|
362
|
+
await this.attachmentService.withContext((ctx) => this.syncingService.deleteArchivedAttachments(ctx));
|
|
363
|
+
}, signal);
|
|
364
|
+
} catch (error) {
|
|
365
|
+
// A queued batch's acquire rejects when `stopSync` aborts — expected, not an error.
|
|
366
|
+
if (signal?.aborted) return;
|
|
367
|
+
throw error;
|
|
368
|
+
}
|
|
336
369
|
}
|
|
337
370
|
|
|
338
371
|
/**
|
|
339
372
|
* Stops the attachment synchronization process.
|
|
340
373
|
*
|
|
341
|
-
* Clears the periodic sync timer
|
|
374
|
+
* Clears the periodic sync timer, closes all active attachment watchers, and
|
|
375
|
+
* aborts any in-flight `syncStorage()` call so it exits within one
|
|
376
|
+
* attachment's processing time instead of running the batch to completion.
|
|
342
377
|
*/
|
|
343
378
|
async stopSync(): Promise<void> {
|
|
344
379
|
clearInterval(this.periodicSyncTimer);
|
|
345
380
|
this.periodicSyncTimer = undefined;
|
|
381
|
+
if (this.syncAbortController) {
|
|
382
|
+
this.syncAbortController.abort();
|
|
383
|
+
this.syncAbortController = undefined;
|
|
384
|
+
}
|
|
346
385
|
if (this.watchActiveAttachments) await this.watchActiveAttachments.close();
|
|
347
386
|
if (this.watchAttachmentsAbortController) {
|
|
348
387
|
this.watchAttachmentsAbortController.abort();
|