@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
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { column } from '../db/schema/Column.js';
|
|
2
|
-
import { Table } from '../db/schema/Table.js';
|
|
2
|
+
import { RowType, Table } from '../db/schema/Table.js';
|
|
3
3
|
import { TableV2Options } from '../db/schema/Table.js';
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -66,30 +66,39 @@ export enum AttachmentState {
|
|
|
66
66
|
*/
|
|
67
67
|
export interface AttachmentTableOptions extends Omit<TableV2Options, 'name' | 'columns'> {}
|
|
68
68
|
|
|
69
|
+
/**
|
|
70
|
+
* @alpha
|
|
71
|
+
*/
|
|
72
|
+
export const ATTACHMENT_TABLE_COLUMNS = {
|
|
73
|
+
filename: column.text,
|
|
74
|
+
local_uri: column.text,
|
|
75
|
+
timestamp: column.integer,
|
|
76
|
+
size: column.integer,
|
|
77
|
+
media_type: column.text,
|
|
78
|
+
state: column.integer, // Corresponds to AttachmentState
|
|
79
|
+
has_synced: column.integer,
|
|
80
|
+
meta_data: column.text
|
|
81
|
+
};
|
|
82
|
+
|
|
69
83
|
/**
|
|
70
84
|
* AttachmentTable defines the schema for the attachment queue table.
|
|
71
85
|
*
|
|
72
86
|
* @alpha
|
|
73
87
|
*/
|
|
74
|
-
export class AttachmentTable extends Table {
|
|
88
|
+
export class AttachmentTable extends Table<typeof ATTACHMENT_TABLE_COLUMNS> {
|
|
75
89
|
constructor(options?: AttachmentTableOptions) {
|
|
76
|
-
super(
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
media_type: column.text,
|
|
83
|
-
state: column.integer, // Corresponds to AttachmentState
|
|
84
|
-
has_synced: column.integer,
|
|
85
|
-
meta_data: column.text
|
|
86
|
-
},
|
|
87
|
-
{
|
|
88
|
-
...options,
|
|
89
|
-
viewName: options?.viewName ?? ATTACHMENT_TABLE,
|
|
90
|
-
localOnly: true,
|
|
91
|
-
insertOnly: false
|
|
92
|
-
}
|
|
93
|
-
);
|
|
90
|
+
super(ATTACHMENT_TABLE_COLUMNS, {
|
|
91
|
+
...options,
|
|
92
|
+
viewName: options?.viewName ?? ATTACHMENT_TABLE,
|
|
93
|
+
localOnly: true,
|
|
94
|
+
insertOnly: false
|
|
95
|
+
});
|
|
94
96
|
}
|
|
95
97
|
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* AttachmentTableRecord represents the row type of the attachment table.
|
|
101
|
+
*
|
|
102
|
+
* @alpha
|
|
103
|
+
*/
|
|
104
|
+
export type AttachmentTableRecord = RowType<AttachmentTable>;
|
|
@@ -35,35 +35,58 @@ export class SyncingService {
|
|
|
35
35
|
|
|
36
36
|
/**
|
|
37
37
|
* Processes attachments based on their state (upload, download, or delete).
|
|
38
|
-
*
|
|
38
|
+
*
|
|
39
|
+
* Each attachment's I/O runs outside the attachment-service mutex, and the row's
|
|
40
|
+
* state transition is persisted immediately after it completes. This keeps the
|
|
41
|
+
* mutex available to concurrent `saveFile` / `deleteFile` / watched-attachment
|
|
42
|
+
* processing while a batch is in flight, and means consumer queries against the
|
|
43
|
+
* attachments queue see incremental progress instead of one atomic commit at the
|
|
44
|
+
* end of the batch.
|
|
39
45
|
*
|
|
40
46
|
* @param attachments - Array of attachment records to process
|
|
41
|
-
* @param
|
|
42
|
-
*
|
|
47
|
+
* @param options - Optional controls. Pass `signal` (an `AbortSignal`) to interrupt
|
|
48
|
+
* the batch: it is checked between attachments and, once aborted, the
|
|
49
|
+
* loop exits early — letting `stopSync` stop a running batch within
|
|
50
|
+
* one attachment's processing time.
|
|
43
51
|
*/
|
|
44
|
-
async processAttachments(
|
|
45
|
-
|
|
52
|
+
async processAttachments(
|
|
53
|
+
attachments: AttachmentRecord[],
|
|
54
|
+
options?: {
|
|
55
|
+
signal?: AbortSignal;
|
|
56
|
+
}
|
|
57
|
+
): Promise<void> {
|
|
58
|
+
const signal = options?.signal;
|
|
59
|
+
this.logger.info(`Starting processAttachments with ${attachments.length} attachments`);
|
|
60
|
+
|
|
46
61
|
for (const attachment of attachments) {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
updatedAttachments.push(uploaded);
|
|
51
|
-
break;
|
|
52
|
-
case AttachmentState.QUEUED_DOWNLOAD:
|
|
53
|
-
const downloaded = await this.downloadAttachment(attachment);
|
|
54
|
-
updatedAttachments.push(downloaded);
|
|
55
|
-
break;
|
|
56
|
-
case AttachmentState.QUEUED_DELETE:
|
|
57
|
-
const deleted = await this.deleteAttachment(attachment, context);
|
|
58
|
-
updatedAttachments.push(deleted);
|
|
59
|
-
break;
|
|
60
|
-
|
|
61
|
-
default:
|
|
62
|
-
break;
|
|
62
|
+
if (signal?.aborted) {
|
|
63
|
+
this.logger.info('Sync cancelled; stopping iteration early');
|
|
64
|
+
return;
|
|
63
65
|
}
|
|
64
|
-
}
|
|
65
66
|
|
|
66
|
-
|
|
67
|
+
try {
|
|
68
|
+
let updated: AttachmentRecord;
|
|
69
|
+
switch (attachment.state) {
|
|
70
|
+
case AttachmentState.QUEUED_UPLOAD:
|
|
71
|
+
updated = await this.uploadAttachment(attachment);
|
|
72
|
+
break;
|
|
73
|
+
case AttachmentState.QUEUED_DOWNLOAD:
|
|
74
|
+
updated = await this.downloadAttachment(attachment);
|
|
75
|
+
break;
|
|
76
|
+
case AttachmentState.QUEUED_DELETE:
|
|
77
|
+
// `deleteAttachment` needs a context (it removes the row in a
|
|
78
|
+
// transaction); briefly re-acquire the mutex for just this row.
|
|
79
|
+
updated = await this.attachmentService.withContext((ctx) => this.deleteAttachment(attachment, ctx));
|
|
80
|
+
break;
|
|
81
|
+
default:
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
await this.attachmentService.withContext((ctx) => ctx.saveAttachments([updated]));
|
|
86
|
+
} catch (error) {
|
|
87
|
+
this.logger.warn(`Error during sync for ${attachment.id}`, error);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
67
90
|
}
|
|
68
91
|
|
|
69
92
|
/**
|