@powersync/service-core 0.0.0-dev-20240930091342 → 0.0.0-dev-20241001150444

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 (107) hide show
  1. package/CHANGELOG.md +5 -6
  2. package/dist/api/diagnostics.js.map +1 -1
  3. package/dist/api/schema.js.map +1 -1
  4. package/dist/auth/CachedKeyCollector.js.map +1 -1
  5. package/dist/auth/KeySpec.js.map +1 -1
  6. package/dist/auth/KeyStore.js.map +1 -1
  7. package/dist/auth/LeakyBucket.js.map +1 -1
  8. package/dist/auth/RemoteJWKSCollector.d.ts +2 -0
  9. package/dist/auth/RemoteJWKSCollector.js.map +1 -1
  10. package/dist/db/mongo.js +5 -3
  11. package/dist/db/mongo.js.map +1 -1
  12. package/dist/entry/cli-entry.js.map +1 -1
  13. package/dist/entry/commands/compact-action.js.map +1 -1
  14. package/dist/entry/commands/migrate-action.js.map +1 -1
  15. package/dist/entry/commands/teardown-action.js.map +1 -1
  16. package/dist/locks/MongoLocks.js.map +1 -1
  17. package/dist/metrics/Metrics.js.map +1 -1
  18. package/dist/migrations/db/migrations/1684951997326-init.js.map +1 -1
  19. package/dist/migrations/db/migrations/1702295701188-sync-rule-state.js.map +1 -1
  20. package/dist/migrations/db/migrations/1711543888062-write-checkpoint-index.js.map +1 -1
  21. package/dist/migrations/executor.js.map +1 -1
  22. package/dist/migrations/migrations.js.map +1 -1
  23. package/dist/migrations/store/migration-store.js.map +1 -1
  24. package/dist/modules/ModuleManager.js.map +1 -1
  25. package/dist/replication/AbstractReplicationJob.d.ts +1 -0
  26. package/dist/replication/AbstractReplicator.js.map +1 -1
  27. package/dist/replication/ErrorRateLimiter.d.ts +1 -0
  28. package/dist/replication/ReplicationEngine.js.map +1 -1
  29. package/dist/replication/ReplicationModule.js.map +1 -1
  30. package/dist/routes/RouterEngine.js.map +1 -1
  31. package/dist/routes/auth.js.map +1 -1
  32. package/dist/routes/configure-fastify.d.ts +7 -15
  33. package/dist/routes/configure-rsocket.d.ts +1 -0
  34. package/dist/routes/configure-rsocket.js.map +1 -1
  35. package/dist/routes/endpoints/admin.d.ts +12 -30
  36. package/dist/routes/endpoints/admin.js.map +1 -1
  37. package/dist/routes/endpoints/checkpointing.js.map +1 -1
  38. package/dist/routes/endpoints/socket-route.js.map +1 -1
  39. package/dist/routes/endpoints/sync-rules.js.map +1 -1
  40. package/dist/routes/endpoints/sync-stream.d.ts +1 -0
  41. package/dist/routes/endpoints/sync-stream.js.map +1 -1
  42. package/dist/routes/hooks.js.map +1 -1
  43. package/dist/routes/route-register.js.map +1 -1
  44. package/dist/runner/teardown.js.map +1 -1
  45. package/dist/storage/BucketStorage.d.ts +5 -0
  46. package/dist/storage/BucketStorage.js.map +1 -1
  47. package/dist/storage/ChecksumCache.js.map +1 -1
  48. package/dist/storage/MongoBucketStorage.d.ts +1 -0
  49. package/dist/storage/MongoBucketStorage.js +1 -1
  50. package/dist/storage/MongoBucketStorage.js.map +1 -1
  51. package/dist/storage/StorageEngine.js.map +1 -1
  52. package/dist/storage/mongo/MongoBucketBatch.d.ts +1 -0
  53. package/dist/storage/mongo/MongoBucketBatch.js +4 -1
  54. package/dist/storage/mongo/MongoBucketBatch.js.map +1 -1
  55. package/dist/storage/mongo/MongoCompactor.js.map +1 -1
  56. package/dist/storage/mongo/MongoIdSequence.js.map +1 -1
  57. package/dist/storage/mongo/MongoPersistedSyncRulesContent.js.map +1 -1
  58. package/dist/storage/mongo/MongoSyncBucketStorage.js.map +1 -1
  59. package/dist/storage/mongo/MongoSyncRulesLock.js.map +1 -1
  60. package/dist/storage/mongo/OperationBatch.js.map +1 -1
  61. package/dist/storage/mongo/PersistedBatch.js.map +1 -1
  62. package/dist/storage/mongo/config.d.ts +19 -0
  63. package/dist/storage/mongo/config.js +26 -0
  64. package/dist/storage/mongo/config.js.map +1 -0
  65. package/dist/storage/mongo/util.js.map +1 -1
  66. package/dist/storage/storage-index.d.ts +1 -0
  67. package/dist/storage/storage-index.js +1 -0
  68. package/dist/storage/storage-index.js.map +1 -1
  69. package/dist/sync/BroadcastIterable.d.ts +1 -0
  70. package/dist/sync/BroadcastIterable.js.map +1 -1
  71. package/dist/sync/LastValueSink.d.ts +1 -0
  72. package/dist/sync/LastValueSink.js.map +1 -1
  73. package/dist/sync/merge.d.ts +1 -0
  74. package/dist/sync/merge.js.map +1 -1
  75. package/dist/sync/safeRace.js.map +1 -1
  76. package/dist/sync/sync.d.ts +1 -0
  77. package/dist/sync/sync.js.map +1 -1
  78. package/dist/sync/util.d.ts +2 -0
  79. package/dist/sync/util.js.map +1 -1
  80. package/dist/util/Mutex.js.map +1 -1
  81. package/dist/util/config/collectors/config-collector.js.map +1 -1
  82. package/dist/util/config/collectors/impl/base64-config-collector.js.map +1 -1
  83. package/dist/util/config/collectors/impl/filesystem-config-collector.js.map +1 -1
  84. package/dist/util/config/compound-config-collector.js +1 -1
  85. package/dist/util/config/compound-config-collector.js.map +1 -1
  86. package/dist/util/config/sync-rules/impl/base64-sync-rules-collector.js.map +1 -1
  87. package/dist/util/config/sync-rules/impl/filesystem-sync-rules-collector.js.map +1 -1
  88. package/dist/util/config/sync-rules/impl/inline-sync-rules-collector.js.map +1 -1
  89. package/dist/util/config/sync-rules/sync-rules-provider.js.map +1 -1
  90. package/dist/util/config.js.map +1 -1
  91. package/dist/util/memory-tracking.js.map +1 -1
  92. package/dist/util/secs.js.map +1 -1
  93. package/dist/util/utils.js.map +1 -1
  94. package/package.json +9 -8
  95. package/src/auth/RemoteJWKSCollector.ts +1 -4
  96. package/src/db/mongo.ts +5 -3
  97. package/src/storage/BucketStorage.ts +5 -0
  98. package/src/storage/mongo/MongoBucketBatch.ts +6 -2
  99. package/src/storage/mongo/MongoCompactor.ts +1 -5
  100. package/src/storage/mongo/MongoPersistedSyncRulesContent.ts +1 -4
  101. package/src/storage/mongo/MongoSyncRulesLock.ts +2 -6
  102. package/src/storage/mongo/PersistedBatch.ts +1 -4
  103. package/src/storage/mongo/config.ts +40 -0
  104. package/src/storage/storage-index.ts +1 -0
  105. package/test/src/__snapshots__/sync.test.ts.snap +7 -7
  106. package/tsconfig.tsbuildinfo +1 -1
  107. package/vitest.config.ts +1 -7
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
8
- "version": "0.0.0-dev-20240930091342",
8
+ "version": "0.0.0-dev-20241001150444",
9
9
  "main": "dist/index.js",
10
10
  "license": "FSL-1.1-Apache-2.0",
11
11
  "type": "module",
@@ -29,14 +29,15 @@
29
29
  "mongodb": "^6.7.0",
30
30
  "node-fetch": "^3.3.2",
31
31
  "ts-codec": "^1.2.2",
32
+ "uri-js": "^4.4.1",
32
33
  "uuid": "^9.0.1",
33
34
  "winston": "^3.13.0",
34
35
  "yaml": "^2.3.2",
35
- "@powersync/lib-services-framework": "0.0.0-dev-20240930091342",
36
+ "@powersync/lib-services-framework": "0.0.0-dev-20241001150444",
36
37
  "@powersync/service-jsonbig": "0.17.10",
37
- "@powersync/service-rsocket-router": "0.0.0-dev-20240930091342",
38
- "@powersync/service-sync-rules": "0.0.0-dev-20240930091342",
39
- "@powersync/service-types": "0.0.0-dev-20240930091342"
38
+ "@powersync/service-rsocket-router": "0.0.0-dev-20241001150444",
39
+ "@powersync/service-sync-rules": "0.0.0-dev-20241001150444",
40
+ "@powersync/service-types": "0.0.0-dev-20241001150444"
40
41
  },
41
42
  "devDependencies": {
42
43
  "@types/async": "^3.2.24",
@@ -44,14 +45,14 @@
44
45
  "@types/uuid": "^9.0.4",
45
46
  "fastify": "4.23.2",
46
47
  "fastify-plugin": "^4.5.1",
47
- "typescript": "^5.6.2",
48
+ "typescript": "^5.2.2",
48
49
  "vite-tsconfig-paths": "^4.3.2",
49
- "vitest": "^2.1.1"
50
+ "vitest": "^0.34.6"
50
51
  },
51
52
  "scripts": {
52
53
  "build": "tsc -b",
53
54
  "build:tests": "tsc -b test/tsconfig.json",
54
- "test": "vitest",
55
+ "test": "vitest --no-threads",
55
56
  "clean": "rm -rf ./lib && tsc -b --clean"
56
57
  }
57
58
  }
@@ -22,10 +22,7 @@ export type RemoteJWKSCollectorOptions = {
22
22
  export class RemoteJWKSCollector implements KeyCollector {
23
23
  private url: URL;
24
24
 
25
- constructor(
26
- url: string,
27
- protected options?: RemoteJWKSCollectorOptions
28
- ) {
25
+ constructor(url: string, protected options?: RemoteJWKSCollectorOptions) {
29
26
  try {
30
27
  this.url = new URL(url);
31
28
  } catch (e) {
package/src/db/mongo.ts CHANGED
@@ -2,6 +2,7 @@ import * as mongo from 'mongodb';
2
2
  import * as timers from 'timers/promises';
3
3
 
4
4
  import { configFile } from '@powersync/service-types';
5
+ import { normalizeMongoConfig } from '../storage/storage-index.js';
5
6
 
6
7
  /**
7
8
  * Time for new connection to timeout.
@@ -23,10 +24,11 @@ export const MONGO_SOCKET_TIMEOUT_MS = 60_000;
23
24
  export const MONGO_OPERATION_TIMEOUT_MS = 30_000;
24
25
 
25
26
  export function createMongoClient(config: configFile.PowerSyncConfig['storage']) {
26
- return new mongo.MongoClient(config.uri, {
27
+ const normalized = normalizeMongoConfig(config);
28
+ return new mongo.MongoClient(normalized.uri, {
27
29
  auth: {
28
- username: config.username,
29
- password: config.password
30
+ username: normalized.username,
31
+ password: normalized.password
30
32
  },
31
33
  // Time for connection to timeout
32
34
  connectTimeoutMS: MONGO_CONNECT_TIMEOUT_MS,
@@ -339,6 +339,11 @@ export interface BucketStorageBatch {
339
339
  */
340
340
  keepalive(lsn: string): Promise<boolean>;
341
341
 
342
+ /**
343
+ * Get the last checkpoint LSN, from either commit or keepalive.
344
+ */
345
+ lastCheckpointLsn: string | null;
346
+
342
347
  markSnapshotDone(tables: SourceTable[], no_checkpoint_before_lsn: string): Promise<SourceTable[]>;
343
348
  }
344
349
 
@@ -7,7 +7,7 @@ import * as util from '../../util/util-index.js';
7
7
  import { BucketStorageBatch, FlushedResult, mergeToast, SaveOptions } from '../BucketStorage.js';
8
8
  import { SourceTable } from '../SourceTable.js';
9
9
  import { PowerSyncMongo } from './db.js';
10
- import { CurrentBucket, CurrentDataDocument, SourceKey } from './models.js';
10
+ import { CurrentBucket, CurrentDataDocument, SourceKey, SyncRuleDocument } from './models.js';
11
11
  import { MongoIdSequence } from './MongoIdSequence.js';
12
12
  import { cacheKey, OperationBatch, RecordOperation } from './OperationBatch.js';
13
13
  import { PersistedBatch } from './PersistedBatch.js';
@@ -73,6 +73,10 @@ export class MongoBucketBatch implements BucketStorageBatch {
73
73
  this.no_checkpoint_before_lsn = no_checkpoint_before_lsn;
74
74
  }
75
75
 
76
+ get lastCheckpointLsn() {
77
+ return this.last_checkpoint_lsn;
78
+ }
79
+
76
80
  async flush(): Promise<FlushedResult | null> {
77
81
  let result: FlushedResult | null = null;
78
82
  // One flush may be split over multiple transactions.
@@ -535,7 +539,7 @@ export class MongoBucketBatch implements BucketStorageBatch {
535
539
  async commit(lsn: string): Promise<boolean> {
536
540
  await this.flush();
537
541
 
538
- if (this.last_checkpoint_lsn != null && lsn <= this.last_checkpoint_lsn) {
542
+ if (this.last_checkpoint_lsn != null && lsn < this.last_checkpoint_lsn) {
539
543
  // When re-applying transactions, don't create a new checkpoint until
540
544
  // we are past the last transaction.
541
545
  logger.info(`Re-applied transaction ${lsn} - skipping checkpoint`);
@@ -58,11 +58,7 @@ export class MongoCompactor {
58
58
  private maxOpId: bigint | undefined;
59
59
  private buckets: string[] | undefined;
60
60
 
61
- constructor(
62
- private db: PowerSyncMongo,
63
- private group_id: number,
64
- options?: MongoCompactOptions
65
- ) {
61
+ constructor(private db: PowerSyncMongo, private group_id: number, options?: MongoCompactOptions) {
66
62
  this.idLimitBytes = (options?.memoryLimitMB ?? DEFAULT_MEMORY_LIMIT_MB) * 1024 * 1024;
67
63
  this.moveBatchLimit = options?.moveBatchLimit ?? DEFAULT_MOVE_BATCH_LIMIT;
68
64
  this.moveBatchQueryLimit = options?.moveBatchQueryLimit ?? DEFAULT_MOVE_BATCH_QUERY_LIMIT;
@@ -19,10 +19,7 @@ export class MongoPersistedSyncRulesContent implements PersistedSyncRulesContent
19
19
 
20
20
  public current_lock: MongoSyncRulesLock | null = null;
21
21
 
22
- constructor(
23
- private db: PowerSyncMongo,
24
- doc: mongo.WithId<SyncRuleDocument>
25
- ) {
22
+ constructor(private db: PowerSyncMongo, doc: mongo.WithId<SyncRuleDocument>) {
26
23
  this.id = doc._id;
27
24
  this.sync_rules_content = doc.content;
28
25
  this.last_checkpoint_lsn = doc.last_checkpoint_lsn;
@@ -9,7 +9,7 @@ import { logger } from '@powersync/lib-services-framework';
9
9
  * replicates those sync rules at a time.
10
10
  */
11
11
  export class MongoSyncRulesLock implements ReplicationLock {
12
- private readonly refreshInterval: NodeJS.Timeout;
12
+ private readonly refreshInterval: NodeJS.Timer;
13
13
 
14
14
  static async createLock(db: PowerSyncMongo, sync_rules: PersistedSyncRulesContent): Promise<MongoSyncRulesLock> {
15
15
  const lockId = crypto.randomBytes(8).toString('hex');
@@ -35,11 +35,7 @@ export class MongoSyncRulesLock implements ReplicationLock {
35
35
  return new MongoSyncRulesLock(db, sync_rules.id, lockId);
36
36
  }
37
37
 
38
- constructor(
39
- private db: PowerSyncMongo,
40
- public sync_rules_id: number,
41
- private lock_id: string
42
- ) {
38
+ constructor(private db: PowerSyncMongo, public sync_rules_id: number, private lock_id: string) {
43
39
  this.refreshInterval = setInterval(async () => {
44
40
  try {
45
41
  await this.refresh();
@@ -54,10 +54,7 @@ export class PersistedBatch {
54
54
  */
55
55
  currentSize = 0;
56
56
 
57
- constructor(
58
- private group_id: number,
59
- writtenSize: number
60
- ) {
57
+ constructor(private group_id: number, writtenSize: number) {
61
58
  this.currentSize = writtenSize;
62
59
  }
63
60
 
@@ -0,0 +1,40 @@
1
+ import * as urijs from 'uri-js';
2
+
3
+ export interface MongoConnectionConfig {
4
+ uri: string;
5
+ username?: string;
6
+ password?: string;
7
+ database?: string;
8
+ }
9
+
10
+ /**
11
+ * Validate and normalize connection options.
12
+ *
13
+ * Returns destructured options.
14
+ *
15
+ * For use by both storage and mongo module.
16
+ */
17
+ export function normalizeMongoConfig(options: MongoConnectionConfig) {
18
+ let uri = urijs.parse(options.uri);
19
+
20
+ const database = options.database ?? uri.path?.substring(1) ?? '';
21
+
22
+ const userInfo = uri.userinfo?.split(':');
23
+
24
+ const username = options.username ?? userInfo?.[0];
25
+ const password = options.password ?? userInfo?.[1];
26
+
27
+ if (database == '') {
28
+ throw new Error(`database required`);
29
+ }
30
+
31
+ delete uri.userinfo;
32
+
33
+ return {
34
+ uri: urijs.serialize(uri),
35
+ database,
36
+
37
+ username,
38
+ password
39
+ };
40
+ }
@@ -16,3 +16,4 @@ export * from './mongo/MongoSyncRulesLock.js';
16
16
  export * from './mongo/OperationBatch.js';
17
17
  export * from './mongo/PersistedBatch.js';
18
18
  export * from './mongo/util.js';
19
+ export * from './mongo/config.js';
@@ -56,7 +56,7 @@ exports[`sync - mongodb > compacting data - invalidate checkpoint 2`] = `
56
56
  "data": [
57
57
  {
58
58
  "checksum": 1859363232n,
59
- "data": "{"id":"t1","description":"Test 1b"}",
59
+ "data": "{\\"id\\":\\"t1\\",\\"description\\":\\"Test 1b\\"}",
60
60
  "object_id": "t1",
61
61
  "object_type": "test",
62
62
  "op": "PUT",
@@ -65,7 +65,7 @@ exports[`sync - mongodb > compacting data - invalidate checkpoint 2`] = `
65
65
  },
66
66
  {
67
67
  "checksum": 3028503153n,
68
- "data": "{"id":"t2","description":"Test 2b"}",
68
+ "data": "{\\"id\\":\\"t2\\",\\"description\\":\\"Test 2b\\"}",
69
69
  "object_id": "t2",
70
70
  "object_type": "test",
71
71
  "op": "PUT",
@@ -146,7 +146,7 @@ exports[`sync - mongodb > sync global data 1`] = `
146
146
  "data": [
147
147
  {
148
148
  "checksum": 920318466n,
149
- "data": "{"id":"t1","description":"Test 1"}",
149
+ "data": "{\\"id\\":\\"t1\\",\\"description\\":\\"Test 1\\"}",
150
150
  "object_id": "t1",
151
151
  "object_type": "test",
152
152
  "op": "PUT",
@@ -155,7 +155,7 @@ exports[`sync - mongodb > sync global data 1`] = `
155
155
  },
156
156
  {
157
157
  "checksum": 3280762209n,
158
- "data": "{"id":"t2","description":"Test 2"}",
158
+ "data": "{\\"id\\":\\"t2\\",\\"description\\":\\"Test 2\\"}",
159
159
  "object_id": "t2",
160
160
  "object_type": "test",
161
161
  "op": "PUT",
@@ -199,7 +199,7 @@ exports[`sync - mongodb > sync legacy non-raw data 1`] = `
199
199
  "checksum": 3442149460n,
200
200
  "data": {
201
201
  "description": "Test
202
- "string"",
202
+ \\"string\\"",
203
203
  "id": "t1",
204
204
  "large_num": 12345678901234567890n,
205
205
  },
@@ -268,7 +268,7 @@ exports[`sync - mongodb > sync updates to global data 2`] = `
268
268
  "data": [
269
269
  {
270
270
  "checksum": 920318466n,
271
- "data": "{"id":"t1","description":"Test 1"}",
271
+ "data": "{\\"id\\":\\"t1\\",\\"description\\":\\"Test 1\\"}",
272
272
  "object_id": "t1",
273
273
  "object_type": "test",
274
274
  "op": "PUT",
@@ -311,7 +311,7 @@ exports[`sync - mongodb > sync updates to global data 3`] = `
311
311
  "data": [
312
312
  {
313
313
  "checksum": 3280762209n,
314
- "data": "{"id":"t2","description":"Test 2"}",
314
+ "data": "{\\"id\\":\\"t2\\",\\"description\\":\\"Test 2\\"}",
315
315
  "object_id": "t2",
316
316
  "object_type": "test",
317
317
  "op": "PUT",