@powersync/service-core 0.8.8 → 0.9.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 (372) hide show
  1. package/CHANGELOG.md +31 -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/auth-index.d.ts +0 -1
  23. package/dist/auth/auth-index.js +0 -1
  24. package/dist/auth/auth-index.js.map +1 -1
  25. package/dist/db/mongo.js +5 -3
  26. package/dist/db/mongo.js.map +1 -1
  27. package/dist/entry/cli-entry.js +3 -2
  28. package/dist/entry/cli-entry.js.map +1 -1
  29. package/dist/entry/commands/compact-action.js +90 -14
  30. package/dist/entry/commands/compact-action.js.map +1 -1
  31. package/dist/entry/commands/migrate-action.js +4 -5
  32. package/dist/entry/commands/migrate-action.js.map +1 -1
  33. package/dist/entry/commands/teardown-action.js +2 -2
  34. package/dist/entry/commands/teardown-action.js.map +1 -1
  35. package/dist/index.d.ts +4 -2
  36. package/dist/index.js +4 -2
  37. package/dist/index.js.map +1 -1
  38. package/dist/locks/MongoLocks.js.map +1 -1
  39. package/dist/metrics/Metrics.d.ts +2 -2
  40. package/dist/metrics/Metrics.js +5 -13
  41. package/dist/metrics/Metrics.js.map +1 -1
  42. package/dist/migrations/db/migrations/1684951997326-init.d.ts +2 -2
  43. package/dist/migrations/db/migrations/1684951997326-init.js +4 -2
  44. package/dist/migrations/db/migrations/1684951997326-init.js.map +1 -1
  45. package/dist/migrations/db/migrations/1702295701188-sync-rule-state.d.ts +2 -2
  46. package/dist/migrations/db/migrations/1702295701188-sync-rule-state.js +4 -2
  47. package/dist/migrations/db/migrations/1702295701188-sync-rule-state.js.map +1 -1
  48. package/dist/migrations/db/migrations/1711543888062-write-checkpoint-index.d.ts +2 -2
  49. package/dist/migrations/db/migrations/1711543888062-write-checkpoint-index.js +4 -2
  50. package/dist/migrations/db/migrations/1711543888062-write-checkpoint-index.js.map +1 -1
  51. package/dist/migrations/db/migrations/1727099539247-custom-write-checkpoint-index.d.ts +3 -0
  52. package/dist/migrations/db/migrations/1727099539247-custom-write-checkpoint-index.js +31 -0
  53. package/dist/migrations/db/migrations/1727099539247-custom-write-checkpoint-index.js.map +1 -0
  54. package/dist/migrations/executor.js.map +1 -1
  55. package/dist/migrations/migrations.d.ts +8 -0
  56. package/dist/migrations/migrations.js +19 -7
  57. package/dist/migrations/migrations.js.map +1 -1
  58. package/dist/migrations/store/migration-store.js.map +1 -1
  59. package/dist/modules/AbstractModule.d.ts +26 -0
  60. package/dist/modules/AbstractModule.js +11 -0
  61. package/dist/modules/AbstractModule.js.map +1 -0
  62. package/dist/modules/ModuleManager.d.ts +11 -0
  63. package/dist/modules/ModuleManager.js +32 -0
  64. package/dist/modules/ModuleManager.js.map +1 -0
  65. package/dist/modules/modules-index.d.ts +2 -0
  66. package/dist/modules/modules-index.js +3 -0
  67. package/dist/modules/modules-index.js.map +1 -0
  68. package/dist/replication/AbstractReplicationJob.d.ts +37 -0
  69. package/dist/replication/AbstractReplicationJob.js +51 -0
  70. package/dist/replication/AbstractReplicationJob.js.map +1 -0
  71. package/dist/replication/AbstractReplicator.d.ts +53 -0
  72. package/dist/replication/AbstractReplicator.js +250 -0
  73. package/dist/replication/AbstractReplicator.js.map +1 -0
  74. package/dist/replication/ErrorRateLimiter.d.ts +0 -10
  75. package/dist/replication/ErrorRateLimiter.js +1 -42
  76. package/dist/replication/ErrorRateLimiter.js.map +1 -1
  77. package/dist/replication/ReplicationEngine.d.ts +18 -0
  78. package/dist/replication/ReplicationEngine.js +41 -0
  79. package/dist/replication/ReplicationEngine.js.map +1 -0
  80. package/dist/replication/ReplicationModule.d.ts +51 -0
  81. package/dist/replication/ReplicationModule.js +68 -0
  82. package/dist/replication/ReplicationModule.js.map +1 -0
  83. package/dist/replication/replication-index.d.ts +4 -6
  84. package/dist/replication/replication-index.js +4 -6
  85. package/dist/replication/replication-index.js.map +1 -1
  86. package/dist/routes/RouterEngine.d.ts +42 -0
  87. package/dist/routes/RouterEngine.js +80 -0
  88. package/dist/routes/RouterEngine.js.map +1 -0
  89. package/dist/routes/auth.d.ts +2 -2
  90. package/dist/routes/auth.js +11 -11
  91. package/dist/routes/auth.js.map +1 -1
  92. package/dist/routes/configure-fastify.d.ts +37 -23
  93. package/dist/routes/configure-fastify.js +18 -18
  94. package/dist/routes/configure-fastify.js.map +1 -1
  95. package/dist/routes/configure-rsocket.d.ts +3 -4
  96. package/dist/routes/configure-rsocket.js +7 -4
  97. package/dist/routes/configure-rsocket.js.map +1 -1
  98. package/dist/routes/endpoints/admin.d.ts +30 -0
  99. package/dist/routes/endpoints/admin.js +46 -67
  100. package/dist/routes/endpoints/admin.js.map +1 -1
  101. package/dist/routes/endpoints/checkpointing.js +103 -15
  102. package/dist/routes/endpoints/checkpointing.js.map +1 -1
  103. package/dist/routes/endpoints/socket-route.js +8 -6
  104. package/dist/routes/endpoints/socket-route.js.map +1 -1
  105. package/dist/routes/endpoints/sync-rules.d.ts +1 -1
  106. package/dist/routes/endpoints/sync-rules.js +32 -23
  107. package/dist/routes/endpoints/sync-rules.js.map +1 -1
  108. package/dist/routes/endpoints/sync-stream.d.ts +0 -1
  109. package/dist/routes/endpoints/sync-stream.js +8 -8
  110. package/dist/routes/endpoints/sync-stream.js.map +1 -1
  111. package/dist/routes/hooks.js.map +1 -1
  112. package/dist/routes/route-register.js.map +1 -1
  113. package/dist/routes/router.d.ts +9 -2
  114. package/dist/routes/router.js.map +1 -1
  115. package/dist/routes/routes-index.d.ts +1 -0
  116. package/dist/routes/routes-index.js +1 -0
  117. package/dist/routes/routes-index.js.map +1 -1
  118. package/dist/runner/teardown.js +109 -76
  119. package/dist/runner/teardown.js.map +1 -1
  120. package/dist/storage/BucketStorage.d.ts +86 -36
  121. package/dist/storage/BucketStorage.js +6 -10
  122. package/dist/storage/BucketStorage.js.map +1 -1
  123. package/dist/storage/ChecksumCache.js.map +1 -1
  124. package/dist/storage/MongoBucketStorage.d.ts +7 -11
  125. package/dist/storage/MongoBucketStorage.js +48 -41
  126. package/dist/storage/MongoBucketStorage.js.map +1 -1
  127. package/dist/storage/ReplicationEventPayload.d.ts +14 -0
  128. package/dist/storage/ReplicationEventPayload.js +2 -0
  129. package/dist/storage/ReplicationEventPayload.js.map +1 -0
  130. package/dist/storage/SourceEntity.d.ts +20 -0
  131. package/dist/storage/SourceEntity.js +2 -0
  132. package/dist/storage/SourceEntity.js.map +1 -0
  133. package/dist/storage/SourceTable.d.ts +12 -5
  134. package/dist/storage/SourceTable.js +12 -5
  135. package/dist/storage/SourceTable.js.map +1 -1
  136. package/dist/storage/StorageEngine.d.ts +28 -0
  137. package/dist/storage/StorageEngine.js +45 -0
  138. package/dist/storage/StorageEngine.js.map +1 -0
  139. package/dist/storage/StorageProvider.d.ts +21 -0
  140. package/dist/storage/StorageProvider.js +2 -0
  141. package/dist/storage/StorageProvider.js.map +1 -0
  142. package/dist/storage/WriteCheckpointAPI.d.ts +74 -0
  143. package/dist/storage/WriteCheckpointAPI.js +16 -0
  144. package/dist/storage/WriteCheckpointAPI.js.map +1 -0
  145. package/dist/storage/mongo/MongoBucketBatch.d.ts +24 -5
  146. package/dist/storage/mongo/MongoBucketBatch.js +119 -62
  147. package/dist/storage/mongo/MongoBucketBatch.js.map +1 -1
  148. package/dist/storage/mongo/MongoCompactor.js +20 -3
  149. package/dist/storage/mongo/MongoCompactor.js.map +1 -1
  150. package/dist/storage/mongo/MongoIdSequence.js.map +1 -1
  151. package/dist/storage/mongo/MongoPersistedSyncRulesContent.d.ts +2 -2
  152. package/dist/storage/mongo/MongoPersistedSyncRulesContent.js +2 -2
  153. package/dist/storage/mongo/MongoPersistedSyncRulesContent.js.map +1 -1
  154. package/dist/storage/mongo/MongoStorageProvider.d.ts +5 -0
  155. package/dist/storage/mongo/MongoStorageProvider.js +26 -0
  156. package/dist/storage/mongo/MongoStorageProvider.js.map +1 -0
  157. package/dist/storage/mongo/MongoSyncBucketStorage.d.ts +18 -10
  158. package/dist/storage/mongo/MongoSyncBucketStorage.js +140 -25
  159. package/dist/storage/mongo/MongoSyncBucketStorage.js.map +1 -1
  160. package/dist/storage/mongo/MongoSyncRulesLock.js +1 -1
  161. package/dist/storage/mongo/MongoSyncRulesLock.js.map +1 -1
  162. package/dist/storage/mongo/MongoWriteCheckpointAPI.d.ts +20 -0
  163. package/dist/storage/mongo/MongoWriteCheckpointAPI.js +103 -0
  164. package/dist/storage/mongo/MongoWriteCheckpointAPI.js.map +1 -0
  165. package/dist/storage/mongo/OperationBatch.d.ts +13 -4
  166. package/dist/storage/mongo/OperationBatch.js +25 -7
  167. package/dist/storage/mongo/OperationBatch.js.map +1 -1
  168. package/dist/storage/mongo/PersistedBatch.d.ts +3 -3
  169. package/dist/storage/mongo/PersistedBatch.js +2 -2
  170. package/dist/storage/mongo/PersistedBatch.js.map +1 -1
  171. package/dist/storage/mongo/config.d.ts +19 -0
  172. package/dist/storage/mongo/config.js +26 -0
  173. package/dist/storage/mongo/config.js.map +1 -0
  174. package/dist/storage/mongo/db.d.ts +3 -2
  175. package/dist/storage/mongo/db.js +1 -0
  176. package/dist/storage/mongo/db.js.map +1 -1
  177. package/dist/storage/mongo/models.d.ts +20 -5
  178. package/dist/storage/mongo/models.js.map +1 -1
  179. package/dist/storage/mongo/util.d.ts +12 -1
  180. package/dist/storage/mongo/util.js +50 -2
  181. package/dist/storage/mongo/util.js.map +1 -1
  182. package/dist/storage/storage-index.d.ts +8 -2
  183. package/dist/storage/storage-index.js +8 -2
  184. package/dist/storage/storage-index.js.map +1 -1
  185. package/dist/sync/BroadcastIterable.d.ts +0 -1
  186. package/dist/sync/BroadcastIterable.js.map +1 -1
  187. package/dist/sync/LastValueSink.d.ts +0 -1
  188. package/dist/sync/LastValueSink.js.map +1 -1
  189. package/dist/sync/merge.d.ts +0 -1
  190. package/dist/sync/merge.js.map +1 -1
  191. package/dist/sync/safeRace.js.map +1 -1
  192. package/dist/sync/sync.d.ts +1 -1
  193. package/dist/sync/sync.js +5 -5
  194. package/dist/sync/sync.js.map +1 -1
  195. package/dist/sync/util.d.ts +0 -2
  196. package/dist/sync/util.js.map +1 -1
  197. package/dist/system/ServiceContext.d.ts +37 -0
  198. package/dist/system/ServiceContext.js +48 -0
  199. package/dist/system/ServiceContext.js.map +1 -0
  200. package/dist/system/system-index.d.ts +1 -1
  201. package/dist/system/system-index.js +1 -1
  202. package/dist/system/system-index.js.map +1 -1
  203. package/dist/util/Mutex.js.map +1 -1
  204. package/dist/util/config/collectors/config-collector.js.map +1 -1
  205. package/dist/util/config/collectors/impl/base64-config-collector.js.map +1 -1
  206. package/dist/util/config/collectors/impl/filesystem-config-collector.js.map +1 -1
  207. package/dist/util/config/compound-config-collector.d.ts +9 -2
  208. package/dist/util/config/compound-config-collector.js +16 -24
  209. package/dist/util/config/compound-config-collector.js.map +1 -1
  210. package/dist/util/config/sync-rules/impl/base64-sync-rules-collector.js.map +1 -1
  211. package/dist/util/config/sync-rules/impl/filesystem-sync-rules-collector.js.map +1 -1
  212. package/dist/util/config/sync-rules/impl/inline-sync-rules-collector.js.map +1 -1
  213. package/dist/util/config/sync-rules/sync-rules-provider.d.ts +9 -0
  214. package/dist/util/config/sync-rules/sync-rules-provider.js +15 -0
  215. package/dist/util/config/sync-rules/sync-rules-provider.js.map +1 -0
  216. package/dist/util/config/types.d.ts +7 -4
  217. package/dist/util/config/types.js.map +1 -1
  218. package/dist/util/config.d.ts +3 -4
  219. package/dist/util/config.js +5 -20
  220. package/dist/util/config.js.map +1 -1
  221. package/dist/util/memory-tracking.js.map +1 -1
  222. package/dist/util/secs.js.map +1 -1
  223. package/dist/util/util-index.d.ts +3 -6
  224. package/dist/util/util-index.js +3 -6
  225. package/dist/util/util-index.js.map +1 -1
  226. package/dist/util/utils.d.ts +10 -7
  227. package/dist/util/utils.js +36 -25
  228. package/dist/util/utils.js.map +1 -1
  229. package/package.json +8 -12
  230. package/src/api/RouteAPI.ts +78 -0
  231. package/src/api/api-index.ts +1 -0
  232. package/src/api/diagnostics.ts +18 -70
  233. package/src/api/schema.ts +18 -90
  234. package/src/auth/KeyStore.ts +9 -6
  235. package/src/auth/RemoteJWKSCollector.ts +4 -1
  236. package/src/auth/auth-index.ts +0 -1
  237. package/src/db/mongo.ts +5 -3
  238. package/src/entry/cli-entry.ts +3 -2
  239. package/src/entry/commands/compact-action.ts +24 -12
  240. package/src/entry/commands/migrate-action.ts +5 -8
  241. package/src/entry/commands/teardown-action.ts +2 -2
  242. package/src/index.ts +5 -2
  243. package/src/metrics/Metrics.ts +6 -16
  244. package/src/migrations/db/migrations/1684951997326-init.ts +9 -4
  245. package/src/migrations/db/migrations/1702295701188-sync-rule-state.ts +7 -4
  246. package/src/migrations/db/migrations/1711543888062-write-checkpoint-index.ts +6 -4
  247. package/src/migrations/db/migrations/1727099539247-custom-write-checkpoint-index.ts +37 -0
  248. package/src/migrations/migrations.ts +24 -8
  249. package/src/modules/AbstractModule.ts +37 -0
  250. package/src/modules/ModuleManager.ts +34 -0
  251. package/src/modules/modules-index.ts +2 -0
  252. package/src/replication/AbstractReplicationJob.ts +79 -0
  253. package/src/replication/AbstractReplicator.ts +228 -0
  254. package/src/replication/ErrorRateLimiter.ts +0 -44
  255. package/src/replication/ReplicationEngine.ts +43 -0
  256. package/src/replication/ReplicationModule.ts +122 -0
  257. package/src/replication/replication-index.ts +4 -6
  258. package/src/routes/RouterEngine.ts +120 -0
  259. package/src/routes/auth.ts +21 -12
  260. package/src/routes/configure-fastify.ts +26 -27
  261. package/src/routes/configure-rsocket.ts +13 -8
  262. package/src/routes/endpoints/admin.ts +72 -76
  263. package/src/routes/endpoints/checkpointing.ts +51 -11
  264. package/src/routes/endpoints/socket-route.ts +10 -6
  265. package/src/routes/endpoints/sync-rules.ts +41 -25
  266. package/src/routes/endpoints/sync-stream.ts +8 -8
  267. package/src/routes/router.ts +8 -3
  268. package/src/routes/routes-index.ts +1 -0
  269. package/src/runner/teardown.ts +50 -88
  270. package/src/storage/BucketStorage.ts +103 -41
  271. package/src/storage/MongoBucketStorage.ts +65 -53
  272. package/src/storage/ReplicationEventPayload.ts +16 -0
  273. package/src/storage/SourceEntity.ts +22 -0
  274. package/src/storage/SourceTable.ts +14 -7
  275. package/src/storage/StorageEngine.ts +62 -0
  276. package/src/storage/StorageProvider.ts +27 -0
  277. package/src/storage/WriteCheckpointAPI.ts +85 -0
  278. package/src/storage/mongo/MongoBucketBatch.ts +164 -84
  279. package/src/storage/mongo/MongoCompactor.ts +25 -4
  280. package/src/storage/mongo/MongoPersistedSyncRulesContent.ts +7 -4
  281. package/src/storage/mongo/MongoStorageProvider.ts +31 -0
  282. package/src/storage/mongo/MongoSyncBucketStorage.ts +118 -41
  283. package/src/storage/mongo/MongoSyncRulesLock.ts +7 -3
  284. package/src/storage/mongo/MongoWriteCheckpointAPI.ts +151 -0
  285. package/src/storage/mongo/OperationBatch.ts +28 -12
  286. package/src/storage/mongo/PersistedBatch.ts +10 -6
  287. package/src/storage/mongo/config.ts +40 -0
  288. package/src/storage/mongo/db.ts +4 -1
  289. package/src/storage/mongo/models.ts +21 -5
  290. package/src/storage/mongo/util.ts +48 -3
  291. package/src/storage/storage-index.ts +8 -2
  292. package/src/sync/sync.ts +7 -4
  293. package/src/sync/util.ts +0 -1
  294. package/src/system/ServiceContext.ts +68 -0
  295. package/src/system/system-index.ts +1 -1
  296. package/src/util/config/compound-config-collector.ts +31 -31
  297. package/src/util/config/sync-rules/sync-rules-provider.ts +18 -0
  298. package/src/util/config/types.ts +7 -5
  299. package/src/util/config.ts +6 -23
  300. package/src/util/util-index.ts +3 -6
  301. package/src/util/utils.ts +48 -41
  302. package/test/src/__snapshots__/sync.test.ts.snap +14 -14
  303. package/test/src/auth.test.ts +7 -7
  304. package/test/src/broadcast_iterable.test.ts +1 -1
  305. package/test/src/compacting.test.ts +50 -40
  306. package/test/src/data_storage.test.ts +382 -202
  307. package/test/src/env.ts +1 -3
  308. package/test/src/merge_iterable.test.ts +1 -6
  309. package/test/src/routes/probes.integration.test.ts +34 -30
  310. package/test/src/setup.ts +1 -1
  311. package/test/src/stream_utils.ts +42 -0
  312. package/test/src/sync.test.ts +115 -39
  313. package/test/src/util.ts +48 -51
  314. package/test/tsconfig.json +1 -1
  315. package/tsconfig.tsbuildinfo +1 -1
  316. package/vitest.config.ts +7 -1
  317. package/dist/auth/SupabaseKeyCollector.d.ts +0 -22
  318. package/dist/auth/SupabaseKeyCollector.js +0 -61
  319. package/dist/auth/SupabaseKeyCollector.js.map +0 -1
  320. package/dist/replication/PgRelation.d.ts +0 -16
  321. package/dist/replication/PgRelation.js +0 -26
  322. package/dist/replication/PgRelation.js.map +0 -1
  323. package/dist/replication/WalConnection.d.ts +0 -34
  324. package/dist/replication/WalConnection.js +0 -190
  325. package/dist/replication/WalConnection.js.map +0 -1
  326. package/dist/replication/WalStream.d.ts +0 -57
  327. package/dist/replication/WalStream.js +0 -519
  328. package/dist/replication/WalStream.js.map +0 -1
  329. package/dist/replication/WalStreamManager.d.ts +0 -30
  330. package/dist/replication/WalStreamManager.js +0 -198
  331. package/dist/replication/WalStreamManager.js.map +0 -1
  332. package/dist/replication/WalStreamRunner.d.ts +0 -38
  333. package/dist/replication/WalStreamRunner.js +0 -155
  334. package/dist/replication/WalStreamRunner.js.map +0 -1
  335. package/dist/replication/util.d.ts +0 -9
  336. package/dist/replication/util.js +0 -62
  337. package/dist/replication/util.js.map +0 -1
  338. package/dist/system/CorePowerSyncSystem.d.ts +0 -23
  339. package/dist/system/CorePowerSyncSystem.js +0 -52
  340. package/dist/system/CorePowerSyncSystem.js.map +0 -1
  341. package/dist/util/PgManager.d.ts +0 -24
  342. package/dist/util/PgManager.js +0 -55
  343. package/dist/util/PgManager.js.map +0 -1
  344. package/dist/util/migration_lib.d.ts +0 -11
  345. package/dist/util/migration_lib.js +0 -64
  346. package/dist/util/migration_lib.js.map +0 -1
  347. package/dist/util/pgwire_utils.d.ts +0 -24
  348. package/dist/util/pgwire_utils.js +0 -117
  349. package/dist/util/pgwire_utils.js.map +0 -1
  350. package/dist/util/populate_test_data.d.ts +0 -8
  351. package/dist/util/populate_test_data.js +0 -65
  352. package/dist/util/populate_test_data.js.map +0 -1
  353. package/src/auth/SupabaseKeyCollector.ts +0 -67
  354. package/src/replication/PgRelation.ts +0 -42
  355. package/src/replication/WalConnection.ts +0 -227
  356. package/src/replication/WalStream.ts +0 -631
  357. package/src/replication/WalStreamManager.ts +0 -213
  358. package/src/replication/WalStreamRunner.ts +0 -180
  359. package/src/replication/util.ts +0 -76
  360. package/src/system/CorePowerSyncSystem.ts +0 -64
  361. package/src/util/PgManager.ts +0 -64
  362. package/src/util/migration_lib.ts +0 -79
  363. package/src/util/pgwire_utils.ts +0 -139
  364. package/src/util/populate_test_data.ts +0 -78
  365. package/test/src/__snapshots__/pg_test.test.ts.snap +0 -256
  366. package/test/src/large_batch.test.ts +0 -194
  367. package/test/src/pg_test.test.ts +0 -450
  368. package/test/src/schema_changes.test.ts +0 -545
  369. package/test/src/slow_tests.test.ts +0 -338
  370. package/test/src/validation.test.ts +0 -63
  371. package/test/src/wal_stream.test.ts +0 -319
  372. package/test/src/wal_stream_utils.ts +0 -156
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
 
@@ -6,8 +6,8 @@ import * as system from '../../../src/system/system-index.js';
6
6
  import { configureFastifyServer } from '../../../src/index.js';
7
7
  import { ProbeRoutes } from '../../../src/routes/endpoints/probes.js';
8
8
 
9
- vi.mock("@powersync/lib-services-framework", async () => {
10
- const actual = await vi.importActual("@powersync/lib-services-framework") as any;
9
+ vi.mock('@powersync/lib-services-framework', async () => {
10
+ const actual = (await vi.importActual('@powersync/lib-services-framework')) as any;
11
11
  return {
12
12
  ...actual,
13
13
  container: {
@@ -15,18 +15,18 @@ vi.mock("@powersync/lib-services-framework", async () => {
15
15
  probes: {
16
16
  state: vi.fn()
17
17
  }
18
- },
19
- }
20
- })
18
+ }
19
+ };
20
+ });
21
21
 
22
22
  describe('Probe Routes Integration', () => {
23
23
  let app: FastifyInstance;
24
- let mockSystem: system.CorePowerSyncSystem;
24
+ let mockSystem: system.ServiceContext;
25
25
 
26
26
  beforeEach(async () => {
27
27
  app = Fastify();
28
- mockSystem = {} as system.CorePowerSyncSystem;
29
- await configureFastifyServer(app, { system: mockSystem });
28
+ mockSystem = { routerEngine: {} } as system.ServiceContext;
29
+ await configureFastifyServer(app, { service_context: mockSystem });
30
30
  await app.ready();
31
31
  });
32
32
 
@@ -46,7 +46,7 @@ describe('Probe Routes Integration', () => {
46
46
 
47
47
  const response = await app.inject({
48
48
  method: 'GET',
49
- url: ProbeRoutes.STARTUP,
49
+ url: ProbeRoutes.STARTUP
50
50
  });
51
51
 
52
52
  expect(response.statusCode).toBe(200);
@@ -67,7 +67,7 @@ describe('Probe Routes Integration', () => {
67
67
 
68
68
  const response = await app.inject({
69
69
  method: 'GET',
70
- url: ProbeRoutes.STARTUP,
70
+ url: ProbeRoutes.STARTUP
71
71
  });
72
72
 
73
73
  expect(response.statusCode).toBe(400);
@@ -90,7 +90,7 @@ describe('Probe Routes Integration', () => {
90
90
 
91
91
  const response = await app.inject({
92
92
  method: 'GET',
93
- url: ProbeRoutes.LIVENESS,
93
+ url: ProbeRoutes.LIVENESS
94
94
  });
95
95
 
96
96
  expect(response.statusCode).toBe(200);
@@ -111,7 +111,7 @@ describe('Probe Routes Integration', () => {
111
111
 
112
112
  const response = await app.inject({
113
113
  method: 'GET',
114
- url: ProbeRoutes.LIVENESS,
114
+ url: ProbeRoutes.LIVENESS
115
115
  });
116
116
 
117
117
  expect(response.statusCode).toBe(400);
@@ -134,7 +134,7 @@ describe('Probe Routes Integration', () => {
134
134
 
135
135
  const response = await app.inject({
136
136
  method: 'GET',
137
- url: ProbeRoutes.READINESS,
137
+ url: ProbeRoutes.READINESS
138
138
  });
139
139
 
140
140
  expect(response.statusCode).toBe(200);
@@ -155,7 +155,7 @@ describe('Probe Routes Integration', () => {
155
155
 
156
156
  const response = await app.inject({
157
157
  method: 'GET',
158
- url: ProbeRoutes.READINESS,
158
+ url: ProbeRoutes.READINESS
159
159
  });
160
160
 
161
161
  expect(response.statusCode).toBe(400);
@@ -172,17 +172,19 @@ describe('Probe Routes Integration', () => {
172
172
  vi.mocked(container.probes.state).mockReturnValue(mockState);
173
173
 
174
174
  // Create array of 15 concurrent requests (default concurrency is 10)
175
- const requests = Array(15).fill(null).map(() =>
176
- app.inject({
177
- method: 'GET',
178
- url: ProbeRoutes.STARTUP,
179
- })
180
- );
175
+ const requests = Array(15)
176
+ .fill(null)
177
+ .map(() =>
178
+ app.inject({
179
+ method: 'GET',
180
+ url: ProbeRoutes.STARTUP
181
+ })
182
+ );
181
183
 
182
184
  const responses = await Promise.all(requests);
183
185
 
184
186
  // All requests should complete successfully
185
- responses.forEach(response => {
187
+ responses.forEach((response) => {
186
188
  expect(response.statusCode).toBe(200);
187
189
  expect(JSON.parse(response.payload)).toEqual({
188
190
  ...mockState,
@@ -196,18 +198,20 @@ describe('Probe Routes Integration', () => {
196
198
  vi.mocked(container.probes.state).mockReturnValue(mockState);
197
199
 
198
200
  // Create array of 35 concurrent requests (default max_queue_depth is 20)
199
- const requests = Array(35).fill(null).map(() =>
200
- app.inject({
201
- method: 'GET',
202
- url: ProbeRoutes.STARTUP,
203
- })
204
- );
201
+ const requests = Array(35)
202
+ .fill(null)
203
+ .map(() =>
204
+ app.inject({
205
+ method: 'GET',
206
+ url: ProbeRoutes.STARTUP
207
+ })
208
+ );
205
209
 
206
210
  const responses = await Promise.all(requests);
207
211
 
208
212
  // Some requests should succeed and some should fail with 429
209
- const successCount = responses.filter(r => r.statusCode === 200).length;
210
- const queueFullCount = responses.filter(r => r.statusCode === 429).length;
213
+ const successCount = responses.filter((r) => r.statusCode === 200).length;
214
+ const queueFullCount = responses.filter((r) => r.statusCode === 429).length;
211
215
 
212
216
  expect(successCount).toBeGreaterThan(0);
213
217
  expect(queueFullCount).toBeGreaterThan(0);
@@ -222,7 +226,7 @@ describe('Probe Routes Integration', () => {
222
226
 
223
227
  const response = await app.inject({
224
228
  method: 'GET',
225
- url: ProbeRoutes.STARTUP,
229
+ url: ProbeRoutes.STARTUP
226
230
  });
227
231
 
228
232
  expect(response.headers['content-type']).toMatch(/application\/json/);
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,12 +1,12 @@
1
+ import { SaveOperationTag } from '@/storage/storage-index.js';
1
2
  import { RequestTracker } from '@/sync/RequestTracker.js';
3
+ import { streamResponse, SyncStreamParameters } from '@/sync/sync.js';
2
4
  import { StreamingSyncLine } from '@/util/protocol-types.js';
3
- import { lsnMakeComparable } from '@powersync/service-jpgwire';
4
5
  import { JSONBig } from '@powersync/service-jsonbig';
5
6
  import { RequestParameters } from '@powersync/service-sync-rules';
6
7
  import * as timers from 'timers/promises';
7
8
  import { describe, expect, test } from 'vitest';
8
- import { streamResponse } from '../../src/sync/sync.js';
9
- import { makeTestTable, MONGO_STORAGE_FACTORY, StorageFactory } from './util.js';
9
+ import { BATCH_OPTIONS, makeTestTable, MONGO_STORAGE_FACTORY, PARSE_OPTIONS, StorageFactory } from './util.js';
10
10
 
11
11
  describe('sync - mongodb', function () {
12
12
  defineTests(MONGO_STORAGE_FACTORY);
@@ -31,29 +31,31 @@ function defineTests(factory: StorageFactory) {
31
31
  content: BASIC_SYNC_RULES
32
32
  });
33
33
 
34
- const storage = await f.getInstance(syncRules.parsed());
34
+ const storage = f.getInstance(syncRules);
35
35
  await storage.autoActivate();
36
36
 
37
- const result = await storage.startBatch({}, async (batch) => {
37
+ const result = await storage.startBatch(BATCH_OPTIONS, async (batch) => {
38
38
  await batch.save({
39
39
  sourceTable: TEST_TABLE,
40
- tag: 'insert',
40
+ tag: SaveOperationTag.INSERT,
41
41
  after: {
42
42
  id: 't1',
43
43
  description: 'Test 1'
44
- }
44
+ },
45
+ afterReplicaId: 't1'
45
46
  });
46
47
 
47
48
  await batch.save({
48
49
  sourceTable: TEST_TABLE,
49
- tag: 'insert',
50
+ tag: SaveOperationTag.INSERT,
50
51
  after: {
51
52
  id: 't2',
52
53
  description: 'Test 2'
53
- }
54
+ },
55
+ afterReplicaId: 't2'
54
56
  });
55
57
 
56
- await batch.commit(lsnMakeComparable('0/1'));
58
+ await batch.commit('0/1');
57
59
  });
58
60
 
59
61
  const stream = streamResponse({
@@ -63,6 +65,7 @@ function defineTests(factory: StorageFactory) {
63
65
  include_checksum: true,
64
66
  raw_data: true
65
67
  },
68
+ parseOptions: PARSE_OPTIONS,
66
69
  tracker,
67
70
  syncParams: new RequestParameters({ sub: '' }, {}),
68
71
  token: { exp: Date.now() / 1000 + 10 } as any
@@ -79,21 +82,22 @@ function defineTests(factory: StorageFactory) {
79
82
  content: BASIC_SYNC_RULES
80
83
  });
81
84
 
82
- const storage = await f.getInstance(syncRules.parsed());
85
+ const storage = await f.getInstance(syncRules);
83
86
  await storage.autoActivate();
84
87
 
85
- const result = await storage.startBatch({}, async (batch) => {
88
+ const result = await storage.startBatch(BATCH_OPTIONS, async (batch) => {
86
89
  await batch.save({
87
90
  sourceTable: TEST_TABLE,
88
- tag: 'insert',
91
+ tag: SaveOperationTag.INSERT,
89
92
  after: {
90
93
  id: 't1',
91
94
  description: 'Test\n"string"',
92
95
  large_num: 12345678901234567890n
93
- }
96
+ },
97
+ afterReplicaId: 't1'
94
98
  });
95
99
 
96
- await batch.commit(lsnMakeComparable('0/1'));
100
+ await batch.commit('0/1');
97
101
  });
98
102
 
99
103
  const stream = streamResponse({
@@ -103,6 +107,7 @@ function defineTests(factory: StorageFactory) {
103
107
  include_checksum: true,
104
108
  raw_data: false
105
109
  },
110
+ parseOptions: PARSE_OPTIONS,
106
111
  tracker,
107
112
  syncParams: new RequestParameters({ sub: '' }, {}),
108
113
  token: { exp: Date.now() / 1000 + 10 } as any
@@ -121,7 +126,7 @@ function defineTests(factory: StorageFactory) {
121
126
  content: BASIC_SYNC_RULES
122
127
  });
123
128
 
124
- const storage = await f.getInstance(syncRules.parsed());
129
+ const storage = await f.getInstance(syncRules);
125
130
  await storage.autoActivate();
126
131
 
127
132
  const stream = streamResponse({
@@ -131,6 +136,7 @@ function defineTests(factory: StorageFactory) {
131
136
  include_checksum: true,
132
137
  raw_data: true
133
138
  },
139
+ parseOptions: PARSE_OPTIONS,
134
140
  tracker,
135
141
  syncParams: new RequestParameters({ sub: '' }, {}),
136
142
  token: { exp: 0 } as any
@@ -147,7 +153,7 @@ function defineTests(factory: StorageFactory) {
147
153
  content: BASIC_SYNC_RULES
148
154
  });
149
155
 
150
- const storage = await f.getInstance(syncRules.parsed());
156
+ const storage = await f.getInstance(syncRules);
151
157
  await storage.autoActivate();
152
158
 
153
159
  const stream = streamResponse({
@@ -157,6 +163,7 @@ function defineTests(factory: StorageFactory) {
157
163
  include_checksum: true,
158
164
  raw_data: true
159
165
  },
166
+ parseOptions: PARSE_OPTIONS,
160
167
  tracker,
161
168
  syncParams: new RequestParameters({ sub: '' }, {}),
162
169
  token: { exp: Date.now() / 1000 + 10 } as any
@@ -165,32 +172,34 @@ function defineTests(factory: StorageFactory) {
165
172
 
166
173
  expect(await getCheckpointLines(iter)).toMatchSnapshot();
167
174
 
168
- await storage.startBatch({}, async (batch) => {
175
+ await storage.startBatch(BATCH_OPTIONS, async (batch) => {
169
176
  await batch.save({
170
177
  sourceTable: TEST_TABLE,
171
- tag: 'insert',
178
+ tag: SaveOperationTag.INSERT,
172
179
  after: {
173
180
  id: 't1',
174
181
  description: 'Test 1'
175
- }
182
+ },
183
+ afterReplicaId: 't1'
176
184
  });
177
185
 
178
- await batch.commit(lsnMakeComparable('0/1'));
186
+ await batch.commit('0/1');
179
187
  });
180
188
 
181
189
  expect(await getCheckpointLines(iter)).toMatchSnapshot();
182
190
 
183
- await storage.startBatch({}, async (batch) => {
191
+ await storage.startBatch(BATCH_OPTIONS, async (batch) => {
184
192
  await batch.save({
185
193
  sourceTable: TEST_TABLE,
186
- tag: 'insert',
194
+ tag: SaveOperationTag.INSERT,
187
195
  after: {
188
196
  id: 't2',
189
197
  description: 'Test 2'
190
- }
198
+ },
199
+ afterReplicaId: 't2'
191
200
  });
192
201
 
193
- await batch.commit(lsnMakeComparable('0/2'));
202
+ await batch.commit('0/2');
194
203
  });
195
204
 
196
205
  expect(await getCheckpointLines(iter)).toMatchSnapshot();
@@ -205,7 +214,7 @@ function defineTests(factory: StorageFactory) {
205
214
  content: BASIC_SYNC_RULES
206
215
  });
207
216
 
208
- const storage = await f.getInstance(syncRules.parsed());
217
+ const storage = await f.getInstance(syncRules);
209
218
  await storage.autoActivate();
210
219
 
211
220
  const exp = Date.now() / 1000 + 0.1;
@@ -217,6 +226,7 @@ function defineTests(factory: StorageFactory) {
217
226
  include_checksum: true,
218
227
  raw_data: true
219
228
  },
229
+ parseOptions: PARSE_OPTIONS,
220
230
  tracker,
221
231
  syncParams: new RequestParameters({ sub: '' }, {}),
222
232
  token: { exp: exp } as any
@@ -242,29 +252,31 @@ function defineTests(factory: StorageFactory) {
242
252
  content: BASIC_SYNC_RULES
243
253
  });
244
254
 
245
- const storage = await f.getInstance(syncRules.parsed());
255
+ const storage = await f.getInstance(syncRules);
246
256
  await storage.autoActivate();
247
257
 
248
- await storage.startBatch({}, async (batch) => {
258
+ await storage.startBatch(BATCH_OPTIONS, async (batch) => {
249
259
  await batch.save({
250
260
  sourceTable: TEST_TABLE,
251
- tag: 'insert',
261
+ tag: SaveOperationTag.INSERT,
252
262
  after: {
253
263
  id: 't1',
254
264
  description: 'Test 1'
255
- }
265
+ },
266
+ afterReplicaId: 't1'
256
267
  });
257
268
 
258
269
  await batch.save({
259
270
  sourceTable: TEST_TABLE,
260
- tag: 'insert',
271
+ tag: SaveOperationTag.INSERT,
261
272
  after: {
262
273
  id: 't2',
263
274
  description: 'Test 2'
264
- }
275
+ },
276
+ afterReplicaId: 't2'
265
277
  });
266
278
 
267
- await batch.commit(lsnMakeComparable('0/1'));
279
+ await batch.commit('0/1');
268
280
  });
269
281
 
270
282
  const stream = streamResponse({
@@ -274,6 +286,7 @@ function defineTests(factory: StorageFactory) {
274
286
  include_checksum: true,
275
287
  raw_data: true
276
288
  },
289
+ parseOptions: PARSE_OPTIONS,
277
290
  tracker,
278
291
  syncParams: new RequestParameters({ sub: '' }, {}),
279
292
  token: { exp: Date.now() / 1000 + 10 } as any
@@ -293,26 +306,28 @@ function defineTests(factory: StorageFactory) {
293
306
  // Now we save additional data AND compact before continuing.
294
307
  // This invalidates the checkpoint we've received above.
295
308
 
296
- await storage.startBatch({}, async (batch) => {
309
+ await storage.startBatch(BATCH_OPTIONS, async (batch) => {
297
310
  await batch.save({
298
311
  sourceTable: TEST_TABLE,
299
- tag: 'update',
312
+ tag: SaveOperationTag.UPDATE,
300
313
  after: {
301
314
  id: 't1',
302
315
  description: 'Test 1b'
303
- }
316
+ },
317
+ afterReplicaId: 't1'
304
318
  });
305
319
 
306
320
  await batch.save({
307
321
  sourceTable: TEST_TABLE,
308
- tag: 'update',
322
+ tag: SaveOperationTag.UPDATE,
309
323
  after: {
310
324
  id: 't2',
311
325
  description: 'Test 2b'
312
- }
326
+ },
327
+ afterReplicaId: 't2'
313
328
  });
314
329
 
315
- await batch.commit(lsnMakeComparable('0/2'));
330
+ await batch.commit('0/2');
316
331
  });
317
332
 
318
333
  await storage.compact();
@@ -366,6 +381,67 @@ function defineTests(factory: StorageFactory) {
366
381
  })
367
382
  });
368
383
  });
384
+
385
+ test('write checkpoint', async () => {
386
+ const f = await factory();
387
+
388
+ const syncRules = await f.updateSyncRules({
389
+ content: BASIC_SYNC_RULES
390
+ });
391
+
392
+ const storage = f.getInstance(syncRules);
393
+ await storage.autoActivate();
394
+
395
+ await storage.startBatch(BATCH_OPTIONS, async (batch) => {
396
+ // <= the managed write checkpoint LSN below
397
+ await batch.commit('0/1');
398
+ });
399
+
400
+ const checkpoint = await storage.createManagedWriteCheckpoint({
401
+ user_id: 'test',
402
+ heads: { '1': '1/0' }
403
+ });
404
+
405
+ const params: SyncStreamParameters = {
406
+ storage: f,
407
+ params: {
408
+ buckets: [],
409
+ include_checksum: true,
410
+ raw_data: true
411
+ },
412
+ parseOptions: PARSE_OPTIONS,
413
+ tracker,
414
+ syncParams: new RequestParameters({ sub: 'test' }, {}),
415
+ token: { sub: 'test', exp: Date.now() / 1000 + 10 } as any
416
+ };
417
+ const stream1 = streamResponse(params);
418
+ const lines1 = await consumeCheckpointLines(stream1);
419
+
420
+ // If write checkpoints are not correctly filtered, this may already
421
+ // contain the write checkpoint.
422
+ expect(lines1[0]).toMatchObject({
423
+ checkpoint: expect.objectContaining({
424
+ last_op_id: '0',
425
+ write_checkpoint: undefined
426
+ })
427
+ });
428
+
429
+ await storage.startBatch(BATCH_OPTIONS, async (batch) => {
430
+ // must be >= the managed write checkpoint LSN
431
+ await batch.commit('1/0');
432
+ });
433
+
434
+ // At this point the LSN has advanced, so the write checkpoint should be
435
+ // included in the next checkpoint message.
436
+ const stream2 = streamResponse(params);
437
+ const lines2 = await consumeCheckpointLines(stream2);
438
+ expect(lines2[0]).toMatchObject({
439
+ checkpoint: expect.objectContaining({
440
+ last_op_id: '0',
441
+ write_checkpoint: `${checkpoint}`
442
+ })
443
+ });
444
+ });
369
445
  }
370
446
 
371
447
  /**