@powersync/common 1.46.0 → 1.47.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/README.md +5 -1
- package/dist/bundle.cjs +1266 -360
- package/dist/bundle.cjs.map +1 -1
- package/dist/bundle.mjs +1259 -361
- package/dist/bundle.mjs.map +1 -1
- package/dist/bundle.node.cjs +1266 -360
- package/dist/bundle.node.cjs.map +1 -1
- package/dist/bundle.node.mjs +1259 -361
- package/dist/bundle.node.mjs.map +1 -1
- package/dist/index.d.cts +530 -29
- package/lib/attachments/AttachmentContext.d.ts +86 -0
- package/lib/attachments/AttachmentContext.js +229 -0
- package/lib/attachments/AttachmentContext.js.map +1 -0
- package/lib/attachments/AttachmentErrorHandler.d.ts +31 -0
- package/lib/attachments/AttachmentErrorHandler.js +2 -0
- package/lib/attachments/AttachmentErrorHandler.js.map +1 -0
- package/lib/attachments/AttachmentQueue.d.ts +149 -0
- package/lib/attachments/AttachmentQueue.js +362 -0
- package/lib/attachments/AttachmentQueue.js.map +1 -0
- package/lib/attachments/AttachmentService.d.ts +29 -0
- package/lib/attachments/AttachmentService.js +56 -0
- package/lib/attachments/AttachmentService.js.map +1 -0
- package/lib/attachments/LocalStorageAdapter.d.ts +62 -0
- package/lib/attachments/LocalStorageAdapter.js +6 -0
- package/lib/attachments/LocalStorageAdapter.js.map +1 -0
- package/lib/attachments/RemoteStorageAdapter.d.ts +27 -0
- package/lib/attachments/RemoteStorageAdapter.js +2 -0
- package/lib/attachments/RemoteStorageAdapter.js.map +1 -0
- package/lib/attachments/Schema.d.ts +50 -0
- package/lib/attachments/Schema.js +62 -0
- package/lib/attachments/Schema.js.map +1 -0
- package/lib/attachments/SyncingService.d.ts +62 -0
- package/lib/attachments/SyncingService.js +168 -0
- package/lib/attachments/SyncingService.js.map +1 -0
- package/lib/attachments/WatchedAttachmentItem.d.ts +17 -0
- package/lib/attachments/WatchedAttachmentItem.js +2 -0
- package/lib/attachments/WatchedAttachmentItem.js.map +1 -0
- package/lib/index.d.ts +10 -0
- package/lib/index.js +10 -0
- package/lib/index.js.map +1 -1
- package/lib/utils/mutex.d.ts +1 -1
- package/lib/utils/mutex.js.map +1 -1
- package/package.json +1 -1
- package/src/attachments/AttachmentContext.ts +279 -0
- package/src/attachments/AttachmentErrorHandler.ts +34 -0
- package/src/attachments/AttachmentQueue.ts +472 -0
- package/src/attachments/AttachmentService.ts +62 -0
- package/src/attachments/LocalStorageAdapter.ts +72 -0
- package/src/attachments/README.md +718 -0
- package/src/attachments/RemoteStorageAdapter.ts +30 -0
- package/src/attachments/Schema.ts +87 -0
- package/src/attachments/SyncingService.ts +193 -0
- package/src/attachments/WatchedAttachmentItem.ts +19 -0
- package/src/index.ts +11 -0
- package/src/utils/mutex.ts +1 -1
|
@@ -0,0 +1,362 @@
|
|
|
1
|
+
import { DEFAULT_WATCH_THROTTLE_MS } from '../client/watched/WatchedQuery.js';
|
|
2
|
+
import { ATTACHMENT_TABLE, AttachmentState } from './Schema.js';
|
|
3
|
+
import { SyncingService } from './SyncingService.js';
|
|
4
|
+
import { AttachmentService } from './AttachmentService.js';
|
|
5
|
+
/**
|
|
6
|
+
* AttachmentQueue manages the lifecycle and synchronization of attachments
|
|
7
|
+
* between local and remote storage.
|
|
8
|
+
* Provides automatic synchronization, upload/download queuing, attachment monitoring,
|
|
9
|
+
* verification and repair of local files, and cleanup of archived attachments.
|
|
10
|
+
*
|
|
11
|
+
* @experimental
|
|
12
|
+
* @alpha This is currently experimental and may change without a major version bump.
|
|
13
|
+
*/
|
|
14
|
+
export class AttachmentQueue {
|
|
15
|
+
/** Timer for periodic synchronization operations */
|
|
16
|
+
periodicSyncTimer;
|
|
17
|
+
/** Service for synchronizing attachments between local and remote storage */
|
|
18
|
+
syncingService;
|
|
19
|
+
/** Adapter for local file storage operations */
|
|
20
|
+
localStorage;
|
|
21
|
+
/** Adapter for remote file storage operations */
|
|
22
|
+
remoteStorage;
|
|
23
|
+
/**
|
|
24
|
+
* Callback function to watch for changes in attachment references in your data model.
|
|
25
|
+
*
|
|
26
|
+
* This should be implemented by the user of AttachmentQueue to monitor changes in your application's
|
|
27
|
+
* data that reference attachments. When attachments are added, removed, or modified,
|
|
28
|
+
* this callback should trigger the onUpdate function with the current set of attachments.
|
|
29
|
+
*/
|
|
30
|
+
watchAttachments;
|
|
31
|
+
/** Name of the database table storing attachment records */
|
|
32
|
+
tableName;
|
|
33
|
+
/** Logger instance for diagnostic information */
|
|
34
|
+
logger;
|
|
35
|
+
/** Interval in milliseconds between periodic sync operations. Default: 30000 (30 seconds) */
|
|
36
|
+
syncIntervalMs = 30 * 1000;
|
|
37
|
+
/** Duration in milliseconds to throttle sync operations */
|
|
38
|
+
syncThrottleDuration;
|
|
39
|
+
/** Whether to automatically download remote attachments. Default: true */
|
|
40
|
+
downloadAttachments = true;
|
|
41
|
+
/** Maximum number of archived attachments to keep before cleanup. Default: 100 */
|
|
42
|
+
archivedCacheLimit;
|
|
43
|
+
/** Service for managing attachment-related database operations */
|
|
44
|
+
attachmentService;
|
|
45
|
+
/** PowerSync database instance */
|
|
46
|
+
db;
|
|
47
|
+
/** Cleanup function for status change listener */
|
|
48
|
+
statusListenerDispose;
|
|
49
|
+
watchActiveAttachments;
|
|
50
|
+
watchAttachmentsAbortController;
|
|
51
|
+
/**
|
|
52
|
+
* Creates a new AttachmentQueue instance.
|
|
53
|
+
*
|
|
54
|
+
* @param options - Configuration options
|
|
55
|
+
* @param options.db - PowerSync database instance
|
|
56
|
+
* @param options.remoteStorage - Remote storage adapter for upload/download operations
|
|
57
|
+
* @param options.localStorage - Local storage adapter for file persistence
|
|
58
|
+
* @param options.watchAttachments - Callback for monitoring attachment changes in your data model
|
|
59
|
+
* @param options.tableName - Name of the table to store attachment records. Default: 'ps_attachment_queue'
|
|
60
|
+
* @param options.logger - Logger instance. Defaults to db.logger
|
|
61
|
+
* @param options.syncIntervalMs - Interval between automatic syncs in milliseconds. Default: 30000
|
|
62
|
+
* @param options.syncThrottleDuration - Throttle duration for sync operations in milliseconds. Default: 1000
|
|
63
|
+
* @param options.downloadAttachments - Whether to automatically download remote attachments. Default: true
|
|
64
|
+
* @param options.archivedCacheLimit - Maximum archived attachments before cleanup. Default: 100
|
|
65
|
+
*/
|
|
66
|
+
constructor({ db, localStorage, remoteStorage, watchAttachments, logger, tableName = ATTACHMENT_TABLE, syncIntervalMs = 30 * 1000, syncThrottleDuration = DEFAULT_WATCH_THROTTLE_MS, downloadAttachments = true, archivedCacheLimit = 100, errorHandler }) {
|
|
67
|
+
this.db = db;
|
|
68
|
+
this.remoteStorage = remoteStorage;
|
|
69
|
+
this.localStorage = localStorage;
|
|
70
|
+
this.watchAttachments = watchAttachments;
|
|
71
|
+
this.tableName = tableName;
|
|
72
|
+
this.syncIntervalMs = syncIntervalMs;
|
|
73
|
+
this.syncThrottleDuration = syncThrottleDuration;
|
|
74
|
+
this.archivedCacheLimit = archivedCacheLimit;
|
|
75
|
+
this.downloadAttachments = downloadAttachments;
|
|
76
|
+
this.logger = logger ?? db.logger;
|
|
77
|
+
this.attachmentService = new AttachmentService(db, this.logger, tableName, archivedCacheLimit);
|
|
78
|
+
this.syncingService = new SyncingService(this.attachmentService, localStorage, remoteStorage, this.logger, errorHandler);
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Generates a new attachment ID using a SQLite UUID function.
|
|
82
|
+
*
|
|
83
|
+
* @returns Promise resolving to the new attachment ID
|
|
84
|
+
*/
|
|
85
|
+
async generateAttachmentId() {
|
|
86
|
+
return this.db.get('SELECT uuid() as id').then((row) => row.id);
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Starts the attachment synchronization process.
|
|
90
|
+
*
|
|
91
|
+
* This method:
|
|
92
|
+
* - Stops any existing sync operations
|
|
93
|
+
* - Sets up periodic synchronization based on syncIntervalMs
|
|
94
|
+
* - Registers listeners for active attachment changes
|
|
95
|
+
* - Processes watched attachments to queue uploads/downloads
|
|
96
|
+
* - Handles state transitions for archived and new attachments
|
|
97
|
+
*/
|
|
98
|
+
async startSync() {
|
|
99
|
+
await this.stopSync();
|
|
100
|
+
this.watchActiveAttachments = this.attachmentService.watchActiveAttachments({
|
|
101
|
+
throttleMs: this.syncThrottleDuration
|
|
102
|
+
});
|
|
103
|
+
// immediately invoke the sync storage to initialize local storage
|
|
104
|
+
await this.localStorage.initialize();
|
|
105
|
+
await this.verifyAttachments();
|
|
106
|
+
// Sync storage periodically
|
|
107
|
+
this.periodicSyncTimer = setInterval(async () => {
|
|
108
|
+
await this.syncStorage();
|
|
109
|
+
}, this.syncIntervalMs);
|
|
110
|
+
// Sync storage when there is a change in active attachments
|
|
111
|
+
this.watchActiveAttachments.registerListener({
|
|
112
|
+
onDiff: async () => {
|
|
113
|
+
await this.syncStorage();
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
this.statusListenerDispose = this.db.registerListener({
|
|
117
|
+
statusChanged: (status) => {
|
|
118
|
+
if (status.connected) {
|
|
119
|
+
// Device came online, process attachments immediately
|
|
120
|
+
this.syncStorage().catch((error) => {
|
|
121
|
+
this.logger.error('Error syncing storage on connection:', error);
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
this.watchAttachmentsAbortController = new AbortController();
|
|
127
|
+
const signal = this.watchAttachmentsAbortController.signal;
|
|
128
|
+
// Process attachments when there is a change in watched attachments
|
|
129
|
+
this.watchAttachments(async (watchedAttachments) => {
|
|
130
|
+
// Skip processing if sync has been stopped
|
|
131
|
+
if (signal.aborted) {
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
await this.attachmentService.withContext(async (ctx) => {
|
|
135
|
+
// Need to get all the attachments which are tracked in the DB.
|
|
136
|
+
// We might need to restore an archived attachment.
|
|
137
|
+
const currentAttachments = await ctx.getAttachments();
|
|
138
|
+
const attachmentUpdates = [];
|
|
139
|
+
for (const watchedAttachment of watchedAttachments) {
|
|
140
|
+
const existingQueueItem = currentAttachments.find((a) => a.id === watchedAttachment.id);
|
|
141
|
+
if (!existingQueueItem) {
|
|
142
|
+
// Item is watched but not in the queue yet. Need to add it.
|
|
143
|
+
if (!this.downloadAttachments) {
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
const filename = watchedAttachment.filename ?? `${watchedAttachment.id}.${watchedAttachment.fileExtension}`;
|
|
147
|
+
attachmentUpdates.push({
|
|
148
|
+
id: watchedAttachment.id,
|
|
149
|
+
filename,
|
|
150
|
+
state: AttachmentState.QUEUED_DOWNLOAD,
|
|
151
|
+
hasSynced: false,
|
|
152
|
+
metaData: watchedAttachment.metaData,
|
|
153
|
+
timestamp: new Date().getTime()
|
|
154
|
+
});
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
if (existingQueueItem.state === AttachmentState.ARCHIVED) {
|
|
158
|
+
// The attachment is present again. Need to queue it for sync.
|
|
159
|
+
// We might be able to optimize this in future
|
|
160
|
+
if (existingQueueItem.hasSynced === true) {
|
|
161
|
+
// No remote action required, we can restore the record (avoids deletion)
|
|
162
|
+
attachmentUpdates.push({
|
|
163
|
+
...existingQueueItem,
|
|
164
|
+
state: AttachmentState.SYNCED
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
else {
|
|
168
|
+
// The localURI should be set if the record was meant to be uploaded
|
|
169
|
+
// and hasSynced is false then
|
|
170
|
+
// it must be an upload operation
|
|
171
|
+
const newState = existingQueueItem.localUri == null ? AttachmentState.QUEUED_DOWNLOAD : AttachmentState.QUEUED_UPLOAD;
|
|
172
|
+
attachmentUpdates.push({
|
|
173
|
+
...existingQueueItem,
|
|
174
|
+
state: newState
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
for (const attachment of currentAttachments) {
|
|
180
|
+
const notInWatchedItems = watchedAttachments.find((i) => i.id === attachment.id) == null;
|
|
181
|
+
if (notInWatchedItems) {
|
|
182
|
+
switch (attachment.state) {
|
|
183
|
+
case AttachmentState.QUEUED_DELETE:
|
|
184
|
+
case AttachmentState.QUEUED_UPLOAD:
|
|
185
|
+
// Only archive if it has synced
|
|
186
|
+
if (attachment.hasSynced === true) {
|
|
187
|
+
attachmentUpdates.push({
|
|
188
|
+
...attachment,
|
|
189
|
+
state: AttachmentState.ARCHIVED
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
break;
|
|
193
|
+
default:
|
|
194
|
+
// Archive other states such as QUEUED_DOWNLOAD
|
|
195
|
+
attachmentUpdates.push({
|
|
196
|
+
...attachment,
|
|
197
|
+
state: AttachmentState.ARCHIVED
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
if (attachmentUpdates.length > 0) {
|
|
203
|
+
await ctx.saveAttachments(attachmentUpdates);
|
|
204
|
+
}
|
|
205
|
+
});
|
|
206
|
+
}, signal);
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Synchronizes all active attachments between local and remote storage.
|
|
210
|
+
*
|
|
211
|
+
* This is called automatically at regular intervals when sync is started,
|
|
212
|
+
* but can also be called manually to trigger an immediate sync.
|
|
213
|
+
*/
|
|
214
|
+
async syncStorage() {
|
|
215
|
+
await this.attachmentService.withContext(async (ctx) => {
|
|
216
|
+
const activeAttachments = await ctx.getActiveAttachments();
|
|
217
|
+
await this.localStorage.initialize();
|
|
218
|
+
await this.syncingService.processAttachments(activeAttachments, ctx);
|
|
219
|
+
await this.syncingService.deleteArchivedAttachments(ctx);
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Stops the attachment synchronization process.
|
|
224
|
+
*
|
|
225
|
+
* Clears the periodic sync timer and closes all active attachment watchers.
|
|
226
|
+
*/
|
|
227
|
+
async stopSync() {
|
|
228
|
+
clearInterval(this.periodicSyncTimer);
|
|
229
|
+
this.periodicSyncTimer = undefined;
|
|
230
|
+
if (this.watchActiveAttachments)
|
|
231
|
+
await this.watchActiveAttachments.close();
|
|
232
|
+
if (this.watchAttachmentsAbortController) {
|
|
233
|
+
this.watchAttachmentsAbortController.abort();
|
|
234
|
+
}
|
|
235
|
+
if (this.statusListenerDispose) {
|
|
236
|
+
this.statusListenerDispose();
|
|
237
|
+
this.statusListenerDispose = undefined;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Saves a file to local storage and queues it for upload to remote storage.
|
|
242
|
+
*
|
|
243
|
+
* @param options - File save options
|
|
244
|
+
* @param options.data - The file data as ArrayBuffer, Blob, or base64 string
|
|
245
|
+
* @param options.fileExtension - File extension (e.g., 'jpg', 'pdf')
|
|
246
|
+
* @param options.mediaType - MIME type of the file (e.g., 'image/jpeg')
|
|
247
|
+
* @param options.metaData - Optional metadata to associate with the attachment
|
|
248
|
+
* @param options.id - Optional custom ID. If not provided, a UUID will be generated
|
|
249
|
+
* @param options.updateHook - Optional callback to execute additional database operations
|
|
250
|
+
* within the same transaction as the attachment creation
|
|
251
|
+
* @returns Promise resolving to the created attachment record
|
|
252
|
+
*/
|
|
253
|
+
async saveFile({ data, fileExtension, mediaType, metaData, id, updateHook }) {
|
|
254
|
+
const resolvedId = id ?? (await this.generateAttachmentId());
|
|
255
|
+
const filename = `${resolvedId}.${fileExtension}`;
|
|
256
|
+
const localUri = this.localStorage.getLocalUri(filename);
|
|
257
|
+
const size = await this.localStorage.saveFile(localUri, data);
|
|
258
|
+
const attachment = {
|
|
259
|
+
id: resolvedId,
|
|
260
|
+
filename,
|
|
261
|
+
mediaType,
|
|
262
|
+
localUri,
|
|
263
|
+
state: AttachmentState.QUEUED_UPLOAD,
|
|
264
|
+
hasSynced: false,
|
|
265
|
+
size,
|
|
266
|
+
timestamp: new Date().getTime(),
|
|
267
|
+
metaData
|
|
268
|
+
};
|
|
269
|
+
await this.attachmentService.withContext(async (ctx) => {
|
|
270
|
+
await ctx.db.writeTransaction(async (tx) => {
|
|
271
|
+
await updateHook?.(tx, attachment);
|
|
272
|
+
await ctx.upsertAttachment(attachment, tx);
|
|
273
|
+
});
|
|
274
|
+
});
|
|
275
|
+
return attachment;
|
|
276
|
+
}
|
|
277
|
+
async deleteFile({ id, updateHook }) {
|
|
278
|
+
await this.attachmentService.withContext(async (ctx) => {
|
|
279
|
+
const attachment = await ctx.getAttachment(id);
|
|
280
|
+
if (!attachment) {
|
|
281
|
+
throw new Error(`Attachment with id ${id} not found`);
|
|
282
|
+
}
|
|
283
|
+
await ctx.db.writeTransaction(async (tx) => {
|
|
284
|
+
await updateHook?.(tx, attachment);
|
|
285
|
+
await ctx.upsertAttachment({
|
|
286
|
+
...attachment,
|
|
287
|
+
state: AttachmentState.QUEUED_DELETE,
|
|
288
|
+
hasSynced: false
|
|
289
|
+
}, tx);
|
|
290
|
+
});
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
async expireCache() {
|
|
294
|
+
let isDone = false;
|
|
295
|
+
while (!isDone) {
|
|
296
|
+
await this.attachmentService.withContext(async (ctx) => {
|
|
297
|
+
isDone = await this.syncingService.deleteArchivedAttachments(ctx);
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
async clearQueue() {
|
|
302
|
+
await this.attachmentService.withContext(async (ctx) => {
|
|
303
|
+
await ctx.clearQueue();
|
|
304
|
+
});
|
|
305
|
+
await this.localStorage.clear();
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* Verifies the integrity of all attachment records and repairs inconsistencies.
|
|
309
|
+
*
|
|
310
|
+
* This method checks each attachment record against the local filesystem and:
|
|
311
|
+
* - Updates localUri if the file exists at a different path
|
|
312
|
+
* - Archives attachments with missing local files that haven't been uploaded
|
|
313
|
+
* - Requeues synced attachments for download if their local files are missing
|
|
314
|
+
*/
|
|
315
|
+
async verifyAttachments() {
|
|
316
|
+
await this.attachmentService.withContext(async (ctx) => {
|
|
317
|
+
const attachments = await ctx.getAttachments();
|
|
318
|
+
const updates = [];
|
|
319
|
+
for (const attachment of attachments) {
|
|
320
|
+
if (attachment.localUri == null) {
|
|
321
|
+
continue;
|
|
322
|
+
}
|
|
323
|
+
const exists = await this.localStorage.fileExists(attachment.localUri);
|
|
324
|
+
if (exists) {
|
|
325
|
+
// The file exists, this is correct
|
|
326
|
+
continue;
|
|
327
|
+
}
|
|
328
|
+
const newLocalUri = this.localStorage.getLocalUri(attachment.filename);
|
|
329
|
+
const newExists = await this.localStorage.fileExists(newLocalUri);
|
|
330
|
+
if (newExists) {
|
|
331
|
+
// The file exists locally but the localUri is broken, we update it.
|
|
332
|
+
updates.push({
|
|
333
|
+
...attachment,
|
|
334
|
+
localUri: newLocalUri
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
else {
|
|
338
|
+
// the file doesn't exist locally.
|
|
339
|
+
if (attachment.state === AttachmentState.SYNCED) {
|
|
340
|
+
// the file has been successfully synced to remote storage but is missing
|
|
341
|
+
// we download it again
|
|
342
|
+
updates.push({
|
|
343
|
+
...attachment,
|
|
344
|
+
state: AttachmentState.QUEUED_DOWNLOAD,
|
|
345
|
+
localUri: undefined
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
else {
|
|
349
|
+
// the file wasn't successfully synced to remote storage, we archive it
|
|
350
|
+
updates.push({
|
|
351
|
+
...attachment,
|
|
352
|
+
state: AttachmentState.ARCHIVED,
|
|
353
|
+
localUri: undefined // Clears the value
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
await ctx.saveAttachments(updates);
|
|
359
|
+
});
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
//# sourceMappingURL=AttachmentQueue.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AttachmentQueue.js","sourceRoot":"","sources":["../../src/attachments/AttachmentQueue.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { AbstractPowerSyncDatabase } from '../client/AbstractPowerSyncDatabase.js';
|
|
2
|
+
import { DifferentialWatchedQuery } from '../client/watched/processors/DifferentialQueryProcessor.js';
|
|
3
|
+
import { ILogger } from '../utils/Logger.js';
|
|
4
|
+
import { AttachmentContext } from './AttachmentContext.js';
|
|
5
|
+
import { AttachmentRecord } from './Schema.js';
|
|
6
|
+
/**
|
|
7
|
+
* Service for querying and watching attachment records in the database.
|
|
8
|
+
*
|
|
9
|
+
* @internal
|
|
10
|
+
*/
|
|
11
|
+
export declare class AttachmentService {
|
|
12
|
+
private db;
|
|
13
|
+
private logger;
|
|
14
|
+
private tableName;
|
|
15
|
+
private mutex;
|
|
16
|
+
private context;
|
|
17
|
+
constructor(db: AbstractPowerSyncDatabase, logger: ILogger, tableName?: string, archivedCacheLimit?: number);
|
|
18
|
+
/**
|
|
19
|
+
* Creates a differential watch query for active attachments requiring synchronization.
|
|
20
|
+
* @returns Watch query that emits changes for queued uploads, downloads, and deletes
|
|
21
|
+
*/
|
|
22
|
+
watchActiveAttachments({ throttleMs }?: {
|
|
23
|
+
throttleMs?: number;
|
|
24
|
+
}): DifferentialWatchedQuery<AttachmentRecord>;
|
|
25
|
+
/**
|
|
26
|
+
* Executes a callback with exclusive access to the attachment context.
|
|
27
|
+
*/
|
|
28
|
+
withContext<T>(callback: (context: AttachmentContext) => Promise<T>): Promise<T>;
|
|
29
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { Mutex } from 'async-mutex';
|
|
2
|
+
import { mutexRunExclusive } from '../utils/mutex.js';
|
|
3
|
+
import { AttachmentContext } from './AttachmentContext.js';
|
|
4
|
+
import { AttachmentState } from './Schema.js';
|
|
5
|
+
/**
|
|
6
|
+
* Service for querying and watching attachment records in the database.
|
|
7
|
+
*
|
|
8
|
+
* @internal
|
|
9
|
+
*/
|
|
10
|
+
export class AttachmentService {
|
|
11
|
+
db;
|
|
12
|
+
logger;
|
|
13
|
+
tableName;
|
|
14
|
+
mutex = new Mutex();
|
|
15
|
+
context;
|
|
16
|
+
constructor(db, logger, tableName = 'attachments', archivedCacheLimit = 100) {
|
|
17
|
+
this.db = db;
|
|
18
|
+
this.logger = logger;
|
|
19
|
+
this.tableName = tableName;
|
|
20
|
+
this.context = new AttachmentContext(db, tableName, logger, archivedCacheLimit);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Creates a differential watch query for active attachments requiring synchronization.
|
|
24
|
+
* @returns Watch query that emits changes for queued uploads, downloads, and deletes
|
|
25
|
+
*/
|
|
26
|
+
watchActiveAttachments({ throttleMs } = {}) {
|
|
27
|
+
this.logger.info('Watching active attachments...');
|
|
28
|
+
const watch = this.db
|
|
29
|
+
.query({
|
|
30
|
+
sql: /* sql */ `
|
|
31
|
+
SELECT
|
|
32
|
+
*
|
|
33
|
+
FROM
|
|
34
|
+
${this.tableName}
|
|
35
|
+
WHERE
|
|
36
|
+
state = ?
|
|
37
|
+
OR state = ?
|
|
38
|
+
OR state = ?
|
|
39
|
+
ORDER BY
|
|
40
|
+
timestamp ASC
|
|
41
|
+
`,
|
|
42
|
+
parameters: [AttachmentState.QUEUED_UPLOAD, AttachmentState.QUEUED_DOWNLOAD, AttachmentState.QUEUED_DELETE]
|
|
43
|
+
})
|
|
44
|
+
.differentialWatch({ throttleMs });
|
|
45
|
+
return watch;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Executes a callback with exclusive access to the attachment context.
|
|
49
|
+
*/
|
|
50
|
+
async withContext(callback) {
|
|
51
|
+
return mutexRunExclusive(this.mutex, async () => {
|
|
52
|
+
return callback(this.context);
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=AttachmentService.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AttachmentService.js","sourceRoot":"","sources":["../../src/attachments/AttachmentService.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAIpC,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAoB,eAAe,EAAE,MAAM,aAAa,CAAC;AAEhE;;;;GAIG;AACH,MAAM,OAAO,iBAAiB;IAKlB;IACA;IACA;IANF,KAAK,GAAG,IAAI,KAAK,EAAE,CAAC;IACpB,OAAO,CAAoB;IAEnC,YACU,EAA6B,EAC7B,MAAe,EACf,YAAoB,aAAa,EACzC,qBAA6B,GAAG;QAHxB,OAAE,GAAF,EAAE,CAA2B;QAC7B,WAAM,GAAN,MAAM,CAAS;QACf,cAAS,GAAT,SAAS,CAAwB;QAGzC,IAAI,CAAC,OAAO,GAAG,IAAI,iBAAiB,CAAC,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,kBAAkB,CAAC,CAAC;IAClF,CAAC;IAED;;;OAGG;IACH,sBAAsB,CAAC,EAAE,UAAU,KAA8B,EAAE;QACjE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,gCAAgC,CAAC,CAAC;QACnD,MAAM,KAAK,GAAG,IAAI,CAAC,EAAE;aAClB,KAAK,CAAmB;YACvB,GAAG,EAAE,SAAS,CAAC;;;;cAIT,IAAI,CAAC,SAAS;;;;;;;SAOnB;YACD,UAAU,EAAE,CAAC,eAAe,CAAC,aAAa,EAAE,eAAe,CAAC,eAAe,EAAE,eAAe,CAAC,aAAa,CAAC;SAC5G,CAAC;aACD,iBAAiB,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC;QAErC,OAAO,KAAK,CAAC;IACf,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,WAAW,CAAI,QAAoD;QACvE,OAAO,iBAAiB,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,IAAI,EAAE;YAC9C,OAAO,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAChC,CAAC,CAAC,CAAC;IACL,CAAC;CACF"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
export type AttachmentData = ArrayBuffer | string;
|
|
2
|
+
export declare enum EncodingType {
|
|
3
|
+
UTF8 = "utf8",
|
|
4
|
+
Base64 = "base64"
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* LocalStorageAdapter defines the interface for local file storage operations.
|
|
8
|
+
* Implementations handle file I/O, directory management, and storage initialization.
|
|
9
|
+
*
|
|
10
|
+
* @experimental
|
|
11
|
+
* @alpha This is currently experimental and may change without a major version bump.
|
|
12
|
+
*/
|
|
13
|
+
export interface LocalStorageAdapter {
|
|
14
|
+
/**
|
|
15
|
+
* Saves data to a local file.
|
|
16
|
+
* @param filePath Path where the file will be stored
|
|
17
|
+
* @param data Data to store (ArrayBuffer, Blob, or string)
|
|
18
|
+
* @returns Number of bytes written
|
|
19
|
+
*/
|
|
20
|
+
saveFile(filePath: string, data: AttachmentData): Promise<number>;
|
|
21
|
+
/**
|
|
22
|
+
* Retrieves file data as an ArrayBuffer.
|
|
23
|
+
* @param filePath Path where the file is stored
|
|
24
|
+
* @returns ArrayBuffer containing the file data
|
|
25
|
+
*/
|
|
26
|
+
readFile(filePath: string): Promise<ArrayBuffer>;
|
|
27
|
+
/**
|
|
28
|
+
* Deletes the file at the given path.
|
|
29
|
+
* @param filePath Path where the file is stored
|
|
30
|
+
*/
|
|
31
|
+
deleteFile(filePath: string): Promise<void>;
|
|
32
|
+
/**
|
|
33
|
+
* Checks if a file exists at the given path.
|
|
34
|
+
* @param filePath Path where the file is stored
|
|
35
|
+
* @returns True if the file exists, false otherwise
|
|
36
|
+
*/
|
|
37
|
+
fileExists(filePath: string): Promise<boolean>;
|
|
38
|
+
/**
|
|
39
|
+
* Creates a directory at the specified path.
|
|
40
|
+
* @param path The full path to the directory
|
|
41
|
+
*/
|
|
42
|
+
makeDir(path: string): Promise<void>;
|
|
43
|
+
/**
|
|
44
|
+
* Removes a directory at the specified path.
|
|
45
|
+
* @param path The full path to the directory
|
|
46
|
+
*/
|
|
47
|
+
rmDir(path: string): Promise<void>;
|
|
48
|
+
/**
|
|
49
|
+
* Initializes the storage adapter (e.g., creating necessary directories).
|
|
50
|
+
*/
|
|
51
|
+
initialize(): Promise<void>;
|
|
52
|
+
/**
|
|
53
|
+
* Clears all files in the storage.
|
|
54
|
+
*/
|
|
55
|
+
clear(): Promise<void>;
|
|
56
|
+
/**
|
|
57
|
+
* Returns the file path for the provided filename in the storage directory.
|
|
58
|
+
* @param filename The filename to get the path for
|
|
59
|
+
* @returns The full file path
|
|
60
|
+
*/
|
|
61
|
+
getLocalUri(filename: string): string;
|
|
62
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LocalStorageAdapter.js","sourceRoot":"","sources":["../../src/attachments/LocalStorageAdapter.ts"],"names":[],"mappings":"AAEA,MAAM,CAAN,IAAY,YAGX;AAHD,WAAY,YAAY;IACtB,6BAAa,CAAA;IACb,iCAAiB,CAAA;AACnB,CAAC,EAHW,YAAY,KAAZ,YAAY,QAGvB"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { AttachmentRecord } from './Schema.js';
|
|
2
|
+
/**
|
|
3
|
+
* RemoteStorageAdapter defines the interface for remote storage operations.
|
|
4
|
+
* Implementations handle uploading, downloading, and deleting files from remote storage.
|
|
5
|
+
*
|
|
6
|
+
* @experimental
|
|
7
|
+
* @alpha This is currently experimental and may change without a major version bump.
|
|
8
|
+
*/
|
|
9
|
+
export interface RemoteStorageAdapter {
|
|
10
|
+
/**
|
|
11
|
+
* Uploads a file to remote storage.
|
|
12
|
+
* @param fileData The binary content of the file to upload
|
|
13
|
+
* @param attachment The associated attachment metadata
|
|
14
|
+
*/
|
|
15
|
+
uploadFile(fileData: ArrayBuffer, attachment: AttachmentRecord): Promise<void>;
|
|
16
|
+
/**
|
|
17
|
+
* Downloads a file from remote storage.
|
|
18
|
+
* @param attachment The attachment describing the file to download
|
|
19
|
+
* @returns The binary data of the downloaded file
|
|
20
|
+
*/
|
|
21
|
+
downloadFile(attachment: AttachmentRecord): Promise<ArrayBuffer>;
|
|
22
|
+
/**
|
|
23
|
+
* Deletes a file from remote storage.
|
|
24
|
+
* @param attachment The attachment describing the file to delete
|
|
25
|
+
*/
|
|
26
|
+
deleteFile(attachment: AttachmentRecord): Promise<void>;
|
|
27
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RemoteStorageAdapter.js","sourceRoot":"","sources":["../../src/attachments/RemoteStorageAdapter.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { Table } from '../db/schema/Table.js';
|
|
2
|
+
import { TableV2Options } from '../db/schema/Table.js';
|
|
3
|
+
export declare const ATTACHMENT_TABLE = "attachments";
|
|
4
|
+
/**
|
|
5
|
+
* AttachmentRecord represents an attachment in the local database.
|
|
6
|
+
*
|
|
7
|
+
* @experimental
|
|
8
|
+
*/
|
|
9
|
+
export interface AttachmentRecord {
|
|
10
|
+
id: string;
|
|
11
|
+
filename: string;
|
|
12
|
+
localUri?: string;
|
|
13
|
+
size?: number;
|
|
14
|
+
mediaType?: string;
|
|
15
|
+
timestamp?: number;
|
|
16
|
+
metaData?: string;
|
|
17
|
+
hasSynced?: boolean;
|
|
18
|
+
state: AttachmentState;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Maps a database row to an AttachmentRecord.
|
|
22
|
+
*
|
|
23
|
+
* @param row - The database row object
|
|
24
|
+
* @returns The corresponding AttachmentRecord
|
|
25
|
+
*
|
|
26
|
+
* @experimental
|
|
27
|
+
*/
|
|
28
|
+
export declare function attachmentFromSql(row: any): AttachmentRecord;
|
|
29
|
+
/**
|
|
30
|
+
* AttachmentState represents the current synchronization state of an attachment.
|
|
31
|
+
*
|
|
32
|
+
* @experimental
|
|
33
|
+
*/
|
|
34
|
+
export declare enum AttachmentState {
|
|
35
|
+
QUEUED_UPLOAD = 0,// Attachment to be uploaded
|
|
36
|
+
QUEUED_DOWNLOAD = 1,// Attachment to be downloaded
|
|
37
|
+
QUEUED_DELETE = 2,// Attachment to be deleted
|
|
38
|
+
SYNCED = 3,// Attachment has been synced
|
|
39
|
+
ARCHIVED = 4
|
|
40
|
+
}
|
|
41
|
+
export interface AttachmentTableOptions extends Omit<TableV2Options, 'name' | 'columns'> {
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* AttachmentTable defines the schema for the attachment queue table.
|
|
45
|
+
*
|
|
46
|
+
* @internal
|
|
47
|
+
*/
|
|
48
|
+
export declare class AttachmentTable extends Table {
|
|
49
|
+
constructor(options?: AttachmentTableOptions);
|
|
50
|
+
}
|