@powersync/service-core 0.0.0-dev-20240718134716 → 0.0.0-dev-20240918082156

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 (352) hide show
  1. package/CHANGELOG.md +89 -6
  2. package/dist/api/RouteAPI.d.ts +68 -0
  3. package/dist/api/RouteAPI.js +2 -0
  4. package/dist/api/RouteAPI.js.map +1 -0
  5. package/dist/api/api-index.d.ts +1 -0
  6. package/dist/api/api-index.js +1 -0
  7. package/dist/api/api-index.js.map +1 -1
  8. package/dist/api/diagnostics.d.ts +4 -4
  9. package/dist/api/diagnostics.js +11 -65
  10. package/dist/api/diagnostics.js.map +1 -1
  11. package/dist/api/schema.d.ts +3 -5
  12. package/dist/api/schema.js +9 -79
  13. package/dist/api/schema.js.map +1 -1
  14. package/dist/auth/KeyStore.d.ts +7 -4
  15. package/dist/auth/KeyStore.js +1 -1
  16. package/dist/auth/KeyStore.js.map +1 -1
  17. package/dist/auth/auth-index.d.ts +0 -1
  18. package/dist/auth/auth-index.js +0 -1
  19. package/dist/auth/auth-index.js.map +1 -1
  20. package/dist/entry/cli-entry.js +4 -2
  21. package/dist/entry/cli-entry.js.map +1 -1
  22. package/dist/entry/commands/compact-action.d.ts +2 -0
  23. package/dist/entry/commands/compact-action.js +52 -0
  24. package/dist/entry/commands/compact-action.js.map +1 -0
  25. package/dist/entry/commands/migrate-action.js +4 -5
  26. package/dist/entry/commands/migrate-action.js.map +1 -1
  27. package/dist/entry/commands/teardown-action.js +2 -2
  28. package/dist/entry/commands/teardown-action.js.map +1 -1
  29. package/dist/entry/entry-index.d.ts +1 -0
  30. package/dist/entry/entry-index.js +1 -0
  31. package/dist/entry/entry-index.js.map +1 -1
  32. package/dist/index.d.ts +4 -2
  33. package/dist/index.js +4 -2
  34. package/dist/index.js.map +1 -1
  35. package/dist/metrics/Metrics.d.ts +6 -5
  36. package/dist/metrics/Metrics.js +53 -10
  37. package/dist/metrics/Metrics.js.map +1 -1
  38. package/dist/migrations/db/migrations/1684951997326-init.d.ts +2 -2
  39. package/dist/migrations/db/migrations/1684951997326-init.js +4 -2
  40. package/dist/migrations/db/migrations/1684951997326-init.js.map +1 -1
  41. package/dist/migrations/db/migrations/1702295701188-sync-rule-state.d.ts +2 -2
  42. package/dist/migrations/db/migrations/1702295701188-sync-rule-state.js +4 -2
  43. package/dist/migrations/db/migrations/1702295701188-sync-rule-state.js.map +1 -1
  44. package/dist/migrations/db/migrations/1711543888062-write-checkpoint-index.d.ts +2 -2
  45. package/dist/migrations/db/migrations/1711543888062-write-checkpoint-index.js +4 -2
  46. package/dist/migrations/db/migrations/1711543888062-write-checkpoint-index.js.map +1 -1
  47. package/dist/migrations/migrations.d.ts +8 -0
  48. package/dist/migrations/migrations.js +19 -7
  49. package/dist/migrations/migrations.js.map +1 -1
  50. package/dist/modules/AbstractModule.d.ts +26 -0
  51. package/dist/modules/AbstractModule.js +11 -0
  52. package/dist/modules/AbstractModule.js.map +1 -0
  53. package/dist/modules/ModuleManager.d.ts +11 -0
  54. package/dist/modules/ModuleManager.js +32 -0
  55. package/dist/modules/ModuleManager.js.map +1 -0
  56. package/dist/modules/modules-index.d.ts +2 -0
  57. package/dist/modules/modules-index.js +3 -0
  58. package/dist/modules/modules-index.js.map +1 -0
  59. package/dist/replication/AbstractReplicationJob.d.ts +38 -0
  60. package/dist/replication/AbstractReplicationJob.js +51 -0
  61. package/dist/replication/AbstractReplicationJob.js.map +1 -0
  62. package/dist/replication/AbstractReplicator.d.ts +53 -0
  63. package/dist/replication/AbstractReplicator.js +187 -0
  64. package/dist/replication/AbstractReplicator.js.map +1 -0
  65. package/dist/replication/ErrorRateLimiter.d.ts +0 -9
  66. package/dist/replication/ErrorRateLimiter.js +1 -42
  67. package/dist/replication/ErrorRateLimiter.js.map +1 -1
  68. package/dist/replication/ReplicationEngine.d.ts +18 -0
  69. package/dist/replication/ReplicationEngine.js +41 -0
  70. package/dist/replication/ReplicationEngine.js.map +1 -0
  71. package/dist/replication/ReplicationModule.d.ts +39 -0
  72. package/dist/replication/ReplicationModule.js +65 -0
  73. package/dist/replication/ReplicationModule.js.map +1 -0
  74. package/dist/replication/replication-index.d.ts +4 -6
  75. package/dist/replication/replication-index.js +4 -6
  76. package/dist/replication/replication-index.js.map +1 -1
  77. package/dist/routes/RouterEngine.d.ts +42 -0
  78. package/dist/routes/RouterEngine.js +80 -0
  79. package/dist/routes/RouterEngine.js.map +1 -0
  80. package/dist/routes/auth.d.ts +2 -2
  81. package/dist/routes/auth.js +11 -11
  82. package/dist/routes/auth.js.map +1 -1
  83. package/dist/routes/configure-fastify.d.ts +737 -0
  84. package/dist/routes/configure-fastify.js +57 -0
  85. package/dist/routes/configure-fastify.js.map +1 -0
  86. package/dist/routes/configure-rsocket.d.ts +13 -0
  87. package/dist/routes/configure-rsocket.js +47 -0
  88. package/dist/routes/configure-rsocket.js.map +1 -0
  89. package/dist/routes/endpoints/admin.d.ts +0 -34
  90. package/dist/routes/endpoints/admin.js +48 -89
  91. package/dist/routes/endpoints/admin.js.map +1 -1
  92. package/dist/routes/endpoints/checkpointing.d.ts +56 -16
  93. package/dist/routes/endpoints/checkpointing.js +33 -12
  94. package/dist/routes/endpoints/checkpointing.js.map +1 -1
  95. package/dist/routes/endpoints/route-endpoints-index.d.ts +0 -1
  96. package/dist/routes/endpoints/route-endpoints-index.js +0 -1
  97. package/dist/routes/endpoints/route-endpoints-index.js.map +1 -1
  98. package/dist/routes/endpoints/socket-route.js +46 -39
  99. package/dist/routes/endpoints/socket-route.js.map +1 -1
  100. package/dist/routes/endpoints/sync-rules.d.ts +1 -1
  101. package/dist/routes/endpoints/sync-rules.js +32 -23
  102. package/dist/routes/endpoints/sync-rules.js.map +1 -1
  103. package/dist/routes/endpoints/sync-stream.d.ts +10 -0
  104. package/dist/routes/endpoints/sync-stream.js +17 -13
  105. package/dist/routes/endpoints/sync-stream.js.map +1 -1
  106. package/dist/routes/route-register.d.ts +1 -1
  107. package/dist/routes/route-register.js +1 -1
  108. package/dist/routes/route-register.js.map +1 -1
  109. package/dist/routes/router-socket.d.ts +5 -4
  110. package/dist/routes/router-socket.js +2 -1
  111. package/dist/routes/router-socket.js.map +1 -1
  112. package/dist/routes/router.d.ts +7 -2
  113. package/dist/routes/router.js.map +1 -1
  114. package/dist/routes/routes-index.d.ts +3 -0
  115. package/dist/routes/routes-index.js +3 -0
  116. package/dist/routes/routes-index.js.map +1 -1
  117. package/dist/runner/teardown.js +47 -76
  118. package/dist/runner/teardown.js.map +1 -1
  119. package/dist/storage/BucketStorage.d.ts +61 -20
  120. package/dist/storage/BucketStorage.js +0 -10
  121. package/dist/storage/BucketStorage.js.map +1 -1
  122. package/dist/storage/MongoBucketStorage.d.ts +4 -4
  123. package/dist/storage/MongoBucketStorage.js +19 -24
  124. package/dist/storage/MongoBucketStorage.js.map +1 -1
  125. package/dist/storage/SourceEntity.d.ts +20 -0
  126. package/dist/storage/SourceEntity.js +2 -0
  127. package/dist/storage/SourceEntity.js.map +1 -0
  128. package/dist/storage/SourceTable.d.ts +4 -5
  129. package/dist/storage/SourceTable.js +3 -4
  130. package/dist/storage/SourceTable.js.map +1 -1
  131. package/dist/storage/StorageEngine.d.ts +24 -0
  132. package/dist/storage/StorageEngine.js +43 -0
  133. package/dist/storage/StorageEngine.js.map +1 -0
  134. package/dist/storage/StorageProvider.d.ts +21 -0
  135. package/dist/storage/StorageProvider.js +2 -0
  136. package/dist/storage/StorageProvider.js.map +1 -0
  137. package/dist/storage/mongo/MongoBucketBatch.d.ts +1 -1
  138. package/dist/storage/mongo/MongoBucketBatch.js +6 -7
  139. package/dist/storage/mongo/MongoBucketBatch.js.map +1 -1
  140. package/dist/storage/mongo/MongoCompactor.d.ts +40 -0
  141. package/dist/storage/mongo/MongoCompactor.js +293 -0
  142. package/dist/storage/mongo/MongoCompactor.js.map +1 -0
  143. package/dist/storage/mongo/MongoPersistedSyncRulesContent.d.ts +2 -2
  144. package/dist/storage/mongo/MongoPersistedSyncRulesContent.js +2 -2
  145. package/dist/storage/mongo/MongoPersistedSyncRulesContent.js.map +1 -1
  146. package/dist/storage/mongo/MongoStorageProvider.d.ts +5 -0
  147. package/dist/storage/mongo/MongoStorageProvider.js +26 -0
  148. package/dist/storage/mongo/MongoStorageProvider.js.map +1 -0
  149. package/dist/storage/mongo/MongoSyncBucketStorage.d.ts +9 -7
  150. package/dist/storage/mongo/MongoSyncBucketStorage.js +43 -28
  151. package/dist/storage/mongo/MongoSyncBucketStorage.js.map +1 -1
  152. package/dist/storage/mongo/MongoSyncRulesLock.js +1 -1
  153. package/dist/storage/mongo/MongoSyncRulesLock.js.map +1 -1
  154. package/dist/storage/mongo/OperationBatch.d.ts +7 -3
  155. package/dist/storage/mongo/OperationBatch.js +16 -7
  156. package/dist/storage/mongo/OperationBatch.js.map +1 -1
  157. package/dist/storage/mongo/PersistedBatch.d.ts +3 -3
  158. package/dist/storage/mongo/PersistedBatch.js +2 -2
  159. package/dist/storage/mongo/PersistedBatch.js.map +1 -1
  160. package/dist/storage/mongo/models.d.ts +17 -7
  161. package/dist/storage/mongo/models.js.map +1 -1
  162. package/dist/storage/mongo/util.d.ts +14 -0
  163. package/dist/storage/mongo/util.js +70 -0
  164. package/dist/storage/mongo/util.js.map +1 -1
  165. package/dist/storage/storage-index.d.ts +5 -2
  166. package/dist/storage/storage-index.js +5 -2
  167. package/dist/storage/storage-index.js.map +1 -1
  168. package/dist/sync/RequestTracker.js +2 -3
  169. package/dist/sync/RequestTracker.js.map +1 -1
  170. package/dist/sync/sync-index.d.ts +1 -0
  171. package/dist/sync/sync-index.js +1 -0
  172. package/dist/sync/sync-index.js.map +1 -1
  173. package/dist/sync/sync.d.ts +2 -1
  174. package/dist/sync/sync.js +56 -17
  175. package/dist/sync/sync.js.map +1 -1
  176. package/dist/system/ServiceContext.d.ts +37 -0
  177. package/dist/system/ServiceContext.js +48 -0
  178. package/dist/system/ServiceContext.js.map +1 -0
  179. package/dist/system/system-index.d.ts +1 -1
  180. package/dist/system/system-index.js +1 -1
  181. package/dist/system/system-index.js.map +1 -1
  182. package/dist/util/config/collectors/config-collector.d.ts +12 -0
  183. package/dist/util/config/collectors/config-collector.js +43 -0
  184. package/dist/util/config/collectors/config-collector.js.map +1 -1
  185. package/dist/util/config/compound-config-collector.d.ts +10 -29
  186. package/dist/util/config/compound-config-collector.js +28 -84
  187. package/dist/util/config/compound-config-collector.js.map +1 -1
  188. package/dist/util/config/sync-rules/sync-rules-provider.d.ts +9 -0
  189. package/dist/util/config/sync-rules/sync-rules-provider.js +15 -0
  190. package/dist/util/config/sync-rules/sync-rules-provider.js.map +1 -0
  191. package/dist/util/config/types.d.ts +6 -4
  192. package/dist/util/config/types.js.map +1 -1
  193. package/dist/util/config.d.ts +3 -4
  194. package/dist/util/config.js +5 -20
  195. package/dist/util/config.js.map +1 -1
  196. package/dist/util/protocol-types.d.ts +4 -0
  197. package/dist/util/protocol-types.js +5 -1
  198. package/dist/util/protocol-types.js.map +1 -1
  199. package/dist/util/util-index.d.ts +3 -6
  200. package/dist/util/util-index.js +3 -6
  201. package/dist/util/util-index.js.map +1 -1
  202. package/dist/util/utils.d.ts +10 -6
  203. package/dist/util/utils.js +45 -25
  204. package/dist/util/utils.js.map +1 -1
  205. package/package.json +7 -7
  206. package/src/api/RouteAPI.ts +78 -0
  207. package/src/api/api-index.ts +1 -0
  208. package/src/api/diagnostics.ts +16 -71
  209. package/src/api/schema.ts +13 -89
  210. package/src/auth/KeyStore.ts +9 -6
  211. package/src/auth/auth-index.ts +0 -1
  212. package/src/entry/cli-entry.ts +4 -2
  213. package/src/entry/commands/compact-action.ts +57 -0
  214. package/src/entry/commands/migrate-action.ts +5 -8
  215. package/src/entry/commands/teardown-action.ts +2 -2
  216. package/src/entry/entry-index.ts +1 -0
  217. package/src/index.ts +5 -2
  218. package/src/metrics/Metrics.ts +70 -15
  219. package/src/migrations/db/migrations/1684951997326-init.ts +9 -4
  220. package/src/migrations/db/migrations/1702295701188-sync-rule-state.ts +7 -4
  221. package/src/migrations/db/migrations/1711543888062-write-checkpoint-index.ts +6 -4
  222. package/src/migrations/migrations.ts +24 -8
  223. package/src/modules/AbstractModule.ts +37 -0
  224. package/src/modules/ModuleManager.ts +34 -0
  225. package/src/modules/modules-index.ts +2 -0
  226. package/src/replication/AbstractReplicationJob.ts +79 -0
  227. package/src/replication/AbstractReplicator.ts +227 -0
  228. package/src/replication/ErrorRateLimiter.ts +0 -44
  229. package/src/replication/ReplicationEngine.ts +43 -0
  230. package/src/replication/ReplicationModule.ts +101 -0
  231. package/src/replication/replication-index.ts +4 -6
  232. package/src/routes/RouterEngine.ts +120 -0
  233. package/src/routes/auth.ts +21 -12
  234. package/src/routes/configure-fastify.ts +101 -0
  235. package/src/routes/configure-rsocket.ts +60 -0
  236. package/src/routes/endpoints/admin.ts +74 -100
  237. package/src/routes/endpoints/checkpointing.ts +46 -12
  238. package/src/routes/endpoints/route-endpoints-index.ts +0 -1
  239. package/src/routes/endpoints/socket-route.ts +50 -42
  240. package/src/routes/endpoints/sync-rules.ts +41 -25
  241. package/src/routes/endpoints/sync-stream.ts +17 -13
  242. package/src/routes/route-register.ts +2 -2
  243. package/src/routes/router-socket.ts +6 -5
  244. package/src/routes/router.ts +7 -2
  245. package/src/routes/routes-index.ts +3 -0
  246. package/src/runner/teardown.ts +50 -88
  247. package/src/storage/BucketStorage.ts +74 -26
  248. package/src/storage/MongoBucketStorage.ts +23 -26
  249. package/src/storage/SourceEntity.ts +22 -0
  250. package/src/storage/SourceTable.ts +4 -6
  251. package/src/storage/StorageEngine.ts +55 -0
  252. package/src/storage/StorageProvider.ts +27 -0
  253. package/src/storage/mongo/MongoBucketBatch.ts +8 -8
  254. package/src/storage/mongo/MongoCompactor.ts +372 -0
  255. package/src/storage/mongo/MongoPersistedSyncRulesContent.ts +3 -3
  256. package/src/storage/mongo/MongoStorageProvider.ts +31 -0
  257. package/src/storage/mongo/MongoSyncBucketStorage.ts +64 -34
  258. package/src/storage/mongo/MongoSyncRulesLock.ts +1 -1
  259. package/src/storage/mongo/OperationBatch.ts +18 -11
  260. package/src/storage/mongo/PersistedBatch.ts +6 -5
  261. package/src/storage/mongo/models.ts +17 -7
  262. package/src/storage/mongo/util.ts +71 -1
  263. package/src/storage/storage-index.ts +5 -2
  264. package/src/sync/RequestTracker.ts +3 -3
  265. package/src/sync/sync-index.ts +1 -0
  266. package/src/sync/sync.ts +66 -17
  267. package/src/system/ServiceContext.ts +68 -0
  268. package/src/system/system-index.ts +1 -1
  269. package/src/util/config/collectors/config-collector.ts +48 -0
  270. package/src/util/config/compound-config-collector.ts +45 -110
  271. package/src/util/config/sync-rules/sync-rules-provider.ts +18 -0
  272. package/src/util/config/types.ts +6 -5
  273. package/src/util/config.ts +6 -23
  274. package/src/util/protocol-types.ts +6 -1
  275. package/src/util/util-index.ts +3 -6
  276. package/src/util/utils.ts +55 -39
  277. package/test/src/__snapshots__/sync.test.ts.snap +90 -5
  278. package/test/src/auth.test.ts +7 -7
  279. package/test/src/broadcast_iterable.test.ts +1 -1
  280. package/test/src/bucket_validation.test.ts +142 -0
  281. package/test/src/bucket_validation.ts +116 -0
  282. package/test/src/checksum_cache.test.ts +3 -3
  283. package/test/src/compacting.test.ts +216 -0
  284. package/test/src/data_storage.test.ts +275 -204
  285. package/test/src/env.ts +1 -3
  286. package/test/src/merge_iterable.test.ts +1 -6
  287. package/test/src/setup.ts +1 -1
  288. package/test/src/stream_utils.ts +42 -0
  289. package/test/src/sync.test.ts +209 -48
  290. package/test/src/util.ts +110 -55
  291. package/test/tsconfig.json +1 -1
  292. package/tsconfig.tsbuildinfo +1 -1
  293. package/dist/auth/SupabaseKeyCollector.d.ts +0 -22
  294. package/dist/auth/SupabaseKeyCollector.js +0 -61
  295. package/dist/auth/SupabaseKeyCollector.js.map +0 -1
  296. package/dist/replication/PgRelation.d.ts +0 -16
  297. package/dist/replication/PgRelation.js +0 -26
  298. package/dist/replication/PgRelation.js.map +0 -1
  299. package/dist/replication/WalConnection.d.ts +0 -34
  300. package/dist/replication/WalConnection.js +0 -190
  301. package/dist/replication/WalConnection.js.map +0 -1
  302. package/dist/replication/WalStream.d.ts +0 -57
  303. package/dist/replication/WalStream.js +0 -517
  304. package/dist/replication/WalStream.js.map +0 -1
  305. package/dist/replication/WalStreamManager.d.ts +0 -30
  306. package/dist/replication/WalStreamManager.js +0 -198
  307. package/dist/replication/WalStreamManager.js.map +0 -1
  308. package/dist/replication/WalStreamRunner.d.ts +0 -38
  309. package/dist/replication/WalStreamRunner.js +0 -155
  310. package/dist/replication/WalStreamRunner.js.map +0 -1
  311. package/dist/replication/util.d.ts +0 -9
  312. package/dist/replication/util.js +0 -62
  313. package/dist/replication/util.js.map +0 -1
  314. package/dist/routes/endpoints/dev.d.ts +0 -312
  315. package/dist/routes/endpoints/dev.js +0 -172
  316. package/dist/routes/endpoints/dev.js.map +0 -1
  317. package/dist/system/CorePowerSyncSystem.d.ts +0 -23
  318. package/dist/system/CorePowerSyncSystem.js +0 -52
  319. package/dist/system/CorePowerSyncSystem.js.map +0 -1
  320. package/dist/util/PgManager.d.ts +0 -24
  321. package/dist/util/PgManager.js +0 -55
  322. package/dist/util/PgManager.js.map +0 -1
  323. package/dist/util/migration_lib.d.ts +0 -11
  324. package/dist/util/migration_lib.js +0 -64
  325. package/dist/util/migration_lib.js.map +0 -1
  326. package/dist/util/pgwire_utils.d.ts +0 -24
  327. package/dist/util/pgwire_utils.js +0 -117
  328. package/dist/util/pgwire_utils.js.map +0 -1
  329. package/dist/util/populate_test_data.d.ts +0 -8
  330. package/dist/util/populate_test_data.js +0 -65
  331. package/dist/util/populate_test_data.js.map +0 -1
  332. package/src/auth/SupabaseKeyCollector.ts +0 -67
  333. package/src/replication/PgRelation.ts +0 -42
  334. package/src/replication/WalConnection.ts +0 -227
  335. package/src/replication/WalStream.ts +0 -628
  336. package/src/replication/WalStreamManager.ts +0 -213
  337. package/src/replication/WalStreamRunner.ts +0 -180
  338. package/src/replication/util.ts +0 -76
  339. package/src/routes/endpoints/dev.ts +0 -199
  340. package/src/system/CorePowerSyncSystem.ts +0 -64
  341. package/src/util/PgManager.ts +0 -64
  342. package/src/util/migration_lib.ts +0 -79
  343. package/src/util/pgwire_utils.ts +0 -139
  344. package/src/util/populate_test_data.ts +0 -78
  345. package/test/src/__snapshots__/pg_test.test.ts.snap +0 -256
  346. package/test/src/large_batch.test.ts +0 -194
  347. package/test/src/pg_test.test.ts +0 -450
  348. package/test/src/schema_changes.test.ts +0 -545
  349. package/test/src/slow_tests.test.ts +0 -296
  350. package/test/src/validation.test.ts +0 -63
  351. package/test/src/wal_stream.test.ts +0 -314
  352. package/test/src/wal_stream_utils.ts +0 -147
package/test/src/env.ts CHANGED
@@ -2,7 +2,5 @@ import { utils } from '@powersync/lib-services-framework';
2
2
 
3
3
  export const env = utils.collectEnvironmentVariables({
4
4
  MONGO_TEST_URL: utils.type.string.default('mongodb://localhost:27017/powersync_test'),
5
- PG_TEST_URL: utils.type.string.default('postgres://postgres:postgres@localhost:5432/powersync_test'),
6
- CI: utils.type.boolean.default('false'),
7
- SLOW_TESTS: utils.type.boolean.default('false')
5
+ CI: utils.type.boolean.default('false')
8
6
  });
@@ -1,11 +1,6 @@
1
+ import { mergeAsyncIterablesNew, mergeAsyncIterablesOld } from '@/sync/merge.js';
1
2
  import * as timers from 'timers/promises';
2
3
  import { describe, expect, test } from 'vitest';
3
- import {
4
- FixedMergeAsyncIterable,
5
- mergeAsyncIterables,
6
- mergeAsyncIterablesNew,
7
- mergeAsyncIterablesOld
8
- } from '../../src/sync/merge.js';
9
4
 
10
5
  type MergeIteratorFunction = <T>(source: AsyncIterable<T>[]) => AsyncIterable<T>;
11
6
 
package/test/src/setup.ts CHANGED
@@ -2,6 +2,6 @@ import { container } from '@powersync/lib-services-framework';
2
2
  import { beforeAll } from 'vitest';
3
3
 
4
4
  beforeAll(() => {
5
- // Your setup code here
5
+ // Executes for every test file
6
6
  container.registerDefaults();
7
7
  });
@@ -0,0 +1,42 @@
1
+ import { OplogEntry } from '@/util/protocol-types.js';
2
+ import { JSONBig } from '@powersync/service-jsonbig';
3
+
4
+ export function putOp(table: string, data: Record<string, any>): Partial<OplogEntry> {
5
+ return {
6
+ op: 'PUT',
7
+ object_type: table,
8
+ object_id: data.id,
9
+ data: JSONBig.stringify(data)
10
+ };
11
+ }
12
+
13
+ export function removeOp(table: string, id: string): Partial<OplogEntry> {
14
+ return {
15
+ op: 'REMOVE',
16
+ object_type: table,
17
+ object_id: id
18
+ };
19
+ }
20
+
21
+ export function compareIds(a: OplogEntry, b: OplogEntry) {
22
+ return a.object_id!.localeCompare(b.object_id!);
23
+ }
24
+
25
+ export async function oneFromAsync<T>(source: Iterable<T> | AsyncIterable<T>): Promise<T> {
26
+ const items: T[] = [];
27
+ for await (const item of source) {
28
+ items.push(item);
29
+ }
30
+ if (items.length != 1) {
31
+ throw new Error(`One item expected, got: ${items.length}`);
32
+ }
33
+ return items[0];
34
+ }
35
+
36
+ export async function fromAsync<T>(source: Iterable<T> | AsyncIterable<T>): Promise<T[]> {
37
+ const items: T[] = [];
38
+ for await (const item of source) {
39
+ items.push(item);
40
+ }
41
+ return items;
42
+ }
@@ -1,34 +1,24 @@
1
- import * as bson from 'bson';
2
- import { describe, expect, test } from 'vitest';
3
- import { ZERO_LSN } from '../../src/replication/WalStream.js';
4
- import { SourceTable } from '../../src/storage/SourceTable.js';
5
- import { hashData } from '../../src/util/utils.js';
6
- import { MONGO_STORAGE_FACTORY, StorageFactory } from './util.js';
1
+ import { RequestTracker } from '@/sync/RequestTracker.js';
2
+ import { streamResponse } from '@/sync/sync.js';
3
+ import { StreamingSyncLine } from '@/util/protocol-types.js';
7
4
  import { JSONBig } from '@powersync/service-jsonbig';
8
- import { streamResponse } from '../../src/sync/sync.js';
9
- import * as timers from 'timers/promises';
10
- import { lsnMakeComparable } from '@powersync/service-jpgwire';
11
5
  import { RequestParameters } from '@powersync/service-sync-rules';
12
- import { RequestTracker } from '@/sync/RequestTracker.js';
6
+ import * as timers from 'timers/promises';
7
+ import { describe, expect, test } from 'vitest';
8
+ import {
9
+ BATCH_OPTIONS,
10
+ makeTestTable,
11
+ MONGO_STORAGE_FACTORY,
12
+ PARSE_OPTIONS,
13
+ StorageFactory,
14
+ ZERO_LSN
15
+ } from './util.js';
16
+ import { ParseSyncRulesOptions, StartBatchOptions } from '@/storage/BucketStorage.js';
13
17
 
14
18
  describe('sync - mongodb', function () {
15
19
  defineTests(MONGO_STORAGE_FACTORY);
16
20
  });
17
21
 
18
- function makeTestTable(name: string, columns?: string[] | undefined) {
19
- const relId = hashData('table', name, (columns ?? ['id']).join(','));
20
- const id = new bson.ObjectId('6544e3899293153fa7b38331');
21
- return new SourceTable(
22
- id,
23
- SourceTable.DEFAULT_TAG,
24
- relId,
25
- SourceTable.DEFAULT_SCHEMA,
26
- name,
27
- (columns ?? ['id']).map((column) => ({ name: column, typeOid: 25 })),
28
- true
29
- );
30
- }
31
-
32
22
  const TEST_TABLE = makeTestTable('test', ['id']);
33
23
 
34
24
  const BASIC_SYNC_RULES = `
@@ -48,18 +38,19 @@ function defineTests(factory: StorageFactory) {
48
38
  content: BASIC_SYNC_RULES
49
39
  });
50
40
 
51
- const storage = await f.getInstance(syncRules.parsed());
41
+ const storage = await f.getInstance(syncRules);
52
42
  await storage.setSnapshotDone(ZERO_LSN);
53
43
  await storage.autoActivate();
54
44
 
55
- const result = await storage.startBatch({}, async (batch) => {
45
+ const result = await storage.startBatch(BATCH_OPTIONS, async (batch) => {
56
46
  await batch.save({
57
47
  sourceTable: TEST_TABLE,
58
48
  tag: 'insert',
59
49
  after: {
60
50
  id: 't1',
61
51
  description: 'Test 1'
62
- }
52
+ },
53
+ afterReplicaId: 't1'
63
54
  });
64
55
 
65
56
  await batch.save({
@@ -68,10 +59,11 @@ function defineTests(factory: StorageFactory) {
68
59
  after: {
69
60
  id: 't2',
70
61
  description: 'Test 2'
71
- }
62
+ },
63
+ afterReplicaId: 't2'
72
64
  });
73
65
 
74
- await batch.commit(lsnMakeComparable('0/1'));
66
+ await batch.commit('0/1');
75
67
  });
76
68
 
77
69
  const stream = streamResponse({
@@ -81,6 +73,7 @@ function defineTests(factory: StorageFactory) {
81
73
  include_checksum: true,
82
74
  raw_data: true
83
75
  },
76
+ parseOptions: PARSE_OPTIONS,
84
77
  tracker,
85
78
  syncParams: new RequestParameters({ sub: '' }, {}),
86
79
  token: { exp: Date.now() / 1000 + 10 } as any
@@ -97,11 +90,11 @@ function defineTests(factory: StorageFactory) {
97
90
  content: BASIC_SYNC_RULES
98
91
  });
99
92
 
100
- const storage = await f.getInstance(syncRules.parsed());
93
+ const storage = await f.getInstance(syncRules);
101
94
  await storage.setSnapshotDone(ZERO_LSN);
102
95
  await storage.autoActivate();
103
96
 
104
- const result = await storage.startBatch({}, async (batch) => {
97
+ const result = await storage.startBatch(BATCH_OPTIONS, async (batch) => {
105
98
  await batch.save({
106
99
  sourceTable: TEST_TABLE,
107
100
  tag: 'insert',
@@ -109,10 +102,11 @@ function defineTests(factory: StorageFactory) {
109
102
  id: 't1',
110
103
  description: 'Test\n"string"',
111
104
  large_num: 12345678901234567890n
112
- }
105
+ },
106
+ afterReplicaId: 't1'
113
107
  });
114
108
 
115
- await batch.commit(lsnMakeComparable('0/1'));
109
+ await batch.commit('0/1');
116
110
  });
117
111
 
118
112
  const stream = streamResponse({
@@ -122,6 +116,7 @@ function defineTests(factory: StorageFactory) {
122
116
  include_checksum: true,
123
117
  raw_data: false
124
118
  },
119
+ parseOptions: PARSE_OPTIONS,
125
120
  tracker,
126
121
  syncParams: new RequestParameters({ sub: '' }, {}),
127
122
  token: { exp: Date.now() / 1000 + 10 } as any
@@ -140,7 +135,7 @@ function defineTests(factory: StorageFactory) {
140
135
  content: BASIC_SYNC_RULES
141
136
  });
142
137
 
143
- const storage = await f.getInstance(syncRules.parsed());
138
+ const storage = await f.getInstance(syncRules);
144
139
  await storage.setSnapshotDone(ZERO_LSN);
145
140
  await storage.autoActivate();
146
141
 
@@ -151,6 +146,7 @@ function defineTests(factory: StorageFactory) {
151
146
  include_checksum: true,
152
147
  raw_data: true
153
148
  },
149
+ parseOptions: PARSE_OPTIONS,
154
150
  tracker,
155
151
  syncParams: new RequestParameters({ sub: '' }, {}),
156
152
  token: { exp: 0 } as any
@@ -167,7 +163,7 @@ function defineTests(factory: StorageFactory) {
167
163
  content: BASIC_SYNC_RULES
168
164
  });
169
165
 
170
- const storage = await f.getInstance(syncRules.parsed());
166
+ const storage = await f.getInstance(syncRules);
171
167
  await storage.setSnapshotDone(ZERO_LSN);
172
168
  await storage.autoActivate();
173
169
 
@@ -178,6 +174,7 @@ function defineTests(factory: StorageFactory) {
178
174
  include_checksum: true,
179
175
  raw_data: true
180
176
  },
177
+ parseOptions: PARSE_OPTIONS,
181
178
  tracker,
182
179
  syncParams: new RequestParameters({ sub: '' }, {}),
183
180
  token: { exp: Date.now() / 1000 + 10 } as any
@@ -186,32 +183,34 @@ function defineTests(factory: StorageFactory) {
186
183
 
187
184
  expect(await getCheckpointLines(iter)).toMatchSnapshot();
188
185
 
189
- await storage.startBatch({}, async (batch) => {
186
+ await storage.startBatch(BATCH_OPTIONS, async (batch) => {
190
187
  await batch.save({
191
188
  sourceTable: TEST_TABLE,
192
189
  tag: 'insert',
193
190
  after: {
194
191
  id: 't1',
195
192
  description: 'Test 1'
196
- }
193
+ },
194
+ afterReplicaId: 't1'
197
195
  });
198
196
 
199
- await batch.commit(lsnMakeComparable('0/1'));
197
+ await batch.commit('0/1');
200
198
  });
201
199
 
202
200
  expect(await getCheckpointLines(iter)).toMatchSnapshot();
203
201
 
204
- await storage.startBatch({}, async (batch) => {
202
+ await storage.startBatch(BATCH_OPTIONS, async (batch) => {
205
203
  await batch.save({
206
204
  sourceTable: TEST_TABLE,
207
205
  tag: 'insert',
208
206
  after: {
209
207
  id: 't2',
210
208
  description: 'Test 2'
211
- }
209
+ },
210
+ afterReplicaId: 't2'
212
211
  });
213
212
 
214
- await batch.commit(lsnMakeComparable('0/2'));
213
+ await batch.commit('0/2');
215
214
  });
216
215
 
217
216
  expect(await getCheckpointLines(iter)).toMatchSnapshot();
@@ -226,7 +225,7 @@ function defineTests(factory: StorageFactory) {
226
225
  content: BASIC_SYNC_RULES
227
226
  });
228
227
 
229
- const storage = await f.getInstance(syncRules.parsed());
228
+ const storage = await f.getInstance(syncRules);
230
229
  await storage.setSnapshotDone(ZERO_LSN);
231
230
  await storage.autoActivate();
232
231
 
@@ -239,6 +238,7 @@ function defineTests(factory: StorageFactory) {
239
238
  include_checksum: true,
240
239
  raw_data: true
241
240
  },
241
+ parseOptions: PARSE_OPTIONS,
242
242
  tracker,
243
243
  syncParams: new RequestParameters({ sub: '' }, {}),
244
244
  token: { exp: exp } as any
@@ -251,15 +251,161 @@ function defineTests(factory: StorageFactory) {
251
251
  const expLines = await getCheckpointLines(iter);
252
252
  expect(expLines).toMatchSnapshot();
253
253
  });
254
+
255
+ test('compacting data - invalidate checkpoint', async () => {
256
+ // This tests a case of a compact operation invalidating a checkpoint in the
257
+ // middle of syncing data.
258
+ // This is expected to be rare in practice, but it is important to handle
259
+ // this case correctly to maintain consistency on the client.
260
+
261
+ const f = await factory();
262
+
263
+ const syncRules = await f.updateSyncRules({
264
+ content: BASIC_SYNC_RULES
265
+ });
266
+
267
+ const storage = await f.getInstance(syncRules);
268
+ await storage.setSnapshotDone(ZERO_LSN);
269
+ await storage.autoActivate();
270
+
271
+ await storage.startBatch(BATCH_OPTIONS, async (batch) => {
272
+ await batch.save({
273
+ sourceTable: TEST_TABLE,
274
+ tag: 'insert',
275
+ after: {
276
+ id: 't1',
277
+ description: 'Test 1'
278
+ },
279
+ afterReplicaId: 't1'
280
+ });
281
+
282
+ await batch.save({
283
+ sourceTable: TEST_TABLE,
284
+ tag: 'insert',
285
+ after: {
286
+ id: 't2',
287
+ description: 'Test 2'
288
+ },
289
+ afterReplicaId: 't2'
290
+ });
291
+
292
+ await batch.commit('0/1');
293
+ });
294
+
295
+ const stream = streamResponse({
296
+ storage: f,
297
+ params: {
298
+ buckets: [],
299
+ include_checksum: true,
300
+ raw_data: true
301
+ },
302
+ parseOptions: PARSE_OPTIONS,
303
+ tracker,
304
+ syncParams: new RequestParameters({ sub: '' }, {}),
305
+ token: { exp: Date.now() / 1000 + 10 } as any
306
+ });
307
+
308
+ const iter = stream[Symbol.asyncIterator]();
309
+
310
+ // Only consume the first "checkpoint" message, and pause before receiving data.
311
+ const lines = await consumeIterator(iter, { consume: false, isDone: (line) => (line as any)?.checkpoint != null });
312
+ expect(lines).toMatchSnapshot();
313
+ expect(lines[0]).toEqual({
314
+ checkpoint: expect.objectContaining({
315
+ last_op_id: '2'
316
+ })
317
+ });
318
+
319
+ // Now we save additional data AND compact before continuing.
320
+ // This invalidates the checkpoint we've received above.
321
+
322
+ await storage.startBatch(BATCH_OPTIONS, async (batch) => {
323
+ await batch.save({
324
+ sourceTable: TEST_TABLE,
325
+ tag: 'update',
326
+ after: {
327
+ id: 't1',
328
+ description: 'Test 1b'
329
+ },
330
+ afterReplicaId: 't1'
331
+ });
332
+
333
+ await batch.save({
334
+ sourceTable: TEST_TABLE,
335
+ tag: 'update',
336
+ after: {
337
+ id: 't2',
338
+ description: 'Test 2b'
339
+ },
340
+ afterReplicaId: 't2'
341
+ });
342
+
343
+ await batch.commit('0/2');
344
+ });
345
+
346
+ await storage.compact();
347
+
348
+ const lines2 = await getCheckpointLines(iter, { consume: true });
349
+
350
+ // Snapshot test checks for changes in general.
351
+ // The tests after that documents the specific things we're looking for
352
+ // in this test.
353
+ expect(lines2).toMatchSnapshot();
354
+
355
+ expect(lines2[0]).toEqual({
356
+ data: expect.objectContaining({
357
+ has_more: false,
358
+ data: [
359
+ // The first two ops have been replaced by a single CLEAR op
360
+ expect.objectContaining({
361
+ op: 'CLEAR'
362
+ })
363
+ ]
364
+ })
365
+ });
366
+
367
+ // Note: No checkpoint_complete here, since the checkpoint has been
368
+ // invalidated by the CLEAR op.
369
+
370
+ expect(lines2[1]).toEqual({
371
+ checkpoint_diff: expect.objectContaining({
372
+ last_op_id: '4'
373
+ })
374
+ });
375
+
376
+ expect(lines2[2]).toEqual({
377
+ data: expect.objectContaining({
378
+ has_more: false,
379
+ data: [
380
+ expect.objectContaining({
381
+ op: 'PUT'
382
+ }),
383
+ expect.objectContaining({
384
+ op: 'PUT'
385
+ })
386
+ ]
387
+ })
388
+ });
389
+
390
+ // Now we get a checkpoint_complete
391
+ expect(lines2[3]).toEqual({
392
+ checkpoint_complete: expect.objectContaining({
393
+ last_op_id: '4'
394
+ })
395
+ });
396
+ });
254
397
  }
255
398
 
256
399
  /**
257
- * Get lines on an iterator until the next checkpoint_complete.
400
+ * Get lines on an iterator until isDone(line) == true.
258
401
  *
259
- * Does not stop the iterator.
402
+ * Does not stop the iterator unless options.consume is true.
260
403
  */
261
- async function getCheckpointLines(iter: AsyncIterator<any>, options?: { consume?: boolean }): Promise<any[]> {
262
- let lines: any[] = [];
404
+ async function consumeIterator<T>(
405
+ iter: AsyncIterator<T>,
406
+ options: { isDone: (line: T) => boolean; consume?: boolean }
407
+ ) {
408
+ let lines: T[] = [];
263
409
  try {
264
410
  const controller = new AbortController();
265
411
  const timeout = timers.setTimeout(1500, { value: null, done: 'timeout' }, { signal: controller.signal });
@@ -274,7 +420,7 @@ async function getCheckpointLines(iter: AsyncIterator<any>, options?: { consume?
274
420
  if (value) {
275
421
  lines.push(value);
276
422
  }
277
- if (done || value.checkpoint_complete) {
423
+ if (done || options.isDone(value)) {
278
424
  break;
279
425
  }
280
426
  }
@@ -292,11 +438,26 @@ async function getCheckpointLines(iter: AsyncIterator<any>, options?: { consume?
292
438
  }
293
439
  }
294
440
 
441
+ /**
442
+ * Get lines on an iterator until the next checkpoint_complete.
443
+ *
444
+ * Does not stop the iterator unless options.consume is true.
445
+ */
446
+ async function getCheckpointLines(
447
+ iter: AsyncIterator<StreamingSyncLine | string | null>,
448
+ options?: { consume?: boolean }
449
+ ) {
450
+ return consumeIterator(iter, {
451
+ consume: options?.consume,
452
+ isDone: (line) => (line as any)?.checkpoint_complete
453
+ });
454
+ }
455
+
295
456
  /**
296
457
  * Get lines on an iterator until the next checkpoint_complete.
297
458
  *
298
459
  * Stops the iterator afterwards.
299
460
  */
300
- async function consumeCheckpointLines(iterable: AsyncIterable<any>): Promise<any[]> {
461
+ async function consumeCheckpointLines(iterable: AsyncIterable<StreamingSyncLine | string | null>): Promise<any[]> {
301
462
  return getCheckpointLines(iterable[Symbol.asyncIterator](), { consume: true });
302
463
  }
package/test/src/util.ts CHANGED
@@ -1,28 +1,29 @@
1
- import * as pgwire from '@powersync/service-jpgwire';
2
- import { normalizeConnection } from '@powersync/service-types';
1
+ import { Metrics } from '@/metrics/Metrics.js';
2
+ import {
3
+ BucketStorageFactory,
4
+ ParseSyncRulesOptions,
5
+ PersistedSyncRulesContent,
6
+ StartBatchOptions,
7
+ SyncBucketDataBatch
8
+ } from '@/storage/BucketStorage.js';
9
+ import { MongoBucketStorage } from '@/storage/MongoBucketStorage.js';
10
+ import { SourceTable } from '@/storage/SourceTable.js';
11
+ import { PowerSyncMongo } from '@/storage/mongo/db.js';
12
+ import { SyncBucketData } from '@/util/protocol-types.js';
13
+ import { getUuidReplicaIdentityBson, hashData } from '@/util/utils.js';
14
+ import * as bson from 'bson';
3
15
  import * as mongo from 'mongodb';
4
- import { BucketStorageFactory } from '../../src/storage/BucketStorage.js';
5
- import { MongoBucketStorage } from '../../src/storage/MongoBucketStorage.js';
6
- import { PowerSyncMongo } from '../../src/storage/mongo/db.js';
7
- import { escapeIdentifier } from '../../src/util/pgwire_utils.js';
8
16
  import { env } from './env.js';
9
- import { Metrics } from '@/metrics/Metrics.js';
10
- import { container } from '@powersync/lib-services-framework';
11
- import { MeterProvider } from '@opentelemetry/sdk-metrics';
12
- import { PrometheusExporter } from '@opentelemetry/exporter-prometheus';
17
+ import { SqlSyncRules } from '@powersync/service-sync-rules';
18
+ import { ReplicaId } from '@/storage/storage-index.js';
13
19
 
14
20
  // The metrics need to be initialised before they can be used
15
- const prometheus = new PrometheusExporter();
16
- const metrics = new Metrics(
17
- new MeterProvider({
18
- readers: [prometheus]
19
- }),
20
- prometheus
21
- );
22
- container.register(Metrics, metrics);
23
- metrics.resetCounters();
24
-
25
- export const TEST_URI = env.PG_TEST_URL;
21
+ await Metrics.initialise({
22
+ disable_telemetry_sharing: true,
23
+ powersync_instance_id: 'test',
24
+ internal_metrics_endpoint: 'unused.for.tests.com'
25
+ });
26
+ Metrics.getInstance().resetCounters();
26
27
 
27
28
  export type StorageFactory = () => Promise<BucketStorageFactory>;
28
29
 
@@ -32,41 +33,33 @@ export const MONGO_STORAGE_FACTORY: StorageFactory = async () => {
32
33
  return new MongoBucketStorage(db, { slot_name_prefix: 'test_' });
33
34
  };
34
35
 
35
- export async function clearTestDb(db: pgwire.PgClient) {
36
- await db.query(`CREATE EXTENSION IF NOT EXISTS "uuid-ossp"`);
37
- try {
38
- await db.query(`DROP PUBLICATION powersync`);
39
- } catch (e) {
40
- // Ignore
41
- }
36
+ export const ZERO_LSN = '0/0';
42
37
 
43
- await db.query(`CREATE PUBLICATION powersync FOR ALL TABLES`);
44
-
45
- const tableRows = pgwire.pgwireRows(
46
- await db.query(`SELECT table_name FROM information_schema.tables where table_schema = 'public'`)
47
- );
48
- for (let row of tableRows) {
49
- const name = row.table_name;
50
- if (name.startsWith('test_')) {
51
- await db.query(`DROP TABLE public.${escapeIdentifier(name)}`);
52
- }
53
- }
54
- }
55
-
56
- export const TEST_CONNECTION_OPTIONS = normalizeConnection({
57
- type: 'postgresql',
58
- uri: TEST_URI,
59
- sslmode: 'disable'
60
- });
38
+ export const PARSE_OPTIONS: ParseSyncRulesOptions = {
39
+ defaultSchema: 'public'
40
+ };
61
41
 
62
- export async function connectPgWire(type?: 'replication' | 'standard') {
63
- const db = await pgwire.connectPgWire(TEST_CONNECTION_OPTIONS, { type });
64
- return db;
65
- }
42
+ export const BATCH_OPTIONS: StartBatchOptions = {
43
+ ...PARSE_OPTIONS,
44
+ zeroLSN: ZERO_LSN
45
+ };
66
46
 
67
- export function connectPgPool() {
68
- const db = pgwire.connectPgWirePool(TEST_CONNECTION_OPTIONS);
69
- return db;
47
+ export function testRules(content: string): PersistedSyncRulesContent {
48
+ return {
49
+ id: 1,
50
+ sync_rules_content: content,
51
+ slot_name: 'test',
52
+ parsed(options) {
53
+ return {
54
+ id: 1,
55
+ sync_rules: SqlSyncRules.fromYaml(content, PARSE_OPTIONS),
56
+ slot_name: 'test'
57
+ };
58
+ },
59
+ lock() {
60
+ throw new Error('Not implemented');
61
+ }
62
+ };
70
63
  }
71
64
 
72
65
  export async function connectMongo() {
@@ -77,6 +70,68 @@ export async function connectMongo() {
77
70
  socketTimeoutMS: env.CI ? 15_000 : 5_000,
78
71
  serverSelectionTimeoutMS: env.CI ? 15_000 : 2_500
79
72
  });
80
- const db = new PowerSyncMongo(client);
81
- return db;
73
+ return new PowerSyncMongo(client);
74
+ }
75
+
76
+ export function makeTestTable(name: string, columns?: string[] | undefined) {
77
+ const relId = hashData('table', name, (columns ?? ['id']).join(','));
78
+ const id = new bson.ObjectId('6544e3899293153fa7b38331');
79
+ return new SourceTable(
80
+ id,
81
+ SourceTable.DEFAULT_TAG,
82
+ relId,
83
+ 'public',
84
+ name,
85
+ (columns ?? ['id']).map((column) => ({ name: column, type: 'VARCHAR', typeId: 25 })),
86
+ true
87
+ );
88
+ }
89
+
90
+ export function getBatchData(batch: SyncBucketData[] | SyncBucketDataBatch[] | SyncBucketDataBatch) {
91
+ const first = getFirst(batch);
92
+ if (first == null) {
93
+ return [];
94
+ }
95
+ return first.data.map((d) => {
96
+ return {
97
+ op_id: d.op_id,
98
+ op: d.op,
99
+ object_id: d.object_id,
100
+ checksum: d.checksum
101
+ };
102
+ });
103
+ }
104
+
105
+ export function getBatchMeta(batch: SyncBucketData[] | SyncBucketDataBatch[] | SyncBucketDataBatch) {
106
+ const first = getFirst(batch);
107
+ if (first == null) {
108
+ return null;
109
+ }
110
+ return {
111
+ has_more: first.has_more,
112
+ after: first.after,
113
+ next_after: first.next_after
114
+ };
115
+ }
116
+
117
+ function getFirst(batch: SyncBucketData[] | SyncBucketDataBatch[] | SyncBucketDataBatch): SyncBucketData | null {
118
+ if (!Array.isArray(batch)) {
119
+ return batch.batch;
120
+ }
121
+ if (batch.length == 0) {
122
+ return null;
123
+ }
124
+ let first = batch[0];
125
+ if ((first as SyncBucketDataBatch).batch != null) {
126
+ return (first as SyncBucketDataBatch).batch;
127
+ } else {
128
+ return first as SyncBucketData;
129
+ }
130
+ }
131
+
132
+ /**
133
+ * Replica id in the old Postgres format, for backwards-compatible tests.
134
+ */
135
+ export function rid(id: string): bson.UUID {
136
+ return getUuidReplicaIdentityBson({ id: id }, [{ name: 'id', type: 'VARCHAR', typeId: 25 }]);
82
137
  }
@@ -2,8 +2,8 @@
2
2
  "extends": "../../../tsconfig.base.json",
3
3
  "compilerOptions": {
4
4
  "rootDir": "src",
5
- "noEmit": true,
6
5
  "baseUrl": "./",
6
+ "outDir": "dist",
7
7
  "esModuleInterop": true,
8
8
  "skipLibCheck": true,
9
9
  "sourceMap": true,