@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/src/util/utils.ts CHANGED
@@ -1,15 +1,21 @@
1
+ import * as sync_rules from '@powersync/service-sync-rules';
2
+ import * as bson from 'bson';
1
3
  import crypto from 'crypto';
4
+ import * as uuid from 'uuid';
5
+ import { BucketChecksum, OpId } from './protocol-types.js';
2
6
 
3
- import { logger } from '@powersync/lib-services-framework';
4
- import * as pgwire from '@powersync/service-jpgwire';
5
- import { pgwireRows } from '@powersync/service-jpgwire';
6
- import { PartialChecksum } from '../storage/ChecksumCache.js';
7
7
  import * as storage from '../storage/storage-index.js';
8
- import { retriedQuery } from './pgwire_utils.js';
9
- import { BucketChecksum, OpId } from './protocol-types.js';
8
+
9
+ import { PartialChecksum } from '../storage/ChecksumCache.js';
10
10
 
11
11
  export type ChecksumMap = Map<string, BucketChecksum>;
12
12
 
13
+ export const ID_NAMESPACE = 'a396dd91-09fc-4017-a28d-3df722f651e9';
14
+
15
+ export function escapeIdentifier(identifier: string) {
16
+ return `"${identifier.replace(/"/g, '""').replace(/\./g, '"."')}"`;
17
+ }
18
+
13
19
  export function hashData(type: string, id: string, data: string): number {
14
20
  const hash = crypto.createHash('sha256');
15
21
  hash.update(`put.${type}.${id}.${data}`);
@@ -83,49 +89,50 @@ export function addBucketChecksums(a: BucketChecksum, b: PartialChecksum | null)
83
89
  }
84
90
  }
85
91
 
86
- export async function getClientCheckpoint(
87
- db: pgwire.PgClient,
88
- bucketStorage: storage.BucketStorageFactory,
89
- options?: { timeout?: number }
90
- ): Promise<OpId> {
91
- const start = Date.now();
92
+ function getRawReplicaIdentity(
93
+ tuple: sync_rules.ToastableSqliteRow,
94
+ columns: storage.ColumnDescriptor[]
95
+ ): Record<string, any> {
96
+ let result: Record<string, any> = {};
97
+ for (let column of columns) {
98
+ const name = column.name;
99
+ result[name] = tuple[name];
100
+ }
101
+ return result;
102
+ }
92
103
 
93
- const [{ lsn }] = pgwireRows(await db.query(`SELECT pg_logical_emit_message(false, 'powersync', 'ping') as lsn`));
104
+ export function getUuidReplicaIdentityBson(
105
+ tuple: sync_rules.ToastableSqliteRow,
106
+ columns: storage.ColumnDescriptor[]
107
+ ): bson.UUID {
108
+ if (columns.length == 0) {
109
+ // REPLICA IDENTITY NOTHING - generate random id
110
+ return new bson.UUID(uuid.v4());
111
+ }
112
+ const rawIdentity = getRawReplicaIdentity(tuple, columns);
94
113
 
95
- // This old API needs a persisted checkpoint id.
96
- // Since we don't use LSNs anymore, the only way to get that is to wait.
114
+ return uuidForRowBson(rawIdentity);
115
+ }
97
116
 
98
- const timeout = options?.timeout ?? 50_000;
117
+ export function uuidForRowBson(row: sync_rules.SqliteRow): bson.UUID {
118
+ // Important: This must not change, since it will affect how ids are generated.
119
+ // Use BSON so that it's a well-defined format without encoding ambiguities.
120
+ const repr = bson.serialize(row);
121
+ const buffer = Buffer.alloc(16);
122
+ return new bson.UUID(uuid.v5(repr, ID_NAMESPACE, buffer));
123
+ }
99
124
 
100
- logger.info(`Waiting for LSN checkpoint: ${lsn}`);
101
- while (Date.now() - start < timeout) {
102
- const cp = await bucketStorage.getActiveCheckpoint();
103
- if (!cp.hasSyncRules()) {
104
- throw new Error('No sync rules available');
105
- }
106
- if (cp.lsn >= lsn) {
107
- logger.info(`Got write checkpoint: ${lsn} : ${cp.checkpoint}`);
108
- return cp.checkpoint;
125
+ export function hasToastedValues(row: sync_rules.ToastableSqliteRow) {
126
+ for (let key in row) {
127
+ if (typeof row[key] == 'undefined') {
128
+ return true;
109
129
  }
110
-
111
- await new Promise((resolve) => setTimeout(resolve, 30));
112
130
  }
113
-
114
- throw new Error('Timeout while waiting for checkpoint');
131
+ return false;
115
132
  }
116
133
 
117
- export async function createWriteCheckpoint(
118
- db: pgwire.PgClient,
119
- bucketStorage: storage.BucketStorageFactory,
120
- user_id: string
121
- ): Promise<bigint> {
122
- const [{ lsn }] = pgwireRows(
123
- await retriedQuery(db, `SELECT pg_logical_emit_message(false, 'powersync', 'ping') as lsn`)
124
- );
125
-
126
- const id = await bucketStorage.createWriteCheckpoint(user_id, { '1': lsn });
127
- logger.info(`Write checkpoint 2: ${JSON.stringify({ lsn, id: String(id) })}`);
128
- return id;
134
+ export function isCompleteRow(row: sync_rules.ToastableSqliteRow): row is sync_rules.SqliteRow {
135
+ return !hasToastedValues(row);
129
136
  }
130
137
 
131
138
  export function checkpointUserId(user_id: string | undefined, client_id: string | undefined) {
@@ -56,21 +56,21 @@ exports[`sync - mongodb > compacting data - invalidate checkpoint 2`] = `
56
56
  "data": [
57
57
  {
58
58
  "checksum": 1859363232n,
59
- "data": "{\\"id\\":\\"t1\\",\\"description\\":\\"Test 1b\\"}",
59
+ "data": "{"id":"t1","description":"Test 1b"}",
60
60
  "object_id": "t1",
61
61
  "object_type": "test",
62
62
  "op": "PUT",
63
63
  "op_id": "3",
64
- "subkey": "6544e3899293153fa7b38331/117ab485-4b42-58a2-ab32-0053a22c3423",
64
+ "subkey": "e5aa2ddc-1328-58fa-a000-0b5ed31eaf1a",
65
65
  },
66
66
  {
67
67
  "checksum": 3028503153n,
68
- "data": "{\\"id\\":\\"t2\\",\\"description\\":\\"Test 2b\\"}",
68
+ "data": "{"id":"t2","description":"Test 2b"}",
69
69
  "object_id": "t2",
70
70
  "object_type": "test",
71
71
  "op": "PUT",
72
72
  "op_id": "4",
73
- "subkey": "6544e3899293153fa7b38331/ec27c691-b47a-5d92-927a-9944feb89eee",
73
+ "subkey": "13423353-9f27-59b4-baf0-64a5e09f1769",
74
74
  },
75
75
  ],
76
76
  "has_more": false,
@@ -146,21 +146,21 @@ exports[`sync - mongodb > sync global data 1`] = `
146
146
  "data": [
147
147
  {
148
148
  "checksum": 920318466n,
149
- "data": "{\\"id\\":\\"t1\\",\\"description\\":\\"Test 1\\"}",
149
+ "data": "{"id":"t1","description":"Test 1"}",
150
150
  "object_id": "t1",
151
151
  "object_type": "test",
152
152
  "op": "PUT",
153
153
  "op_id": "1",
154
- "subkey": "6544e3899293153fa7b38331/117ab485-4b42-58a2-ab32-0053a22c3423",
154
+ "subkey": "e5aa2ddc-1328-58fa-a000-0b5ed31eaf1a",
155
155
  },
156
156
  {
157
157
  "checksum": 3280762209n,
158
- "data": "{\\"id\\":\\"t2\\",\\"description\\":\\"Test 2\\"}",
158
+ "data": "{"id":"t2","description":"Test 2"}",
159
159
  "object_id": "t2",
160
160
  "object_type": "test",
161
161
  "op": "PUT",
162
162
  "op_id": "2",
163
- "subkey": "6544e3899293153fa7b38331/ec27c691-b47a-5d92-927a-9944feb89eee",
163
+ "subkey": "13423353-9f27-59b4-baf0-64a5e09f1769",
164
164
  },
165
165
  ],
166
166
  "has_more": false,
@@ -199,7 +199,7 @@ exports[`sync - mongodb > sync legacy non-raw data 1`] = `
199
199
  "checksum": 3442149460n,
200
200
  "data": {
201
201
  "description": "Test
202
- \\"string\\"",
202
+ "string"",
203
203
  "id": "t1",
204
204
  "large_num": 12345678901234567890n,
205
205
  },
@@ -207,7 +207,7 @@ exports[`sync - mongodb > sync legacy non-raw data 1`] = `
207
207
  "object_type": "test",
208
208
  "op": "PUT",
209
209
  "op_id": "1",
210
- "subkey": "6544e3899293153fa7b38331/117ab485-4b42-58a2-ab32-0053a22c3423",
210
+ "subkey": "e5aa2ddc-1328-58fa-a000-0b5ed31eaf1a",
211
211
  },
212
212
  ],
213
213
  "has_more": false,
@@ -268,12 +268,12 @@ exports[`sync - mongodb > sync updates to global data 2`] = `
268
268
  "data": [
269
269
  {
270
270
  "checksum": 920318466n,
271
- "data": "{\\"id\\":\\"t1\\",\\"description\\":\\"Test 1\\"}",
271
+ "data": "{"id":"t1","description":"Test 1"}",
272
272
  "object_id": "t1",
273
273
  "object_type": "test",
274
274
  "op": "PUT",
275
275
  "op_id": "1",
276
- "subkey": "6544e3899293153fa7b38331/117ab485-4b42-58a2-ab32-0053a22c3423",
276
+ "subkey": "e5aa2ddc-1328-58fa-a000-0b5ed31eaf1a",
277
277
  },
278
278
  ],
279
279
  "has_more": false,
@@ -311,12 +311,12 @@ exports[`sync - mongodb > sync updates to global data 3`] = `
311
311
  "data": [
312
312
  {
313
313
  "checksum": 3280762209n,
314
- "data": "{\\"id\\":\\"t2\\",\\"description\\":\\"Test 2\\"}",
314
+ "data": "{"id":"t2","description":"Test 2"}",
315
315
  "object_id": "t2",
316
316
  "object_type": "test",
317
317
  "op": "PUT",
318
318
  "op_id": "2",
319
- "subkey": "6544e3899293153fa7b38331/ec27c691-b47a-5d92-927a-9944feb89eee",
319
+ "subkey": "13423353-9f27-59b4-baf0-64a5e09f1769",
320
320
  },
321
321
  ],
322
322
  "has_more": false,
@@ -1,11 +1,11 @@
1
- import { describe, expect, test } from 'vitest';
2
- import { StaticKeyCollector } from '../../src/auth/StaticKeyCollector.js';
1
+ import { CachedKeyCollector } from '@/auth/CachedKeyCollector.js';
2
+ import { KeyResult } from '@/auth/KeyCollector.js';
3
+ import { KeySpec } from '@/auth/KeySpec.js';
4
+ import { KeyStore } from '@/auth/KeyStore.js';
5
+ import { RemoteJWKSCollector } from '@/auth/RemoteJWKSCollector.js';
6
+ import { StaticKeyCollector } from '@/auth/StaticKeyCollector.js';
3
7
  import * as jose from 'jose';
4
- import { KeyStore } from '../../src/auth/KeyStore.js';
5
- import { KeySpec } from '../../src/auth/KeySpec.js';
6
- import { RemoteJWKSCollector } from '../../src/auth/RemoteJWKSCollector.js';
7
- import { KeyResult } from '../../src/auth/KeyCollector.js';
8
- import { CachedKeyCollector } from '../../src/auth/CachedKeyCollector.js';
8
+ import { describe, expect, test } from 'vitest';
9
9
 
10
10
  const publicKey: jose.JWK = {
11
11
  use: 'sig',
@@ -1,3 +1,4 @@
1
+ import { BroadcastIterable, IterableSource } from '@/sync/BroadcastIterable.js';
1
2
  import { AsyncIterableX, interval } from 'ix/asynciterable/index.js';
2
3
  import { delayEach } from 'ix/asynciterable/operators/delayeach.js';
3
4
  import { take } from 'ix/asynciterable/operators/take.js';
@@ -5,7 +6,6 @@ import { wrapWithAbort } from 'ix/asynciterable/operators/withabort.js';
5
6
  import { toArray } from 'ix/asynciterable/toarray.js';
6
7
  import * as timers from 'timers/promises';
7
8
  import { describe, expect, test } from 'vitest';
8
- import { BroadcastIterable, IterableSource } from '../../src/sync/BroadcastIterable.js';
9
9
 
10
10
  describe('BroadcastIterable', () => {
11
11
  test('should iterate', async () => {
@@ -1,9 +1,9 @@
1
- import { SqlSyncRules } from '@powersync/service-sync-rules';
2
- import { describe, expect, test } from 'vitest';
3
- import { makeTestTable, MONGO_STORAGE_FACTORY } from './util.js';
4
- import { oneFromAsync } from './wal_stream_utils.js';
1
+ import { SaveOperationTag } from '@/storage/BucketStorage.js';
5
2
  import { MongoCompactOptions } from '@/storage/mongo/MongoCompactor.js';
6
- import { reduceBucket, validateCompactedBucket, validateBucket } from './bucket_validation.js';
3
+ import { describe, expect, test } from 'vitest';
4
+ import { validateCompactedBucket } from './bucket_validation.js';
5
+ import { oneFromAsync } from './stream_utils.js';
6
+ import { BATCH_OPTIONS, makeTestTable, MONGO_STORAGE_FACTORY, rid, testRules } from './util.js';
7
7
 
8
8
  const TEST_TABLE = makeTestTable('test', ['id']);
9
9
 
@@ -18,37 +18,40 @@ function compactTests(compactOptions: MongoCompactOptions) {
18
18
  const factory = MONGO_STORAGE_FACTORY;
19
19
 
20
20
  test('compacting (1)', async () => {
21
- const sync_rules = SqlSyncRules.fromYaml(`
21
+ const sync_rules = testRules(`
22
22
  bucket_definitions:
23
23
  global:
24
24
  data: [select * from test]
25
25
  `);
26
26
 
27
- const storage = (await factory()).getInstance({ id: 1, sync_rules, slot_name: 'test' });
27
+ const storage = (await factory()).getInstance(sync_rules);
28
28
 
29
- const result = await storage.startBatch({}, async (batch) => {
29
+ const result = await storage.startBatch(BATCH_OPTIONS, async (batch) => {
30
30
  await batch.save({
31
31
  sourceTable: TEST_TABLE,
32
- tag: 'insert',
32
+ tag: SaveOperationTag.INSERT,
33
33
  after: {
34
34
  id: 't1'
35
- }
35
+ },
36
+ afterReplicaId: rid('t1')
36
37
  });
37
38
 
38
39
  await batch.save({
39
40
  sourceTable: TEST_TABLE,
40
- tag: 'insert',
41
+ tag: SaveOperationTag.INSERT,
41
42
  after: {
42
43
  id: 't2'
43
- }
44
+ },
45
+ afterReplicaId: rid('t2')
44
46
  });
45
47
 
46
48
  await batch.save({
47
49
  sourceTable: TEST_TABLE,
48
- tag: 'update',
50
+ tag: SaveOperationTag.UPDATE,
49
51
  after: {
50
52
  id: 't2'
51
- }
53
+ },
54
+ afterReplicaId: rid('t2')
52
55
  });
53
56
  });
54
57
 
@@ -112,45 +115,49 @@ bucket_definitions:
112
115
  });
113
116
 
114
117
  test('compacting (2)', async () => {
115
- const sync_rules = SqlSyncRules.fromYaml(`
118
+ const sync_rules = testRules(`
116
119
  bucket_definitions:
117
120
  global:
118
121
  data: [select * from test]
119
122
  `);
120
123
 
121
- const storage = (await factory()).getInstance({ id: 1, sync_rules, slot_name: 'test' });
124
+ const storage = (await factory()).getInstance(sync_rules);
122
125
 
123
- const result = await storage.startBatch({}, async (batch) => {
126
+ const result = await storage.startBatch(BATCH_OPTIONS, async (batch) => {
124
127
  await batch.save({
125
128
  sourceTable: TEST_TABLE,
126
- tag: 'insert',
129
+ tag: SaveOperationTag.INSERT,
127
130
  after: {
128
131
  id: 't1'
129
- }
132
+ },
133
+ afterReplicaId: rid('t1')
130
134
  });
131
135
 
132
136
  await batch.save({
133
137
  sourceTable: TEST_TABLE,
134
- tag: 'insert',
138
+ tag: SaveOperationTag.INSERT,
135
139
  after: {
136
140
  id: 't2'
137
- }
141
+ },
142
+ afterReplicaId: rid('t2')
138
143
  });
139
144
 
140
145
  await batch.save({
141
146
  sourceTable: TEST_TABLE,
142
- tag: 'delete',
147
+ tag: SaveOperationTag.DELETE,
143
148
  before: {
144
149
  id: 't1'
145
- }
150
+ },
151
+ beforeReplicaId: rid('t1')
146
152
  });
147
153
 
148
154
  await batch.save({
149
155
  sourceTable: TEST_TABLE,
150
- tag: 'update',
156
+ tag: SaveOperationTag.UPDATE,
151
157
  after: {
152
158
  id: 't2'
153
- }
159
+ },
160
+ afterReplicaId: rid('t2')
154
161
  });
155
162
  });
156
163
 
@@ -213,51 +220,54 @@ bucket_definitions:
213
220
  });
214
221
 
215
222
  test('compacting (3)', async () => {
216
- const sync_rules = SqlSyncRules.fromYaml(`
223
+ const sync_rules = testRules(`
217
224
  bucket_definitions:
218
225
  global:
219
226
  data: [select * from test]
220
227
  `);
221
228
 
222
- const storage = (await factory()).getInstance({ id: 1, sync_rules, slot_name: 'test' });
229
+ const storage = (await factory()).getInstance(sync_rules);
223
230
 
224
- const result = await storage.startBatch({}, async (batch) => {
231
+ const result = await storage.startBatch(BATCH_OPTIONS, async (batch) => {
225
232
  await batch.save({
226
233
  sourceTable: TEST_TABLE,
227
- tag: 'insert',
234
+ tag: SaveOperationTag.INSERT,
228
235
  after: {
229
236
  id: 't1'
230
- }
237
+ },
238
+ afterReplicaId: 't1'
231
239
  });
232
240
 
233
241
  await batch.save({
234
242
  sourceTable: TEST_TABLE,
235
- tag: 'insert',
243
+ tag: SaveOperationTag.INSERT,
236
244
  after: {
237
245
  id: 't2'
238
- }
246
+ },
247
+ afterReplicaId: 't2'
239
248
  });
240
249
 
241
250
  await batch.save({
242
251
  sourceTable: TEST_TABLE,
243
- tag: 'delete',
252
+ tag: SaveOperationTag.DELETE,
244
253
  before: {
245
254
  id: 't1'
246
- }
255
+ },
256
+ beforeReplicaId: 't1'
247
257
  });
248
258
  });
249
259
 
250
260
  const checkpoint1 = result!.flushed_op;
251
261
  const checksumBefore = await storage.getChecksums(checkpoint1, ['global[]']);
252
- console.log('before', checksumBefore);
253
262
 
254
- const result2 = await storage.startBatch({}, async (batch) => {
263
+ const result2 = await storage.startBatch(BATCH_OPTIONS, async (batch) => {
255
264
  await batch.save({
256
265
  sourceTable: TEST_TABLE,
257
- tag: 'delete',
266
+ tag: SaveOperationTag.DELETE,
258
267
  before: {
259
268
  id: 't2'
260
- }
269
+ },
270
+ beforeReplicaId: 't2'
261
271
  });
262
272
  });
263
273
  const checkpoint2 = result2!.flushed_op;
@@ -271,7 +281,7 @@ bucket_definitions:
271
281
  expect(batchAfter.targetOp).toEqual(4n);
272
282
  expect(dataAfter).toMatchObject([
273
283
  {
274
- checksum: 857217610,
284
+ checksum: 1874612650,
275
285
  op: 'CLEAR',
276
286
  op_id: '4'
277
287
  }
@@ -279,7 +289,7 @@ bucket_definitions:
279
289
  expect(checksumAfter.get('global[]')).toEqual({
280
290
  bucket: 'global[]',
281
291
  count: 1,
282
- checksum: 857217610
292
+ checksum: 1874612650
283
293
  });
284
294
  });
285
295
  }