@powersync/service-module-mssql 0.0.1 → 0.1.1

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.
Files changed (58) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/dist/api/MSSQLRouteAPIAdapter.js +16 -51
  3. package/dist/api/MSSQLRouteAPIAdapter.js.map +1 -1
  4. package/dist/common/LSN.js +2 -2
  5. package/dist/common/LSN.js.map +1 -1
  6. package/dist/common/MSSQLSourceTable.js +4 -4
  7. package/dist/common/MSSQLSourceTable.js.map +1 -1
  8. package/dist/common/mssqls-to-sqlite.js +4 -4
  9. package/dist/common/mssqls-to-sqlite.js.map +1 -1
  10. package/dist/module/MSSQLModule.js +1 -1
  11. package/dist/module/MSSQLModule.js.map +1 -1
  12. package/dist/replication/CDCPoller.d.ts +2 -2
  13. package/dist/replication/CDCPoller.js +12 -8
  14. package/dist/replication/CDCPoller.js.map +1 -1
  15. package/dist/replication/CDCReplicationJob.d.ts +2 -2
  16. package/dist/replication/CDCReplicationJob.js +1 -1
  17. package/dist/replication/CDCReplicationJob.js.map +1 -1
  18. package/dist/replication/CDCReplicator.d.ts +2 -2
  19. package/dist/replication/CDCReplicator.js +1 -1
  20. package/dist/replication/CDCReplicator.js.map +1 -1
  21. package/dist/replication/CDCStream.d.ts +2 -2
  22. package/dist/replication/CDCStream.js +32 -37
  23. package/dist/replication/CDCStream.js.map +1 -1
  24. package/dist/replication/MSSQLConnectionManager.js +1 -1
  25. package/dist/replication/MSSQLConnectionManager.js.map +1 -1
  26. package/dist/replication/MSSQLSnapshotQuery.d.ts +0 -17
  27. package/dist/replication/MSSQLSnapshotQuery.js +0 -47
  28. package/dist/replication/MSSQLSnapshotQuery.js.map +1 -1
  29. package/dist/types/types.d.ts +80 -23
  30. package/dist/types/types.js +24 -24
  31. package/dist/types/types.js.map +1 -1
  32. package/dist/utils/mssql.js +26 -14
  33. package/dist/utils/mssql.js.map +1 -1
  34. package/dist/utils/schema.js +31 -15
  35. package/dist/utils/schema.js.map +1 -1
  36. package/package.json +10 -10
  37. package/src/api/MSSQLRouteAPIAdapter.ts +16 -51
  38. package/src/common/LSN.ts +2 -2
  39. package/src/common/MSSQLSourceTable.ts +4 -4
  40. package/src/common/mssqls-to-sqlite.ts +11 -4
  41. package/src/module/MSSQLModule.ts +1 -1
  42. package/src/replication/CDCPoller.ts +15 -10
  43. package/src/replication/CDCReplicationJob.ts +3 -3
  44. package/src/replication/CDCReplicator.ts +3 -3
  45. package/src/replication/CDCStream.ts +36 -49
  46. package/src/replication/MSSQLConnectionManager.ts +1 -1
  47. package/src/replication/MSSQLSnapshotQuery.ts +0 -54
  48. package/src/types/types.ts +41 -45
  49. package/src/utils/mssql.ts +33 -15
  50. package/src/utils/schema.ts +31 -17
  51. package/test/src/CDCStream.test.ts +9 -17
  52. package/test/src/CDCStreamTestContext.ts +5 -5
  53. package/test/src/CDCStream_resumable_snapshot.test.ts +15 -9
  54. package/test/src/mssql-to-sqlite.test.ts +28 -27
  55. package/test/src/util.ts +27 -14
  56. package/tsconfig.tsbuildinfo +1 -1
  57. package/ci/init-mssql.sql +0 -50
  58. package/test/tsconfig.tsbuildinfo +0 -1
@@ -12,7 +12,6 @@ import { clearTestDb, getClientCheckpoint, TEST_CONNECTION_OPTIONS } from './uti
12
12
  import { CDCStream, CDCStreamOptions } from '@module/replication/CDCStream.js';
13
13
  import { MSSQLConnectionManager } from '@module/replication/MSSQLConnectionManager.js';
14
14
  import timers from 'timers/promises';
15
- import { CDCPollingOptions } from '@module/types/types.js';
16
15
 
17
16
  /**
18
17
  * Tests operating on the change data capture need to configure the stream and manage asynchronous
@@ -110,10 +109,11 @@ export class CDCStreamTestContext implements AsyncDisposable {
110
109
  metrics: METRICS_HELPER.metricsEngine,
111
110
  connections: this.connectionManager,
112
111
  abortSignal: this.abortController.signal,
113
- pollingOptions: {
114
- batchSize: 10,
115
- intervalMs: 1000
116
- } satisfies CDCPollingOptions,
112
+ additionalConfig: {
113
+ pollingBatchSize: 10,
114
+ pollingIntervalMs: 1000,
115
+ trustServerCertificate: true
116
+ },
117
117
  ...this.cdcStreamOptions
118
118
  };
119
119
  this._cdcStream = new CDCStream(options);
@@ -1,13 +1,13 @@
1
1
  import { describe, expect, test } from 'vitest';
2
2
  import { env } from './env.js';
3
- import { createTestTable, createTestTableWithBasicId, describeWithStorage, waitForPendingCDCChanges } from './util.js';
3
+ import { createTestTableWithBasicId, describeWithStorage, waitForPendingCDCChanges } from './util.js';
4
4
  import { TestStorageFactory } from '@powersync/service-core';
5
5
  import { METRICS_HELPER } from '@powersync/service-core-tests';
6
6
  import { ReplicationMetric } from '@powersync/service-types';
7
7
  import * as timers from 'node:timers/promises';
8
- import { ReplicationAbortedError } from '@powersync/lib-services-framework';
8
+ import { logger, ReplicationAbortedError } from '@powersync/lib-services-framework';
9
9
  import { CDCStreamTestContext } from './CDCStreamTestContext.js';
10
- import { getLatestReplicatedLSN } from '@module/utils/mssql.js';
10
+ import { getLatestLSN } from '@module/utils/mssql.js';
11
11
 
12
12
  describe.skipIf(!(env.CI || env.SLOW_TESTS))('batch replication', function () {
13
13
  describeWithStorage({ timeout: 240_000 }, function (factory) {
@@ -46,10 +46,9 @@ async function testResumingReplication(factory: TestStorageFactory, stopAfter: n
46
46
  await createTestTableWithBasicId(connectionManager, 'test_data1');
47
47
  await createTestTableWithBasicId(connectionManager, 'test_data2');
48
48
 
49
- let beforeLSN = await getLatestReplicatedLSN(connectionManager);
50
49
  await connectionManager.query(`INSERT INTO test_data1(description) SELECT 'value' FROM GENERATE_SERIES(1, 1000, 1)`);
50
+ let beforeLSN = await getLatestLSN(connectionManager);
51
51
  await connectionManager.query(`INSERT INTO test_data2(description) SELECT 'value' FROM GENERATE_SERIES(1, 10000, 1)`);
52
-
53
52
  await waitForPendingCDCChanges(beforeLSN, connectionManager);
54
53
 
55
54
  const p = context.replicateSnapshot();
@@ -64,6 +63,7 @@ async function testResumingReplication(factory: TestStorageFactory, stopAfter: n
64
63
  ((await METRICS_HELPER.getMetricValueForTests(ReplicationMetric.ROWS_REPLICATED)) ?? 0) - startRowCount;
65
64
 
66
65
  if (count >= stopAfter) {
66
+ logger.info(`Stopped initial replication after replicating ${count} rows.`);
67
67
  break;
68
68
  }
69
69
  await timers.setTimeout(1);
@@ -85,22 +85,28 @@ async function testResumingReplication(factory: TestStorageFactory, stopAfter: n
85
85
  cdcStreamOptions: { snapshotBatchSize: 1000 }
86
86
  });
87
87
 
88
- beforeLSN = await getLatestReplicatedLSN(context2.connectionManager);
89
88
  // This delete should be using one of the ids already replicated
90
89
  const {
91
- recordset: [id1]
90
+ recordset: [deleteResult]
92
91
  } = await context2.connectionManager.query(`DELETE TOP (1) FROM test_data2 OUTPUT DELETED.id`);
93
92
  // This update should also be using one of the ids already replicated
93
+ const id1 = deleteResult.id;
94
+ logger.info(`Deleted row with id: ${id1}`);
94
95
  const {
95
- recordset: [id2]
96
+ recordset: [updateResult]
96
97
  } = await context2.connectionManager.query(
97
98
  `UPDATE test_data2 SET description = 'update1' OUTPUT INSERTED.id WHERE id = (SELECT TOP 1 id FROM test_data2)`
98
99
  );
100
+ const id2 = updateResult.id;
101
+ logger.info(`Updated row with id: ${id2}`);
102
+ beforeLSN = await getLatestLSN(context2.connectionManager);
99
103
  const {
100
- recordset: [id3]
104
+ recordset: [insertResult]
101
105
  } = await context2.connectionManager.query(
102
106
  `INSERT INTO test_data2(description) OUTPUT INSERTED.id VALUES ('insert1')`
103
107
  );
108
+ const id3 = insertResult.id;
109
+ logger.info(`Inserted row with id: ${id3}`);
104
110
  await waitForPendingCDCChanges(beforeLSN, context2.connectionManager);
105
111
 
106
112
  await context2.loadNextSyncRules();
@@ -1,11 +1,13 @@
1
- import { SqliteInputRow } from '@powersync/service-sync-rules';
1
+ import { SQLITE_TRUE, SqliteInputRow } from '@powersync/service-sync-rules';
2
2
  import { afterAll, beforeEach, describe, expect, test } from 'vitest';
3
3
  import { clearTestDb, createUpperCaseUUID, TEST_CONNECTION_OPTIONS, waitForPendingCDCChanges } from './util.js';
4
4
  import { CDCToSqliteRow, toSqliteInputRow } from '@module/common/mssqls-to-sqlite.js';
5
5
  import { MSSQLConnectionManager } from '@module/replication/MSSQLConnectionManager.js';
6
6
  import {
7
7
  enableCDCForTable,
8
+ escapeIdentifier,
8
9
  getCaptureInstance,
10
+ getLatestLSN,
9
11
  getLatestReplicatedLSN,
10
12
  getMinLSN,
11
13
  toQualifiedTableName
@@ -25,7 +27,7 @@ describe('MSSQL Data Types Tests', () => {
25
27
 
26
28
  async function setupTestTable() {
27
29
  await connectionManager.query(`
28
- CREATE TABLE ${connectionManager.schema}.test_data (
30
+ CREATE TABLE ${escapeIdentifier(connectionManager.schema)}.test_data (
29
31
  id INT IDENTITY(1,1) PRIMARY KEY,
30
32
  tinyint_col TINYINT,
31
33
  smallint_col SMALLINT,
@@ -74,9 +76,9 @@ describe('MSSQL Data Types Tests', () => {
74
76
  }
75
77
 
76
78
  test('Number types mappings', async () => {
77
- const beforeLSN = await getLatestReplicatedLSN(connectionManager);
79
+ const beforeLSN = await getLatestLSN(connectionManager);
78
80
  await connectionManager.query(`
79
- INSERT INTO ${connectionManager.schema}.test_data(
81
+ INSERT INTO ${escapeIdentifier(connectionManager.schema)}.test_data(
80
82
  tinyint_col,
81
83
  smallint_col,
82
84
  int_col,
@@ -118,16 +120,16 @@ describe('MSSQL Data Types Tests', () => {
118
120
  numeric_col: 12345.67,
119
121
  money_col: 12345.67,
120
122
  smallmoney_col: 123.45,
121
- bit_col: 1
123
+ bit_col: SQLITE_TRUE
122
124
  };
123
125
  expect(databaseRows[0]).toMatchObject(expectedResult);
124
126
  expect(replicatedRows[0]).toMatchObject(expectedResult);
125
127
  });
126
128
 
127
129
  test('Character types mappings', async () => {
128
- const beforeLSN = await getLatestReplicatedLSN(connectionManager);
130
+ const beforeLSN = await getLatestLSN(connectionManager);
129
131
  await connectionManager.query(`
130
- INSERT INTO [${connectionManager.schema}].test_data (
132
+ INSERT INTO ${escapeIdentifier(connectionManager.schema)}.test_data (
131
133
  char_col,
132
134
  varchar_col,
133
135
  varchar_max_col,
@@ -167,11 +169,11 @@ describe('MSSQL Data Types Tests', () => {
167
169
  });
168
170
 
169
171
  test('Binary types mappings', async () => {
170
- const beforeLSN = await getLatestReplicatedLSN(connectionManager);
172
+ const beforeLSN = await getLatestLSN(connectionManager);
171
173
  const binaryData = Buffer.from('BinaryData');
172
174
  await connectionManager.query(
173
175
  `
174
- INSERT INTO [${connectionManager.schema}].test_data (
176
+ INSERT INTO ${escapeIdentifier(connectionManager.schema)}.test_data (
175
177
  binary_col,
176
178
  varbinary_col,
177
179
  varbinary_max_col,
@@ -211,11 +213,11 @@ describe('MSSQL Data Types Tests', () => {
211
213
  });
212
214
 
213
215
  test('Date types mappings', async () => {
214
- const beforeLSN = await getLatestReplicatedLSN(connectionManager);
216
+ const beforeLSN = await getLatestLSN(connectionManager);
215
217
  const testDate = new Date('2023-03-06T15:47:00.000Z');
216
218
  await connectionManager.query(
217
219
  `
218
- INSERT INTO [${connectionManager.schema}].test_data(
220
+ INSERT INTO ${escapeIdentifier(connectionManager.schema)}.test_data(
219
221
  date_col,
220
222
  datetime_col,
221
223
  datetime2_col,
@@ -255,22 +257,21 @@ describe('MSSQL Data Types Tests', () => {
255
257
  });
256
258
 
257
259
  test('Date types edge cases mappings', async () => {
258
- const beforeLSN = await getLatestReplicatedLSN(connectionManager);
259
-
260
260
  await connectionManager.query(`
261
- INSERT INTO [${connectionManager.schema}].test_data(datetime2_col)
261
+ INSERT INTO ${escapeIdentifier(connectionManager.schema)}.test_data(datetime2_col)
262
262
  VALUES ('0001-01-01 00:00:00.000')
263
263
  `);
264
264
  await connectionManager.query(`
265
- INSERT INTO [${connectionManager.schema}].test_data(datetime2_col)
265
+ INSERT INTO ${escapeIdentifier(connectionManager.schema)}.test_data(datetime2_col)
266
266
  VALUES ('9999-12-31 23:59:59.999')
267
267
  `);
268
268
  await connectionManager.query(`
269
- INSERT INTO [${connectionManager.schema}].test_data(datetime_col)
269
+ INSERT INTO ${escapeIdentifier(connectionManager.schema)}.test_data(datetime_col)
270
270
  VALUES ('1753-01-01 00:00:00')
271
271
  `);
272
+ const beforeLSN = await getLatestLSN(connectionManager);
272
273
  await connectionManager.query(`
273
- INSERT INTO [${connectionManager.schema}].test_data(datetime_col)
274
+ INSERT INTO ${escapeIdentifier(connectionManager.schema)}.test_data(datetime_col)
274
275
  VALUES ('9999-12-31 23:59:59.997')
275
276
  `);
276
277
  await waitForPendingCDCChanges(beforeLSN, connectionManager);
@@ -292,10 +293,10 @@ describe('MSSQL Data Types Tests', () => {
292
293
  });
293
294
 
294
295
  test('DateTimeOffset type mapping', async () => {
295
- const beforeLSN = await getLatestReplicatedLSN(connectionManager);
296
+ const beforeLSN = await getLatestLSN(connectionManager);
296
297
  // DateTimeOffset preserves timezone information
297
298
  await connectionManager.query(`
298
- INSERT INTO [${connectionManager.schema}].test_data(datetimeoffset_col)
299
+ INSERT INTO ${escapeIdentifier(connectionManager.schema)}.test_data(datetimeoffset_col)
299
300
  VALUES ('2023-03-06 15:47:00.000 +05:00')
300
301
  `);
301
302
  await waitForPendingCDCChanges(beforeLSN, connectionManager);
@@ -313,12 +314,12 @@ describe('MSSQL Data Types Tests', () => {
313
314
  });
314
315
 
315
316
  test('UniqueIdentifier type mapping', async () => {
316
- const beforeLSN = await getLatestReplicatedLSN(connectionManager);
317
+ const beforeLSN = await getLatestLSN(connectionManager);
317
318
 
318
319
  const testGuid = createUpperCaseUUID();
319
320
  await connectionManager.query(
320
321
  `
321
- INSERT INTO [${connectionManager.schema}].test_data(uniqueidentifier_col)
322
+ INSERT INTO ${escapeIdentifier(connectionManager.schema)}.test_data(uniqueidentifier_col)
322
323
  VALUES (@guid)
323
324
  `,
324
325
  [{ name: 'guid', type: sql.UniqueIdentifier, value: testGuid }]
@@ -334,11 +335,11 @@ describe('MSSQL Data Types Tests', () => {
334
335
  });
335
336
 
336
337
  test('JSON type mapping', async () => {
337
- const beforeLSN = await getLatestReplicatedLSN(connectionManager);
338
+ const beforeLSN = await getLatestLSN(connectionManager);
338
339
  const expectedJSON = { name: 'John Doe', age: 30, married: true };
339
340
  await connectionManager.query(
340
341
  `
341
- INSERT INTO [${connectionManager.schema}].test_data(json_col)
342
+ INSERT INTO ${escapeIdentifier(connectionManager.schema)}.test_data(json_col)
342
343
  VALUES (@json)
343
344
  `,
344
345
  [{ name: 'json', type: sql.NVarChar(sql.MAX), value: JSON.stringify(expectedJSON) }]
@@ -355,11 +356,11 @@ describe('MSSQL Data Types Tests', () => {
355
356
  });
356
357
 
357
358
  test('XML type mapping', async () => {
358
- const beforeLSN = await getLatestReplicatedLSN(connectionManager);
359
+ const beforeLSN = await getLatestLSN(connectionManager);
359
360
  const xmlData = '<root><item>value</item></root>';
360
361
  await connectionManager.query(
361
362
  `
362
- INSERT INTO [${connectionManager.schema}].test_data(xml_col)
363
+ INSERT INTO ${escapeIdentifier(connectionManager.schema)}.test_data(xml_col)
363
364
  VALUES (@xml)
364
365
  `,
365
366
  [{ name: 'xml', type: sql.Xml, value: xmlData }]
@@ -375,7 +376,7 @@ describe('MSSQL Data Types Tests', () => {
375
376
 
376
377
  // TODO: Update test when properly converting spatial types
377
378
  // test('Spatial types mappings', async () => {
378
- // const beforeLSN = await getLatestReplicatedLSN(connectionManager);
379
+ // const beforeLSN = await getLatestLSN(connectionManager);
379
380
  // // Geometry and Geography types are stored as binary/WKT strings
380
381
  // await connectionManager.query(`
381
382
  // INSERT INTO [${connectionManager.schema}].test_data(geometry_col, geography_col)
@@ -399,7 +400,7 @@ describe('MSSQL Data Types Tests', () => {
399
400
  // TODO: Enable when HierarchyID type is properly supported
400
401
  // test('HierarchyID type mapping', async () => {
401
402
  // const hierarchyid = '/1/';
402
- // const beforeLSN = await getLatestReplicatedLSN(connectionManager);
403
+ // const beforeLSN = await getLatestLSN(connectionManager);
403
404
  // await connectionManager.query(`
404
405
  // INSERT INTO [${connectionManager.schema}].test_data(hierarchyid_col)
405
406
  // VALUES (@hierarchyid)
package/test/src/util.ts CHANGED
@@ -8,7 +8,7 @@ import * as postgres_storage from '@powersync/service-module-postgres-storage';
8
8
  import { describe, TestOptions } from 'vitest';
9
9
  import { env } from './env.js';
10
10
  import { MSSQLConnectionManager } from '@module/replication/MSSQLConnectionManager.js';
11
- import { createCheckpoint, enableCDCForTable, getLatestLSN } from '@module/utils/mssql.js';
11
+ import { createCheckpoint, enableCDCForTable, escapeIdentifier, getLatestLSN } from '@module/utils/mssql.js';
12
12
  import sql from 'mssql';
13
13
  import { v4 as uuid } from 'uuid';
14
14
  import { LSN } from '@module/common/LSN.js';
@@ -37,7 +37,11 @@ export function describeWithStorage(options: TestOptions, fn: (factory: TestStor
37
37
  export const TEST_CONNECTION_OPTIONS = types.normalizeConnectionConfig({
38
38
  type: 'mssql',
39
39
  uri: TEST_URI,
40
- trustServerCertificate: true
40
+ additionalConfig: {
41
+ pollingBatchSize: 10,
42
+ pollingIntervalMs: 1000,
43
+ trustServerCertificate: true
44
+ }
41
45
  });
42
46
 
43
47
  /**
@@ -62,6 +66,16 @@ export async function clearTestDb(connectionManager: MSSQLConnectionManager) {
62
66
  }
63
67
  }
64
68
 
69
+ export async function resetTestTable(connectionManager: MSSQLConnectionManager, tableName: string) {
70
+ await connectionManager.execute('sys.sp_cdc_disable_table', [
71
+ { name: 'source_schema', value: connectionManager.schema },
72
+ { name: 'source_name', value: tableName },
73
+ { name: 'capture_instance', value: 'all' }
74
+ ]);
75
+
76
+ await connectionManager.query(`DROP TABLE [${tableName}]`);
77
+ }
78
+
65
79
  /**
66
80
  * Create a new database for testing and enables CDC on it.
67
81
  * @param connectionManager
@@ -80,7 +94,7 @@ export async function createTestDb(connectionManager: MSSQLConnectionManager, db
80
94
 
81
95
  export async function createTestTable(connectionManager: MSSQLConnectionManager, tableName: string): Promise<void> {
82
96
  await connectionManager.query(`
83
- CREATE TABLE ${connectionManager.schema}.${tableName} (
97
+ CREATE TABLE ${escapeIdentifier(connectionManager.schema)}.${escapeIdentifier(tableName)} (
84
98
  id UNIQUEIDENTIFIER PRIMARY KEY,
85
99
  description VARCHAR(MAX)
86
100
  )
@@ -93,7 +107,7 @@ export async function createTestTableWithBasicId(
93
107
  tableName: string
94
108
  ): Promise<void> {
95
109
  await connectionManager.query(`
96
- CREATE TABLE ${connectionManager.schema}.${tableName} (
110
+ CREATE TABLE ${escapeIdentifier(connectionManager.schema)}.${escapeIdentifier(tableName)} (
97
111
  id INT IDENTITY(1,1) PRIMARY KEY,
98
112
  description VARCHAR(MAX)
99
113
  )
@@ -110,7 +124,7 @@ export async function insertTestData(connectionManager: MSSQLConnectionManager,
110
124
  const description = `description_${id}`;
111
125
  await connectionManager.query(
112
126
  `
113
- INSERT INTO ${connectionManager.schema}.${tableName} (id, description) VALUES (@id, @description)
127
+ INSERT INTO ${escapeIdentifier(connectionManager.schema)}.${escapeIdentifier(tableName)} (id, description) VALUES (@id, @description)
114
128
  `,
115
129
  [
116
130
  { name: 'id', type: sql.UniqueIdentifier, value: id },
@@ -137,8 +151,8 @@ export async function waitForPendingCDCChanges(
137
151
  );
138
152
 
139
153
  if (result.length === 0) {
140
- logger.info(`CDC changes pending. Waiting for 500ms...`);
141
- await new Promise((resolve) => setTimeout(resolve, 500));
154
+ logger.info(`CDC changes pending. Waiting for 200ms...`);
155
+ await new Promise((resolve) => setTimeout(resolve, 200));
142
156
  } else {
143
157
  logger.info(`Found LSN: ${LSN.fromBinary(result[0].start_lsn).toString()}`);
144
158
  return;
@@ -166,13 +180,12 @@ export async function getClientCheckpoint(
166
180
  while (Date.now() - start < timeout) {
167
181
  const storage = await storageFactory.getActiveStorage();
168
182
  const cp = await storage?.getCheckpoint();
169
- if (cp == null) {
170
- throw new Error('No sync rules available');
171
- }
172
- lastCp = cp;
173
- if (cp.lsn != null && cp.lsn >= lsn.toString()) {
174
- logger.info(`Got write checkpoint: ${lsn} : ${cp.checkpoint}`);
175
- return cp.checkpoint;
183
+ if (cp != null) {
184
+ lastCp = cp;
185
+ if (cp.lsn != null && cp.lsn >= lsn.toString()) {
186
+ logger.info(`Got write checkpoint: ${lsn} : ${cp.checkpoint}`);
187
+ return cp.checkpoint;
188
+ }
176
189
  }
177
190
 
178
191
  await new Promise((resolve) => setTimeout(resolve, 30));