@powersync/service-core 1.7.0 → 1.7.2

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.
@@ -14,11 +14,10 @@ export const BSON_DESERIALIZE_INTERNAL_OPTIONS: bson.DeserializeOptions = {
14
14
  };
15
15
 
16
16
  /**
17
- * Use for data from external sources.
17
+ * Use for data from external sources, which could contain arbitrary fields.
18
18
  */
19
19
  export const BSON_DESERIALIZE_DATA_OPTIONS: bson.DeserializeOptions = {
20
- // Temporarily disable due to https://jira.mongodb.org/browse/NODE-6764
21
- useBigInt64: false
20
+ useBigInt64: true
22
21
  };
23
22
 
24
23
  /**
@@ -67,16 +66,11 @@ export const deserializeReplicaId = (id: Buffer): ReplicaId => {
67
66
  return deserialized.id;
68
67
  };
69
68
 
69
+ /**
70
+ * Deserialize BSON - can be used for BSON containing arbitrary user data.
71
+ */
70
72
  export const deserializeBson = (buffer: Uint8Array): bson.Document => {
71
- const doc = bson.deserialize(buffer, BSON_DESERIALIZE_DATA_OPTIONS);
72
- // Temporary workaround due to https://jira.mongodb.org/browse/NODE-6764
73
- for (let key in doc) {
74
- const value = doc[key];
75
- if (value instanceof bson.Long) {
76
- doc[key] = value.toBigInt();
77
- }
78
- }
79
- return doc;
73
+ return bson.deserialize(buffer, BSON_DESERIALIZE_DATA_OPTIONS);
80
74
  };
81
75
 
82
76
  export const serializeBson = (document: any): NodeBuffer => {
package/src/sync/sync.ts CHANGED
@@ -155,6 +155,15 @@ async function* streamResponseInner(
155
155
  bucketsByPriority.sort((a, b) => a[0] - b[0]); // Sort from high to lower priorities
156
156
  const lowestPriority = bucketsByPriority.at(-1)?.[0];
157
157
 
158
+ // Ensure that we have at least one priority batch: After sending the checkpoint line, clients expect to
159
+ // receive a sync complete message after the synchronization is done (which happens in the last
160
+ // bucketDataInBatches iteration). Without any batch, the line is missing and clients might not complete their
161
+ // sync properly.
162
+ const priorityBatches: [BucketPriority | null, BucketDescription[]][] = bucketsByPriority;
163
+ if (priorityBatches.length == 0) {
164
+ priorityBatches.push([null, []]);
165
+ }
166
+
158
167
  function maybeRaceForNewCheckpoint() {
159
168
  if (syncedOperations >= 1000 && nextCheckpointPromise === undefined) {
160
169
  nextCheckpointPromise = (async () => {
@@ -179,7 +188,7 @@ async function* streamResponseInner(
179
188
 
180
189
  // This incrementally updates dataBuckets with each individual bucket position.
181
190
  // At the end of this, we can be sure that all buckets have data up to the checkpoint.
182
- for (const [priority, buckets] of bucketsByPriority) {
191
+ for (const [priority, buckets] of priorityBatches) {
183
192
  const isLast = priority === lowestPriority;
184
193
  if (abortCheckpointSignal.aborted) {
185
194
  break;
@@ -196,9 +205,9 @@ async function* streamResponseInner(
196
205
  abort_connection: signal,
197
206
  abort_batch: abortCheckpointSignal,
198
207
  user_id: syncParams.user_id,
199
- // Passing undefined will emit a full sync complete message at the end. If we pass a priority, we'll emit a partial
200
- // sync complete message.
201
- forPriority: !isLast ? priority : undefined
208
+ // Passing null here will emit a full sync complete message at the end. If we pass a priority, we'll emit a partial
209
+ // sync complete message instead.
210
+ forPriority: !isLast ? priority : null
202
211
  });
203
212
  }
204
213
 
@@ -227,7 +236,7 @@ interface BucketDataRequest {
227
236
  */
228
237
  abort_batch: AbortSignal;
229
238
  user_id?: string;
230
- forPriority?: BucketPriority;
239
+ forPriority: BucketPriority | null;
231
240
  onRowsSent: (amount: number) => void;
232
241
  }
233
242
 
@@ -372,7 +381,7 @@ async function* bucketDataBatch(request: BucketDataRequest): AsyncGenerator<Buck
372
381
  // More data should be available immediately for a new checkpoint.
373
382
  yield { data: null, done: true };
374
383
  } else {
375
- if (request.forPriority !== undefined) {
384
+ if (request.forPriority != null) {
376
385
  const line: util.StreamingSyncCheckpointPartiallyComplete = {
377
386
  partial_checkpoint_complete: {
378
387
  last_op_id: checkpoint,