@powersync/service-core 0.8.8 → 0.10.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.
Files changed (376) hide show
  1. package/CHANGELOG.md +43 -0
  2. package/dist/api/RouteAPI.d.ts +67 -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 +170 -158
  10. package/dist/api/diagnostics.js.map +1 -1
  11. package/dist/api/schema.d.ts +3 -5
  12. package/dist/api/schema.js +14 -80
  13. package/dist/api/schema.js.map +1 -1
  14. package/dist/auth/CachedKeyCollector.js.map +1 -1
  15. package/dist/auth/KeySpec.js.map +1 -1
  16. package/dist/auth/KeyStore.d.ts +7 -4
  17. package/dist/auth/KeyStore.js +1 -1
  18. package/dist/auth/KeyStore.js.map +1 -1
  19. package/dist/auth/LeakyBucket.js.map +1 -1
  20. package/dist/auth/RemoteJWKSCollector.d.ts +0 -2
  21. package/dist/auth/RemoteJWKSCollector.js.map +1 -1
  22. package/dist/auth/StaticSupabaseKeyCollector.d.ts +19 -0
  23. package/dist/auth/StaticSupabaseKeyCollector.js +28 -0
  24. package/dist/auth/StaticSupabaseKeyCollector.js.map +1 -0
  25. package/dist/auth/auth-index.d.ts +1 -1
  26. package/dist/auth/auth-index.js +1 -1
  27. package/dist/auth/auth-index.js.map +1 -1
  28. package/dist/db/mongo.js +5 -3
  29. package/dist/db/mongo.js.map +1 -1
  30. package/dist/entry/cli-entry.js +3 -2
  31. package/dist/entry/cli-entry.js.map +1 -1
  32. package/dist/entry/commands/compact-action.js +90 -14
  33. package/dist/entry/commands/compact-action.js.map +1 -1
  34. package/dist/entry/commands/migrate-action.js +4 -5
  35. package/dist/entry/commands/migrate-action.js.map +1 -1
  36. package/dist/entry/commands/teardown-action.js +2 -2
  37. package/dist/entry/commands/teardown-action.js.map +1 -1
  38. package/dist/index.d.ts +4 -2
  39. package/dist/index.js +4 -2
  40. package/dist/index.js.map +1 -1
  41. package/dist/locks/MongoLocks.js.map +1 -1
  42. package/dist/metrics/Metrics.d.ts +2 -2
  43. package/dist/metrics/Metrics.js +5 -13
  44. package/dist/metrics/Metrics.js.map +1 -1
  45. package/dist/migrations/db/migrations/1684951997326-init.d.ts +2 -2
  46. package/dist/migrations/db/migrations/1684951997326-init.js +4 -2
  47. package/dist/migrations/db/migrations/1684951997326-init.js.map +1 -1
  48. package/dist/migrations/db/migrations/1702295701188-sync-rule-state.d.ts +2 -2
  49. package/dist/migrations/db/migrations/1702295701188-sync-rule-state.js +4 -2
  50. package/dist/migrations/db/migrations/1702295701188-sync-rule-state.js.map +1 -1
  51. package/dist/migrations/db/migrations/1711543888062-write-checkpoint-index.d.ts +2 -2
  52. package/dist/migrations/db/migrations/1711543888062-write-checkpoint-index.js +4 -2
  53. package/dist/migrations/db/migrations/1711543888062-write-checkpoint-index.js.map +1 -1
  54. package/dist/migrations/db/migrations/1727099539247-custom-write-checkpoint-index.d.ts +3 -0
  55. package/dist/migrations/db/migrations/1727099539247-custom-write-checkpoint-index.js +31 -0
  56. package/dist/migrations/db/migrations/1727099539247-custom-write-checkpoint-index.js.map +1 -0
  57. package/dist/migrations/executor.js.map +1 -1
  58. package/dist/migrations/migrations.d.ts +8 -0
  59. package/dist/migrations/migrations.js +19 -7
  60. package/dist/migrations/migrations.js.map +1 -1
  61. package/dist/migrations/store/migration-store.js.map +1 -1
  62. package/dist/modules/AbstractModule.d.ts +26 -0
  63. package/dist/modules/AbstractModule.js +11 -0
  64. package/dist/modules/AbstractModule.js.map +1 -0
  65. package/dist/modules/ModuleManager.d.ts +11 -0
  66. package/dist/modules/ModuleManager.js +32 -0
  67. package/dist/modules/ModuleManager.js.map +1 -0
  68. package/dist/modules/modules-index.d.ts +2 -0
  69. package/dist/modules/modules-index.js +3 -0
  70. package/dist/modules/modules-index.js.map +1 -0
  71. package/dist/replication/AbstractReplicationJob.d.ts +37 -0
  72. package/dist/replication/AbstractReplicationJob.js +51 -0
  73. package/dist/replication/AbstractReplicationJob.js.map +1 -0
  74. package/dist/replication/AbstractReplicator.d.ts +53 -0
  75. package/dist/replication/AbstractReplicator.js +250 -0
  76. package/dist/replication/AbstractReplicator.js.map +1 -0
  77. package/dist/replication/ErrorRateLimiter.d.ts +0 -10
  78. package/dist/replication/ErrorRateLimiter.js +1 -42
  79. package/dist/replication/ErrorRateLimiter.js.map +1 -1
  80. package/dist/replication/ReplicationEngine.d.ts +18 -0
  81. package/dist/replication/ReplicationEngine.js +41 -0
  82. package/dist/replication/ReplicationEngine.js.map +1 -0
  83. package/dist/replication/ReplicationModule.d.ts +51 -0
  84. package/dist/replication/ReplicationModule.js +68 -0
  85. package/dist/replication/ReplicationModule.js.map +1 -0
  86. package/dist/replication/replication-index.d.ts +4 -6
  87. package/dist/replication/replication-index.js +4 -6
  88. package/dist/replication/replication-index.js.map +1 -1
  89. package/dist/routes/RouterEngine.d.ts +42 -0
  90. package/dist/routes/RouterEngine.js +80 -0
  91. package/dist/routes/RouterEngine.js.map +1 -0
  92. package/dist/routes/auth.d.ts +2 -2
  93. package/dist/routes/auth.js +11 -11
  94. package/dist/routes/auth.js.map +1 -1
  95. package/dist/routes/configure-fastify.d.ts +37 -23
  96. package/dist/routes/configure-fastify.js +18 -18
  97. package/dist/routes/configure-fastify.js.map +1 -1
  98. package/dist/routes/configure-rsocket.d.ts +3 -4
  99. package/dist/routes/configure-rsocket.js +7 -4
  100. package/dist/routes/configure-rsocket.js.map +1 -1
  101. package/dist/routes/endpoints/admin.d.ts +30 -0
  102. package/dist/routes/endpoints/admin.js +46 -67
  103. package/dist/routes/endpoints/admin.js.map +1 -1
  104. package/dist/routes/endpoints/checkpointing.js +103 -15
  105. package/dist/routes/endpoints/checkpointing.js.map +1 -1
  106. package/dist/routes/endpoints/socket-route.js +8 -6
  107. package/dist/routes/endpoints/socket-route.js.map +1 -1
  108. package/dist/routes/endpoints/sync-rules.d.ts +1 -1
  109. package/dist/routes/endpoints/sync-rules.js +32 -23
  110. package/dist/routes/endpoints/sync-rules.js.map +1 -1
  111. package/dist/routes/endpoints/sync-stream.d.ts +0 -1
  112. package/dist/routes/endpoints/sync-stream.js +8 -8
  113. package/dist/routes/endpoints/sync-stream.js.map +1 -1
  114. package/dist/routes/hooks.js.map +1 -1
  115. package/dist/routes/route-register.js.map +1 -1
  116. package/dist/routes/router.d.ts +9 -2
  117. package/dist/routes/router.js.map +1 -1
  118. package/dist/routes/routes-index.d.ts +1 -0
  119. package/dist/routes/routes-index.js +1 -0
  120. package/dist/routes/routes-index.js.map +1 -1
  121. package/dist/runner/teardown.js +109 -76
  122. package/dist/runner/teardown.js.map +1 -1
  123. package/dist/storage/BucketStorage.d.ts +86 -36
  124. package/dist/storage/BucketStorage.js +6 -10
  125. package/dist/storage/BucketStorage.js.map +1 -1
  126. package/dist/storage/ChecksumCache.js.map +1 -1
  127. package/dist/storage/MongoBucketStorage.d.ts +7 -11
  128. package/dist/storage/MongoBucketStorage.js +48 -41
  129. package/dist/storage/MongoBucketStorage.js.map +1 -1
  130. package/dist/storage/ReplicationEventPayload.d.ts +14 -0
  131. package/dist/storage/ReplicationEventPayload.js +2 -0
  132. package/dist/storage/ReplicationEventPayload.js.map +1 -0
  133. package/dist/storage/SourceEntity.d.ts +20 -0
  134. package/dist/storage/SourceEntity.js +2 -0
  135. package/dist/storage/SourceEntity.js.map +1 -0
  136. package/dist/storage/SourceTable.d.ts +12 -5
  137. package/dist/storage/SourceTable.js +12 -5
  138. package/dist/storage/SourceTable.js.map +1 -1
  139. package/dist/storage/StorageEngine.d.ts +28 -0
  140. package/dist/storage/StorageEngine.js +45 -0
  141. package/dist/storage/StorageEngine.js.map +1 -0
  142. package/dist/storage/StorageProvider.d.ts +21 -0
  143. package/dist/storage/StorageProvider.js +2 -0
  144. package/dist/storage/StorageProvider.js.map +1 -0
  145. package/dist/storage/WriteCheckpointAPI.d.ts +74 -0
  146. package/dist/storage/WriteCheckpointAPI.js +16 -0
  147. package/dist/storage/WriteCheckpointAPI.js.map +1 -0
  148. package/dist/storage/mongo/MongoBucketBatch.d.ts +24 -5
  149. package/dist/storage/mongo/MongoBucketBatch.js +119 -62
  150. package/dist/storage/mongo/MongoBucketBatch.js.map +1 -1
  151. package/dist/storage/mongo/MongoCompactor.js +20 -3
  152. package/dist/storage/mongo/MongoCompactor.js.map +1 -1
  153. package/dist/storage/mongo/MongoIdSequence.js.map +1 -1
  154. package/dist/storage/mongo/MongoPersistedSyncRulesContent.d.ts +2 -2
  155. package/dist/storage/mongo/MongoPersistedSyncRulesContent.js +2 -2
  156. package/dist/storage/mongo/MongoPersistedSyncRulesContent.js.map +1 -1
  157. package/dist/storage/mongo/MongoStorageProvider.d.ts +5 -0
  158. package/dist/storage/mongo/MongoStorageProvider.js +26 -0
  159. package/dist/storage/mongo/MongoStorageProvider.js.map +1 -0
  160. package/dist/storage/mongo/MongoSyncBucketStorage.d.ts +18 -10
  161. package/dist/storage/mongo/MongoSyncBucketStorage.js +140 -25
  162. package/dist/storage/mongo/MongoSyncBucketStorage.js.map +1 -1
  163. package/dist/storage/mongo/MongoSyncRulesLock.js +1 -1
  164. package/dist/storage/mongo/MongoSyncRulesLock.js.map +1 -1
  165. package/dist/storage/mongo/MongoWriteCheckpointAPI.d.ts +20 -0
  166. package/dist/storage/mongo/MongoWriteCheckpointAPI.js +103 -0
  167. package/dist/storage/mongo/MongoWriteCheckpointAPI.js.map +1 -0
  168. package/dist/storage/mongo/OperationBatch.d.ts +13 -4
  169. package/dist/storage/mongo/OperationBatch.js +25 -7
  170. package/dist/storage/mongo/OperationBatch.js.map +1 -1
  171. package/dist/storage/mongo/PersistedBatch.d.ts +3 -3
  172. package/dist/storage/mongo/PersistedBatch.js +2 -2
  173. package/dist/storage/mongo/PersistedBatch.js.map +1 -1
  174. package/dist/storage/mongo/config.d.ts +19 -0
  175. package/dist/storage/mongo/config.js +26 -0
  176. package/dist/storage/mongo/config.js.map +1 -0
  177. package/dist/storage/mongo/db.d.ts +3 -2
  178. package/dist/storage/mongo/db.js +1 -0
  179. package/dist/storage/mongo/db.js.map +1 -1
  180. package/dist/storage/mongo/models.d.ts +20 -5
  181. package/dist/storage/mongo/models.js.map +1 -1
  182. package/dist/storage/mongo/util.d.ts +12 -1
  183. package/dist/storage/mongo/util.js +50 -2
  184. package/dist/storage/mongo/util.js.map +1 -1
  185. package/dist/storage/storage-index.d.ts +8 -2
  186. package/dist/storage/storage-index.js +8 -2
  187. package/dist/storage/storage-index.js.map +1 -1
  188. package/dist/sync/BroadcastIterable.d.ts +0 -1
  189. package/dist/sync/BroadcastIterable.js.map +1 -1
  190. package/dist/sync/LastValueSink.d.ts +0 -1
  191. package/dist/sync/LastValueSink.js.map +1 -1
  192. package/dist/sync/merge.d.ts +0 -1
  193. package/dist/sync/merge.js.map +1 -1
  194. package/dist/sync/safeRace.js.map +1 -1
  195. package/dist/sync/sync.d.ts +1 -1
  196. package/dist/sync/sync.js +5 -5
  197. package/dist/sync/sync.js.map +1 -1
  198. package/dist/sync/util.d.ts +0 -2
  199. package/dist/sync/util.js.map +1 -1
  200. package/dist/system/ServiceContext.d.ts +37 -0
  201. package/dist/system/ServiceContext.js +48 -0
  202. package/dist/system/ServiceContext.js.map +1 -0
  203. package/dist/system/system-index.d.ts +1 -1
  204. package/dist/system/system-index.js +1 -1
  205. package/dist/system/system-index.js.map +1 -1
  206. package/dist/util/Mutex.js.map +1 -1
  207. package/dist/util/config/collectors/config-collector.js.map +1 -1
  208. package/dist/util/config/collectors/impl/base64-config-collector.js.map +1 -1
  209. package/dist/util/config/collectors/impl/filesystem-config-collector.js.map +1 -1
  210. package/dist/util/config/compound-config-collector.d.ts +9 -2
  211. package/dist/util/config/compound-config-collector.js +31 -23
  212. package/dist/util/config/compound-config-collector.js.map +1 -1
  213. package/dist/util/config/sync-rules/impl/base64-sync-rules-collector.js.map +1 -1
  214. package/dist/util/config/sync-rules/impl/filesystem-sync-rules-collector.js.map +1 -1
  215. package/dist/util/config/sync-rules/impl/inline-sync-rules-collector.js.map +1 -1
  216. package/dist/util/config/sync-rules/sync-rules-provider.d.ts +9 -0
  217. package/dist/util/config/sync-rules/sync-rules-provider.js +15 -0
  218. package/dist/util/config/sync-rules/sync-rules-provider.js.map +1 -0
  219. package/dist/util/config/types.d.ts +7 -4
  220. package/dist/util/config/types.js.map +1 -1
  221. package/dist/util/config.d.ts +3 -4
  222. package/dist/util/config.js +5 -20
  223. package/dist/util/config.js.map +1 -1
  224. package/dist/util/memory-tracking.js.map +1 -1
  225. package/dist/util/secs.js.map +1 -1
  226. package/dist/util/util-index.d.ts +3 -6
  227. package/dist/util/util-index.js +3 -6
  228. package/dist/util/util-index.js.map +1 -1
  229. package/dist/util/utils.d.ts +10 -7
  230. package/dist/util/utils.js +36 -25
  231. package/dist/util/utils.js.map +1 -1
  232. package/package.json +8 -12
  233. package/src/api/RouteAPI.ts +78 -0
  234. package/src/api/api-index.ts +1 -0
  235. package/src/api/diagnostics.ts +18 -70
  236. package/src/api/schema.ts +18 -90
  237. package/src/auth/KeyStore.ts +9 -6
  238. package/src/auth/RemoteJWKSCollector.ts +4 -1
  239. package/src/auth/StaticSupabaseKeyCollector.ts +31 -0
  240. package/src/auth/auth-index.ts +1 -1
  241. package/src/db/mongo.ts +5 -3
  242. package/src/entry/cli-entry.ts +3 -2
  243. package/src/entry/commands/compact-action.ts +24 -12
  244. package/src/entry/commands/migrate-action.ts +5 -8
  245. package/src/entry/commands/teardown-action.ts +2 -2
  246. package/src/index.ts +5 -2
  247. package/src/metrics/Metrics.ts +6 -16
  248. package/src/migrations/db/migrations/1684951997326-init.ts +9 -4
  249. package/src/migrations/db/migrations/1702295701188-sync-rule-state.ts +7 -4
  250. package/src/migrations/db/migrations/1711543888062-write-checkpoint-index.ts +6 -4
  251. package/src/migrations/db/migrations/1727099539247-custom-write-checkpoint-index.ts +37 -0
  252. package/src/migrations/migrations.ts +24 -8
  253. package/src/modules/AbstractModule.ts +37 -0
  254. package/src/modules/ModuleManager.ts +34 -0
  255. package/src/modules/modules-index.ts +2 -0
  256. package/src/replication/AbstractReplicationJob.ts +79 -0
  257. package/src/replication/AbstractReplicator.ts +228 -0
  258. package/src/replication/ErrorRateLimiter.ts +0 -44
  259. package/src/replication/ReplicationEngine.ts +43 -0
  260. package/src/replication/ReplicationModule.ts +122 -0
  261. package/src/replication/replication-index.ts +4 -6
  262. package/src/routes/RouterEngine.ts +120 -0
  263. package/src/routes/auth.ts +21 -12
  264. package/src/routes/configure-fastify.ts +26 -27
  265. package/src/routes/configure-rsocket.ts +13 -8
  266. package/src/routes/endpoints/admin.ts +72 -76
  267. package/src/routes/endpoints/checkpointing.ts +51 -11
  268. package/src/routes/endpoints/socket-route.ts +10 -6
  269. package/src/routes/endpoints/sync-rules.ts +41 -25
  270. package/src/routes/endpoints/sync-stream.ts +8 -8
  271. package/src/routes/router.ts +8 -3
  272. package/src/routes/routes-index.ts +1 -0
  273. package/src/runner/teardown.ts +50 -88
  274. package/src/storage/BucketStorage.ts +103 -41
  275. package/src/storage/MongoBucketStorage.ts +65 -53
  276. package/src/storage/ReplicationEventPayload.ts +16 -0
  277. package/src/storage/SourceEntity.ts +22 -0
  278. package/src/storage/SourceTable.ts +14 -7
  279. package/src/storage/StorageEngine.ts +62 -0
  280. package/src/storage/StorageProvider.ts +27 -0
  281. package/src/storage/WriteCheckpointAPI.ts +85 -0
  282. package/src/storage/mongo/MongoBucketBatch.ts +164 -84
  283. package/src/storage/mongo/MongoCompactor.ts +25 -4
  284. package/src/storage/mongo/MongoPersistedSyncRulesContent.ts +7 -4
  285. package/src/storage/mongo/MongoStorageProvider.ts +31 -0
  286. package/src/storage/mongo/MongoSyncBucketStorage.ts +118 -41
  287. package/src/storage/mongo/MongoSyncRulesLock.ts +7 -3
  288. package/src/storage/mongo/MongoWriteCheckpointAPI.ts +151 -0
  289. package/src/storage/mongo/OperationBatch.ts +28 -12
  290. package/src/storage/mongo/PersistedBatch.ts +10 -6
  291. package/src/storage/mongo/config.ts +40 -0
  292. package/src/storage/mongo/db.ts +4 -1
  293. package/src/storage/mongo/models.ts +21 -5
  294. package/src/storage/mongo/util.ts +48 -3
  295. package/src/storage/storage-index.ts +8 -2
  296. package/src/sync/sync.ts +7 -4
  297. package/src/sync/util.ts +0 -1
  298. package/src/system/ServiceContext.ts +68 -0
  299. package/src/system/system-index.ts +1 -1
  300. package/src/util/config/compound-config-collector.ts +48 -30
  301. package/src/util/config/sync-rules/sync-rules-provider.ts +18 -0
  302. package/src/util/config/types.ts +7 -5
  303. package/src/util/config.ts +6 -23
  304. package/src/util/util-index.ts +3 -6
  305. package/src/util/utils.ts +48 -41
  306. package/test/src/__snapshots__/sync.test.ts.snap +14 -14
  307. package/test/src/auth.test.ts +7 -7
  308. package/test/src/broadcast_iterable.test.ts +1 -1
  309. package/test/src/compacting.test.ts +50 -40
  310. package/test/src/data_storage.test.ts +382 -202
  311. package/test/src/env.ts +1 -3
  312. package/test/src/merge_iterable.test.ts +1 -6
  313. package/test/src/routes/probes.integration.test.ts +34 -30
  314. package/test/src/setup.ts +1 -1
  315. package/test/src/stream_utils.ts +42 -0
  316. package/test/src/sync.test.ts +115 -39
  317. package/test/src/util.ts +48 -51
  318. package/test/tsconfig.json +1 -1
  319. package/tsconfig.tsbuildinfo +1 -1
  320. package/vitest.config.ts +7 -1
  321. package/dist/auth/SupabaseKeyCollector.d.ts +0 -22
  322. package/dist/auth/SupabaseKeyCollector.js +0 -61
  323. package/dist/auth/SupabaseKeyCollector.js.map +0 -1
  324. package/dist/replication/PgRelation.d.ts +0 -16
  325. package/dist/replication/PgRelation.js +0 -26
  326. package/dist/replication/PgRelation.js.map +0 -1
  327. package/dist/replication/WalConnection.d.ts +0 -34
  328. package/dist/replication/WalConnection.js +0 -190
  329. package/dist/replication/WalConnection.js.map +0 -1
  330. package/dist/replication/WalStream.d.ts +0 -57
  331. package/dist/replication/WalStream.js +0 -519
  332. package/dist/replication/WalStream.js.map +0 -1
  333. package/dist/replication/WalStreamManager.d.ts +0 -30
  334. package/dist/replication/WalStreamManager.js +0 -198
  335. package/dist/replication/WalStreamManager.js.map +0 -1
  336. package/dist/replication/WalStreamRunner.d.ts +0 -38
  337. package/dist/replication/WalStreamRunner.js +0 -155
  338. package/dist/replication/WalStreamRunner.js.map +0 -1
  339. package/dist/replication/util.d.ts +0 -9
  340. package/dist/replication/util.js +0 -62
  341. package/dist/replication/util.js.map +0 -1
  342. package/dist/system/CorePowerSyncSystem.d.ts +0 -23
  343. package/dist/system/CorePowerSyncSystem.js +0 -52
  344. package/dist/system/CorePowerSyncSystem.js.map +0 -1
  345. package/dist/util/PgManager.d.ts +0 -24
  346. package/dist/util/PgManager.js +0 -55
  347. package/dist/util/PgManager.js.map +0 -1
  348. package/dist/util/migration_lib.d.ts +0 -11
  349. package/dist/util/migration_lib.js +0 -64
  350. package/dist/util/migration_lib.js.map +0 -1
  351. package/dist/util/pgwire_utils.d.ts +0 -24
  352. package/dist/util/pgwire_utils.js +0 -117
  353. package/dist/util/pgwire_utils.js.map +0 -1
  354. package/dist/util/populate_test_data.d.ts +0 -8
  355. package/dist/util/populate_test_data.js +0 -65
  356. package/dist/util/populate_test_data.js.map +0 -1
  357. package/src/auth/SupabaseKeyCollector.ts +0 -67
  358. package/src/replication/PgRelation.ts +0 -42
  359. package/src/replication/WalConnection.ts +0 -227
  360. package/src/replication/WalStream.ts +0 -631
  361. package/src/replication/WalStreamManager.ts +0 -213
  362. package/src/replication/WalStreamRunner.ts +0 -180
  363. package/src/replication/util.ts +0 -76
  364. package/src/system/CorePowerSyncSystem.ts +0 -64
  365. package/src/util/PgManager.ts +0 -64
  366. package/src/util/migration_lib.ts +0 -79
  367. package/src/util/pgwire_utils.ts +0 -139
  368. package/src/util/populate_test_data.ts +0 -78
  369. package/test/src/__snapshots__/pg_test.test.ts.snap +0 -256
  370. package/test/src/large_batch.test.ts +0 -194
  371. package/test/src/pg_test.test.ts +0 -450
  372. package/test/src/schema_changes.test.ts +0 -545
  373. package/test/src/slow_tests.test.ts +0 -338
  374. package/test/src/validation.test.ts +0 -63
  375. package/test/src/wal_stream.test.ts +0 -319
  376. package/test/src/wal_stream_utils.ts +0 -156
@@ -1,338 +0,0 @@
1
- import * as bson from 'bson';
2
- import * as mongo from 'mongodb';
3
- import { afterEach, describe, expect, test } from 'vitest';
4
- import { WalStream, WalStreamOptions } from '../../src/replication/WalStream.js';
5
- import { getClientCheckpoint } from '../../src/util/utils.js';
6
- import { env } from './env.js';
7
- import { MONGO_STORAGE_FACTORY, StorageFactory, TEST_CONNECTION_OPTIONS, clearTestDb, connectPgPool } from './util.js';
8
-
9
- import * as pgwire from '@powersync/service-jpgwire';
10
- import { SqliteRow } from '@powersync/service-sync-rules';
11
- import { MongoBucketStorage } from '../../src/storage/MongoBucketStorage.js';
12
- import { PgManager } from '../../src/util/PgManager.js';
13
- import { mapOpEntry } from '@/storage/storage-index.js';
14
- import { reduceBucket, validateCompactedBucket, validateBucket } from './bucket_validation.js';
15
- import * as timers from 'node:timers/promises';
16
-
17
- describe('slow tests - mongodb', function () {
18
- // These are slow, inconsistent tests.
19
- // Not run on every test run, but we do run on CI, or when manually debugging issues.
20
- if (env.CI || env.SLOW_TESTS) {
21
- defineSlowTests(MONGO_STORAGE_FACTORY);
22
- } else {
23
- // Need something in this file.
24
- test('no-op', () => {});
25
- }
26
- });
27
-
28
- function defineSlowTests(factory: StorageFactory) {
29
- let walStream: WalStream | undefined;
30
- let connections: PgManager | undefined;
31
- let abortController: AbortController | undefined;
32
- let streamPromise: Promise<void> | undefined;
33
-
34
- afterEach(async () => {
35
- // This cleans up, similar to WalStreamTestContext.dispose().
36
- // These tests are a little more complex than what is supported by WalStreamTestContext.
37
- abortController?.abort();
38
- await streamPromise;
39
- streamPromise = undefined;
40
- connections?.destroy();
41
-
42
- connections = undefined;
43
- walStream = undefined;
44
- abortController = undefined;
45
- });
46
-
47
- const TEST_DURATION_MS = 15_000;
48
- const TIMEOUT_MARGIN_MS = env.CI ? 30_000 : 15_000;
49
-
50
- // Test repeatedly replicating inserts and deletes, then check that we get
51
- // consistent data out at the end.
52
- //
53
- // Past issues that this could reproduce intermittently:
54
- // * Skipping LSNs after a keepalive message
55
- // * Skipping LSNs when source transactions overlap
56
- test(
57
- 'repeated replication - basic',
58
- async () => {
59
- await testRepeatedReplication({ compact: false, maxBatchSize: 50, numBatches: 5 });
60
- },
61
- { timeout: TEST_DURATION_MS + TIMEOUT_MARGIN_MS }
62
- );
63
-
64
- test(
65
- 'repeated replication - compacted',
66
- async () => {
67
- await testRepeatedReplication({ compact: true, maxBatchSize: 100, numBatches: 2 });
68
- },
69
- { timeout: TEST_DURATION_MS + TIMEOUT_MARGIN_MS }
70
- );
71
-
72
- async function testRepeatedReplication(testOptions: { compact: boolean; maxBatchSize: number; numBatches: number }) {
73
- const connections = new PgManager(TEST_CONNECTION_OPTIONS, {});
74
- const replicationConnection = await connections.replicationConnection();
75
- const pool = connections.pool;
76
- await clearTestDb(pool);
77
- const f = (await factory()) as MongoBucketStorage;
78
-
79
- const syncRuleContent = `
80
- bucket_definitions:
81
- global:
82
- data:
83
- - SELECT * FROM "test_data"
84
- `;
85
- const syncRules = await f.updateSyncRules({ content: syncRuleContent });
86
- const storage = f.getInstance(syncRules.parsed());
87
- abortController = new AbortController();
88
- const options: WalStreamOptions = {
89
- abort_signal: abortController.signal,
90
- connections,
91
- storage: storage,
92
- factory: f
93
- };
94
- walStream = new WalStream(options);
95
-
96
- await pool.query(
97
- `CREATE TABLE test_data(id uuid primary key default uuid_generate_v4(), description text, num decimal)`
98
- );
99
- await pool.query(`ALTER TABLE test_data REPLICA IDENTITY FULL`);
100
-
101
- await walStream.initReplication(replicationConnection);
102
- await storage.autoActivate();
103
- let abort = false;
104
- streamPromise = walStream.streamChanges(replicationConnection).finally(() => {
105
- abort = true;
106
- });
107
- const start = Date.now();
108
-
109
- while (!abort && Date.now() - start < TEST_DURATION_MS) {
110
- const bg = async () => {
111
- for (let j = 0; j < testOptions.numBatches && !abort; j++) {
112
- const n = Math.max(1, Math.floor(Math.random() * testOptions.maxBatchSize));
113
- let statements: pgwire.Statement[] = [];
114
- for (let i = 0; i < n; i++) {
115
- const description = `test${i}`;
116
- statements.push({
117
- statement: `INSERT INTO test_data(description, num) VALUES($1, $2) returning id as test_id`,
118
- params: [
119
- { type: 'varchar', value: description },
120
- { type: 'float8', value: Math.random() }
121
- ]
122
- });
123
- }
124
- const results = await pool.query(...statements);
125
- const ids = results.results.map((sub) => {
126
- return sub.rows[0][0] as string;
127
- });
128
- await new Promise((resolve) => setTimeout(resolve, Math.random() * 30));
129
-
130
- if (Math.random() > 0.5) {
131
- const updateStatements: pgwire.Statement[] = ids.map((id) => {
132
- return {
133
- statement: `UPDATE test_data SET num = $2 WHERE id = $1`,
134
- params: [
135
- { type: 'uuid', value: id },
136
- { type: 'float8', value: Math.random() }
137
- ]
138
- };
139
- });
140
-
141
- await pool.query(...updateStatements);
142
- if (Math.random() > 0.5) {
143
- // Special case - an update that doesn't change data
144
- await pool.query(...updateStatements);
145
- }
146
- }
147
-
148
- const deleteStatements: pgwire.Statement[] = ids.map((id) => {
149
- return {
150
- statement: `DELETE FROM test_data WHERE id = $1`,
151
- params: [{ type: 'uuid', value: id }]
152
- };
153
- });
154
- await pool.query(...deleteStatements);
155
-
156
- await new Promise((resolve) => setTimeout(resolve, Math.random() * 10));
157
- }
158
- };
159
-
160
- let compactController = new AbortController();
161
-
162
- const bgCompact = async () => {
163
- // Repeatedly compact, and check that the compact conditions hold
164
- while (!compactController.signal.aborted) {
165
- const delay = Math.random() * 50;
166
- try {
167
- await timers.setTimeout(delay, undefined, { signal: compactController.signal });
168
- } catch (e) {
169
- break;
170
- }
171
-
172
- const checkpoint = BigInt((await storage.getCheckpoint()).checkpoint);
173
- const opsBefore = (await f.db.bucket_data.find().sort({ _id: 1 }).toArray())
174
- .filter((row) => row._id.o <= checkpoint)
175
- .map(mapOpEntry);
176
- await storage.compact({ maxOpId: checkpoint });
177
- const opsAfter = (await f.db.bucket_data.find().sort({ _id: 1 }).toArray())
178
- .filter((row) => row._id.o <= checkpoint)
179
- .map(mapOpEntry);
180
-
181
- validateCompactedBucket(opsBefore, opsAfter);
182
- }
183
- };
184
-
185
- // Call the above loop multiple times concurrently
186
- const promises = [1, 2, 3].map((i) => bg());
187
- const compactPromise = testOptions.compact ? bgCompact() : null;
188
- await Promise.all(promises);
189
- compactController.abort();
190
- await compactPromise;
191
-
192
- // Wait for replication to finish
193
- let checkpoint = await getClientCheckpoint(pool, storage.factory, { timeout: TIMEOUT_MARGIN_MS });
194
-
195
- // Check that all inserts have been deleted again
196
- const docs = await f.db.current_data.find().toArray();
197
- const transformed = docs.map((doc) => {
198
- return bson.deserialize((doc.data as mongo.Binary).buffer) as SqliteRow;
199
- });
200
- expect(transformed).toEqual([]);
201
-
202
- // Check that each PUT has a REMOVE
203
- const ops = await f.db.bucket_data.find().sort({ _id: 1 }).toArray();
204
-
205
- // All a single bucket in this test
206
- const bucket = ops.map((op) => mapOpEntry(op));
207
- const reduced = reduceBucket(bucket);
208
- expect(reduced).toMatchObject([
209
- {
210
- op_id: '0',
211
- op: 'CLEAR'
212
- }
213
- // Should contain no additional data
214
- ]);
215
- }
216
-
217
- abortController.abort();
218
- await streamPromise;
219
- }
220
-
221
- // Test repeatedly performing initial replication.
222
- //
223
- // If the first LSN does not correctly match with the first replication transaction,
224
- // we may miss some updates.
225
- test(
226
- 'repeated initial replication',
227
- async () => {
228
- const pool = await connectPgPool();
229
- await clearTestDb(pool);
230
- const f = await factory();
231
-
232
- const syncRuleContent = `
233
- bucket_definitions:
234
- global:
235
- data:
236
- - SELECT id, description FROM "test_data"
237
- `;
238
- const syncRules = await f.updateSyncRules({ content: syncRuleContent });
239
- const storage = f.getInstance(syncRules.parsed());
240
-
241
- // 1. Setup some base data that will be replicated in initial replication
242
- await pool.query(`CREATE TABLE test_data(id uuid primary key default uuid_generate_v4(), description text)`);
243
-
244
- let statements: pgwire.Statement[] = [];
245
-
246
- const n = Math.floor(Math.random() * 200);
247
- for (let i = 0; i < n; i++) {
248
- statements.push({
249
- statement: `INSERT INTO test_data(description) VALUES('test_init')`
250
- });
251
- }
252
- await pool.query(...statements);
253
-
254
- const start = Date.now();
255
- let i = 0;
256
-
257
- while (Date.now() - start < TEST_DURATION_MS) {
258
- // 2. Each iteration starts with a clean slate
259
- await pool.query(`SELECT pg_drop_replication_slot(slot_name) FROM pg_replication_slots WHERE active = FALSE`);
260
- i += 1;
261
-
262
- const connections = new PgManager(TEST_CONNECTION_OPTIONS, {});
263
- const replicationConnection = await connections.replicationConnection();
264
-
265
- abortController = new AbortController();
266
- const options: WalStreamOptions = {
267
- abort_signal: abortController.signal,
268
- connections,
269
- storage: storage,
270
- factory: f
271
- };
272
- walStream = new WalStream(options);
273
-
274
- await storage.clear();
275
-
276
- // 3. Start initial replication, then streaming, but don't wait for any of this
277
- let initialReplicationDone = false;
278
- streamPromise = (async () => {
279
- await walStream.initReplication(replicationConnection);
280
- await storage.autoActivate();
281
- initialReplicationDone = true;
282
- await walStream.streamChanges(replicationConnection);
283
- })()
284
- .catch((e) => {
285
- initialReplicationDone = true;
286
- throw e;
287
- })
288
- .then((v) => {
289
- return v;
290
- });
291
-
292
- // 4. While initial replication is still running, write more changes
293
- while (!initialReplicationDone) {
294
- let statements: pgwire.Statement[] = [];
295
- const n = Math.floor(Math.random() * 10) + 1;
296
- for (let i = 0; i < n; i++) {
297
- const description = `test${i}`;
298
- statements.push({
299
- statement: `INSERT INTO test_data(description) VALUES('test1') returning id as test_id`,
300
- params: [{ type: 'varchar', value: description }]
301
- });
302
- }
303
- const results = await pool.query(...statements);
304
- const ids = results.results.map((sub) => {
305
- return sub.rows[0][0] as string;
306
- });
307
- await new Promise((resolve) => setTimeout(resolve, Math.random() * 30));
308
- const deleteStatements: pgwire.Statement[] = ids.map((id) => {
309
- return {
310
- statement: `DELETE FROM test_data WHERE id = $1`,
311
- params: [{ type: 'uuid', value: id }]
312
- };
313
- });
314
- await pool.query(...deleteStatements);
315
- await new Promise((resolve) => setTimeout(resolve, Math.random() * 10));
316
- }
317
-
318
- // 5. Once initial replication is done, wait for the streaming changes to complete syncing.
319
- // getClientCheckpoint() effectively waits for the above replication to complete
320
- // Race with streamingPromise to catch replication errors here.
321
- let checkpoint = await Promise.race([
322
- getClientCheckpoint(pool, storage.factory, { timeout: TIMEOUT_MARGIN_MS }),
323
- streamPromise
324
- ]);
325
- if (typeof checkpoint == undefined) {
326
- // This indicates an issue with the test setup - streamingPromise completed instead
327
- // of getClientCheckpoint()
328
- throw new Error('Test failure - streamingPromise completed');
329
- }
330
-
331
- abortController.abort();
332
- await streamPromise;
333
- await connections.end();
334
- }
335
- },
336
- { timeout: TEST_DURATION_MS + TIMEOUT_MARGIN_MS }
337
- );
338
- }
@@ -1,63 +0,0 @@
1
- import { expect, test } from 'vitest';
2
- import { MONGO_STORAGE_FACTORY } from './util.js';
3
- import { walStreamTest } from './wal_stream_utils.js';
4
- import { WalConnection } from '../../src/replication/WalConnection.js';
5
-
6
- // Not quite a walStreamTest, but it helps to manage the connection
7
- test(
8
- 'validate tables',
9
- walStreamTest(MONGO_STORAGE_FACTORY, async (context) => {
10
- const { pool } = context;
11
-
12
- await pool.query(`CREATE TABLE test_data(id uuid primary key default uuid_generate_v4(), description text)`);
13
-
14
- const syncRuleContent = `
15
- bucket_definitions:
16
- global:
17
- data:
18
- - SELECT id, description FROM "test_data"
19
- - SELECT * FROM "other"
20
- - SELECT * FROM "other%"
21
- `;
22
-
23
- const syncRules = await context.factory.updateSyncRules({ content: syncRuleContent });
24
-
25
- const walConnection = new WalConnection({
26
- db: pool,
27
- sync_rules: syncRules.parsed().sync_rules
28
- });
29
-
30
- const tablePatterns = syncRules.parsed().sync_rules.getSourceTables();
31
- const tableInfo = await walConnection.getDebugTablesInfo(tablePatterns);
32
- expect(tableInfo).toEqual([
33
- {
34
- schema: 'public',
35
- pattern: 'test_data',
36
- wildcard: false,
37
- table: {
38
- schema: 'public',
39
- name: 'test_data',
40
- replication_id: ['id'],
41
- pattern: undefined,
42
- data_queries: true,
43
- parameter_queries: false,
44
- errors: []
45
- }
46
- },
47
- {
48
- schema: 'public',
49
- pattern: 'other',
50
- wildcard: false,
51
- table: {
52
- schema: 'public',
53
- name: 'other',
54
- replication_id: [],
55
- data_queries: true,
56
- parameter_queries: false,
57
- errors: [{ level: 'warning', message: 'Table "public"."other" not found.' }]
58
- }
59
- },
60
- { schema: 'public', pattern: 'other%', wildcard: true, tables: [] }
61
- ]);
62
- })
63
- );