@powersync/service-core 0.8.7 → 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 (377) hide show
  1. package/CHANGELOG.md +37 -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 -7
  93. package/dist/routes/configure-fastify.js +20 -19
  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/probes.d.ts +74 -0
  104. package/dist/routes/endpoints/probes.js +51 -0
  105. package/dist/routes/endpoints/probes.js.map +1 -0
  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 +11 -4
  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 +16 -24
  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/auth-index.ts +0 -1
  240. package/src/db/mongo.ts +5 -3
  241. package/src/entry/cli-entry.ts +3 -2
  242. package/src/entry/commands/compact-action.ts +24 -12
  243. package/src/entry/commands/migrate-action.ts +5 -8
  244. package/src/entry/commands/teardown-action.ts +2 -2
  245. package/src/index.ts +5 -2
  246. package/src/metrics/Metrics.ts +6 -16
  247. package/src/migrations/db/migrations/1684951997326-init.ts +9 -4
  248. package/src/migrations/db/migrations/1702295701188-sync-rule-state.ts +7 -4
  249. package/src/migrations/db/migrations/1711543888062-write-checkpoint-index.ts +6 -4
  250. package/src/migrations/db/migrations/1727099539247-custom-write-checkpoint-index.ts +37 -0
  251. package/src/migrations/migrations.ts +24 -8
  252. package/src/modules/AbstractModule.ts +37 -0
  253. package/src/modules/ModuleManager.ts +34 -0
  254. package/src/modules/modules-index.ts +2 -0
  255. package/src/replication/AbstractReplicationJob.ts +79 -0
  256. package/src/replication/AbstractReplicator.ts +228 -0
  257. package/src/replication/ErrorRateLimiter.ts +0 -44
  258. package/src/replication/ReplicationEngine.ts +43 -0
  259. package/src/replication/ReplicationModule.ts +122 -0
  260. package/src/replication/replication-index.ts +4 -6
  261. package/src/routes/RouterEngine.ts +120 -0
  262. package/src/routes/auth.ts +21 -12
  263. package/src/routes/configure-fastify.ts +28 -28
  264. package/src/routes/configure-rsocket.ts +13 -8
  265. package/src/routes/endpoints/admin.ts +72 -76
  266. package/src/routes/endpoints/checkpointing.ts +51 -11
  267. package/src/routes/endpoints/probes.ts +58 -0
  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 +10 -5
  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 +31 -31
  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 +235 -0
  314. package/test/src/routes/probes.test.ts +153 -0
  315. package/test/src/setup.ts +1 -1
  316. package/test/src/stream_utils.ts +42 -0
  317. package/test/src/sync.test.ts +115 -39
  318. package/test/src/util.ts +48 -51
  319. package/test/tsconfig.json +1 -1
  320. package/tsconfig.tsbuildinfo +1 -1
  321. package/vitest.config.ts +7 -1
  322. package/dist/auth/SupabaseKeyCollector.d.ts +0 -22
  323. package/dist/auth/SupabaseKeyCollector.js +0 -61
  324. package/dist/auth/SupabaseKeyCollector.js.map +0 -1
  325. package/dist/replication/PgRelation.d.ts +0 -16
  326. package/dist/replication/PgRelation.js +0 -26
  327. package/dist/replication/PgRelation.js.map +0 -1
  328. package/dist/replication/WalConnection.d.ts +0 -34
  329. package/dist/replication/WalConnection.js +0 -190
  330. package/dist/replication/WalConnection.js.map +0 -1
  331. package/dist/replication/WalStream.d.ts +0 -57
  332. package/dist/replication/WalStream.js +0 -519
  333. package/dist/replication/WalStream.js.map +0 -1
  334. package/dist/replication/WalStreamManager.d.ts +0 -30
  335. package/dist/replication/WalStreamManager.js +0 -198
  336. package/dist/replication/WalStreamManager.js.map +0 -1
  337. package/dist/replication/WalStreamRunner.d.ts +0 -38
  338. package/dist/replication/WalStreamRunner.js +0 -155
  339. package/dist/replication/WalStreamRunner.js.map +0 -1
  340. package/dist/replication/util.d.ts +0 -9
  341. package/dist/replication/util.js +0 -62
  342. package/dist/replication/util.js.map +0 -1
  343. package/dist/system/CorePowerSyncSystem.d.ts +0 -23
  344. package/dist/system/CorePowerSyncSystem.js +0 -52
  345. package/dist/system/CorePowerSyncSystem.js.map +0 -1
  346. package/dist/util/PgManager.d.ts +0 -24
  347. package/dist/util/PgManager.js +0 -55
  348. package/dist/util/PgManager.js.map +0 -1
  349. package/dist/util/migration_lib.d.ts +0 -11
  350. package/dist/util/migration_lib.js +0 -64
  351. package/dist/util/migration_lib.js.map +0 -1
  352. package/dist/util/pgwire_utils.d.ts +0 -24
  353. package/dist/util/pgwire_utils.js +0 -117
  354. package/dist/util/pgwire_utils.js.map +0 -1
  355. package/dist/util/populate_test_data.d.ts +0 -8
  356. package/dist/util/populate_test_data.js +0 -65
  357. package/dist/util/populate_test_data.js.map +0 -1
  358. package/src/auth/SupabaseKeyCollector.ts +0 -67
  359. package/src/replication/PgRelation.ts +0 -42
  360. package/src/replication/WalConnection.ts +0 -227
  361. package/src/replication/WalStream.ts +0 -631
  362. package/src/replication/WalStreamManager.ts +0 -213
  363. package/src/replication/WalStreamRunner.ts +0 -180
  364. package/src/replication/util.ts +0 -76
  365. package/src/system/CorePowerSyncSystem.ts +0 -64
  366. package/src/util/PgManager.ts +0 -64
  367. package/src/util/migration_lib.ts +0 -79
  368. package/src/util/pgwire_utils.ts +0 -139
  369. package/src/util/populate_test_data.ts +0 -78
  370. package/test/src/__snapshots__/pg_test.test.ts.snap +0 -256
  371. package/test/src/large_batch.test.ts +0 -194
  372. package/test/src/pg_test.test.ts +0 -450
  373. package/test/src/schema_changes.test.ts +0 -545
  374. package/test/src/slow_tests.test.ts +0 -338
  375. package/test/src/validation.test.ts +0 -63
  376. package/test/src/wal_stream.test.ts +0 -319
  377. package/test/src/wal_stream_utils.ts +0 -156
@@ -1,36 +1,39 @@
1
- import * as mongo from 'mongodb';
2
- import * as timers from 'timers/promises';
3
- import { LRUCache } from 'lru-cache/min';
4
1
  import { SqlSyncRules } from '@powersync/service-sync-rules';
5
2
  import { wrapWithAbort } from 'ix/asynciterable/operators/withabort.js';
3
+ import { LRUCache } from 'lru-cache/min';
4
+ import * as mongo from 'mongodb';
5
+ import * as timers from 'timers/promises';
6
6
 
7
- import * as replication from '../replication/replication-index.js';
7
+ import * as locks from '../locks/locks-index.js';
8
8
  import * as sync from '../sync/sync-index.js';
9
9
  import * as util from '../util/util-index.js';
10
- import * as locks from '../locks/locks-index.js';
11
10
 
11
+ import { DisposableObserver, logger } from '@powersync/lib-services-framework';
12
+ import { v4 as uuid } from 'uuid';
12
13
  import {
13
14
  ActiveCheckpoint,
14
15
  BucketStorageFactory,
16
+ BucketStorageFactoryListener,
17
+ ParseSyncRulesOptions,
15
18
  PersistedSyncRules,
16
19
  PersistedSyncRulesContent,
17
20
  StorageMetrics,
18
21
  UpdateSyncRulesOptions,
19
22
  WriteCheckpoint
20
23
  } from './BucketStorage.js';
24
+ import { PowerSyncMongo } from './mongo/db.js';
25
+ import { SyncRuleDocument, SyncRuleState } from './mongo/models.js';
21
26
  import { MongoPersistedSyncRulesContent } from './mongo/MongoPersistedSyncRulesContent.js';
22
27
  import { MongoSyncBucketStorage } from './mongo/MongoSyncBucketStorage.js';
23
- import { PowerSyncMongo, PowerSyncMongoOptions } from './mongo/db.js';
24
- import { SyncRuleDocument, SyncRuleState } from './mongo/models.js';
25
28
  import { generateSlotName } from './mongo/util.js';
26
- import { v4 as uuid } from 'uuid';
27
- import { logger } from '@powersync/lib-services-framework';
28
-
29
- export interface MongoBucketStorageOptions extends PowerSyncMongoOptions {}
30
29
 
31
- export class MongoBucketStorage implements BucketStorageFactory {
30
+ export class MongoBucketStorage
31
+ extends DisposableObserver<BucketStorageFactoryListener>
32
+ implements BucketStorageFactory
33
+ {
32
34
  private readonly client: mongo.MongoClient;
33
35
  private readonly session: mongo.ClientSession;
36
+ // TODO: This is still Postgres specific and needs to be reworked
34
37
  public readonly slot_name_prefix: string;
35
38
 
36
39
  private readonly storageCache = new LRUCache<number, MongoSyncBucketStorage>({
@@ -47,26 +50,44 @@ export class MongoBucketStorage implements BucketStorageFactory {
47
50
  return undefined;
48
51
  }
49
52
  const rules = new MongoPersistedSyncRulesContent(this.db, doc2);
50
- const storage = this.getInstance(rules.parsed());
51
- return storage;
53
+ return this.getInstance(rules);
54
+ },
55
+ dispose: (storage) => {
56
+ storage[Symbol.dispose]();
52
57
  }
53
58
  });
54
59
 
55
60
  public readonly db: PowerSyncMongo;
56
61
 
57
- constructor(db: PowerSyncMongo, options: { slot_name_prefix: string }) {
62
+ constructor(
63
+ db: PowerSyncMongo,
64
+ options: {
65
+ slot_name_prefix: string;
66
+ }
67
+ ) {
68
+ super();
58
69
  this.client = db.client;
59
70
  this.db = db;
60
71
  this.session = this.client.startSession();
61
72
  this.slot_name_prefix = options.slot_name_prefix;
62
73
  }
63
74
 
64
- getInstance(options: PersistedSyncRules): MongoSyncBucketStorage {
65
- let { id, sync_rules, slot_name } = options;
75
+ getInstance(options: PersistedSyncRulesContent): MongoSyncBucketStorage {
76
+ let { id, slot_name } = options;
66
77
  if ((typeof id as any) == 'bigint') {
67
78
  id = Number(id);
68
79
  }
69
- return new MongoSyncBucketStorage(this, id, sync_rules, slot_name);
80
+ const storage = new MongoSyncBucketStorage(this, id, options, slot_name);
81
+ this.iterateListeners((cb) => cb.syncStorageCreated?.(storage));
82
+ storage.registerListener({
83
+ batchStarted: (batch) => {
84
+ // This nested listener will be automatically disposed when the storage is disposed
85
+ batch.registerManagedListener(storage, {
86
+ replicationEvent: (payload) => this.iterateListeners((cb) => cb.replicationEvent?.(payload))
87
+ });
88
+ }
89
+ });
90
+ return storage;
70
91
  }
71
92
 
72
93
  async configureSyncRules(sync_rules: string, options?: { lock?: boolean }) {
@@ -136,7 +157,12 @@ export class MongoBucketStorage implements BucketStorageFactory {
136
157
 
137
158
  async updateSyncRules(options: UpdateSyncRulesOptions): Promise<MongoPersistedSyncRulesContent> {
138
159
  // Parse and validate before applying any changes
139
- const parsed = SqlSyncRules.fromYaml(options.content);
160
+ const parsed = SqlSyncRules.fromYaml(options.content, {
161
+ // No schema-based validation at this point
162
+ schema: undefined,
163
+ defaultSchema: 'not_applicable', // Not needed for validation
164
+ throwOnError: true
165
+ });
140
166
 
141
167
  let rules: MongoPersistedSyncRulesContent | undefined = undefined;
142
168
 
@@ -204,9 +230,9 @@ export class MongoBucketStorage implements BucketStorageFactory {
204
230
  return new MongoPersistedSyncRulesContent(this.db, doc);
205
231
  }
206
232
 
207
- async getActiveSyncRules(): Promise<PersistedSyncRules | null> {
233
+ async getActiveSyncRules(options: ParseSyncRulesOptions): Promise<PersistedSyncRules | null> {
208
234
  const content = await this.getActiveSyncRulesContent();
209
- return content?.parsed() ?? null;
235
+ return content?.parsed(options) ?? null;
210
236
  }
211
237
 
212
238
  async getNextSyncRulesContent(): Promise<MongoPersistedSyncRulesContent | null> {
@@ -223,9 +249,9 @@ export class MongoBucketStorage implements BucketStorageFactory {
223
249
  return new MongoPersistedSyncRulesContent(this.db, doc);
224
250
  }
225
251
 
226
- async getNextSyncRules(): Promise<PersistedSyncRules | null> {
252
+ async getNextSyncRules(options: ParseSyncRulesOptions): Promise<PersistedSyncRules | null> {
227
253
  const content = await this.getNextSyncRulesContent();
228
- return content?.parsed() ?? null;
254
+ return content?.parsed(options) ?? null;
229
255
  }
230
256
 
231
257
  async getReplicatingSyncRules(): Promise<PersistedSyncRulesContent[]> {
@@ -252,32 +278,6 @@ export class MongoBucketStorage implements BucketStorageFactory {
252
278
  });
253
279
  }
254
280
 
255
- async createWriteCheckpoint(user_id: string, lsns: Record<string, string>): Promise<bigint> {
256
- const doc = await this.db.write_checkpoints.findOneAndUpdate(
257
- {
258
- user_id: user_id
259
- },
260
- {
261
- $set: {
262
- lsns: lsns
263
- },
264
- $inc: {
265
- client_id: 1n
266
- }
267
- },
268
- { upsert: true, returnDocument: 'after' }
269
- );
270
- return doc!.client_id;
271
- }
272
-
273
- async lastWriteCheckpoint(user_id: string, lsn: string): Promise<bigint | null> {
274
- const lastWriteCheckpoint = await this.db.write_checkpoints.findOne({
275
- user_id: user_id,
276
- 'lsns.1': { $lte: lsn }
277
- });
278
- return lastWriteCheckpoint?.client_id ?? null;
279
- }
280
-
281
281
  async getActiveCheckpoint(): Promise<ActiveCheckpoint> {
282
282
  const doc = await this.db.sync_rules.findOne(
283
283
  {
@@ -303,7 +303,7 @@ export class MongoBucketStorage implements BucketStorageFactory {
303
303
  }
304
304
  };
305
305
 
306
- const active_sync_rules = await this.getActiveSyncRules();
306
+ const active_sync_rules = await this.getActiveSyncRules({ defaultSchema: 'public' });
307
307
  if (active_sync_rules == null) {
308
308
  return {
309
309
  operations_size_bytes: 0,
@@ -379,7 +379,7 @@ export class MongoBucketStorage implements BucketStorageFactory {
379
379
  private makeActiveCheckpoint(doc: SyncRuleDocument | null) {
380
380
  return {
381
381
  checkpoint: util.timestampToOpId(doc?.last_checkpoint ?? 0n),
382
- lsn: doc?.last_checkpoint_lsn ?? replication.ZERO_LSN,
382
+ lsn: doc?.last_checkpoint_lsn ?? null,
383
383
  hasSyncRules() {
384
384
  return doc != null;
385
385
  },
@@ -389,7 +389,7 @@ export class MongoBucketStorage implements BucketStorageFactory {
389
389
  }
390
390
  return (await this.storageCache.fetch(doc._id)) ?? null;
391
391
  }
392
- };
392
+ } satisfies ActiveCheckpoint;
393
393
  }
394
394
 
395
395
  /**
@@ -479,6 +479,7 @@ export class MongoBucketStorage implements BucketStorageFactory {
479
479
  if (doc == null) {
480
480
  continue;
481
481
  }
482
+
482
483
  const op = this.makeActiveCheckpoint(doc);
483
484
  // Check for LSN / checkpoint changes - ignore other metadata changes
484
485
  if (lastOp == null || op.lsn != lastOp.lsn || op.checkpoint != lastOp.checkpoint) {
@@ -508,8 +509,19 @@ export class MongoBucketStorage implements BucketStorageFactory {
508
509
  // What is important is:
509
510
  // 1. checkpoint (op_id) changes.
510
511
  // 2. write checkpoint changes for the specific user
512
+ const bucketStorage = await cp.getBucketStorage();
513
+ if (!bucketStorage) {
514
+ continue;
515
+ }
516
+
517
+ const lsnFilters: Record<string, string> = lsn ? { 1: lsn } : {};
511
518
 
512
- const currentWriteCheckpoint = await this.lastWriteCheckpoint(user_id, lsn ?? '');
519
+ const currentWriteCheckpoint = await bucketStorage.lastWriteCheckpoint({
520
+ user_id,
521
+ heads: {
522
+ ...lsnFilters
523
+ }
524
+ });
513
525
 
514
526
  if (currentWriteCheckpoint == lastWriteCheckpoint && checkpoint == lastCheckpoint) {
515
527
  // No change - wait for next one
@@ -0,0 +1,16 @@
1
+ import * as sync_rules from '@powersync/service-sync-rules';
2
+ import { BucketStorageBatch, SaveOp } from './BucketStorage.js';
3
+ import { SourceTable } from './SourceTable.js';
4
+
5
+ export type EventData = {
6
+ op: SaveOp;
7
+ before?: sync_rules.SqliteRow;
8
+ after?: sync_rules.SqliteRow;
9
+ };
10
+
11
+ export type ReplicationEventPayload = {
12
+ batch: BucketStorageBatch;
13
+ data: EventData;
14
+ event: sync_rules.SqlEventDescriptor;
15
+ table: SourceTable;
16
+ };
@@ -0,0 +1,22 @@
1
+ export interface ColumnDescriptor {
2
+ name: string;
3
+ /**
4
+ * The type of the column ie VARCHAR, INT, etc
5
+ */
6
+ type?: string;
7
+ /**
8
+ * Some data sources have a type id that can be used to identify the type of the column
9
+ */
10
+ typeId?: number;
11
+ }
12
+
13
+ // TODO: This needs to be consolidated with SourceTable into something new.
14
+ export interface SourceEntityDescriptor {
15
+ /**
16
+ * The internal id of the data source structure in the database
17
+ */
18
+ objectId: number | string;
19
+ schema: string;
20
+ name: string;
21
+ replicationColumns: ColumnDescriptor[];
22
+ }
@@ -1,10 +1,8 @@
1
- import { DEFAULT_SCHEMA, DEFAULT_TAG } from '@powersync/service-sync-rules';
2
-
3
- import * as replication from '../replication/replication-index.js';
1
+ import { DEFAULT_TAG } from '@powersync/service-sync-rules';
4
2
  import * as util from '../util/util-index.js';
3
+ import { ColumnDescriptor } from './SourceEntity.js';
5
4
 
6
5
  export class SourceTable {
7
- static readonly DEFAULT_SCHEMA = DEFAULT_SCHEMA;
8
6
  static readonly DEFAULT_TAG = DEFAULT_TAG;
9
7
 
10
8
  /**
@@ -25,14 +23,23 @@ export class SourceTable {
25
23
  */
26
24
  public syncParameters = true;
27
25
 
26
+ /**
27
+ * True if the table is used in sync rules for events.
28
+ *
29
+ * This value is resolved externally, and cached here.
30
+ *
31
+ * Defaults to true for tests.
32
+ */
33
+ public syncEvent = true;
34
+
28
35
  constructor(
29
36
  public readonly id: any,
30
37
  public readonly connectionTag: string,
31
- public readonly relationId: number,
38
+ public readonly objectId: number | string,
32
39
  public readonly schema: string,
33
40
  public readonly table: string,
34
41
 
35
- public readonly replicaIdColumns: replication.ReplicationColumn[],
42
+ public readonly replicaIdColumns: ColumnDescriptor[],
36
43
  public readonly snapshotComplete: boolean
37
44
  ) {}
38
45
 
@@ -55,6 +62,6 @@ export class SourceTable {
55
62
  }
56
63
 
57
64
  get syncAny() {
58
- return this.syncData || this.syncParameters;
65
+ return this.syncData || this.syncParameters || this.syncEvent;
59
66
  }
60
67
  }
@@ -0,0 +1,62 @@
1
+ import { DisposableListener, DisposableObserver, logger } from '@powersync/lib-services-framework';
2
+ import { ResolvedPowerSyncConfig } from '../util/util-index.js';
3
+ import { BucketStorageFactory } from './BucketStorage.js';
4
+ import { ActiveStorage, BucketStorageProvider } from './StorageProvider.js';
5
+
6
+ export type StorageEngineOptions = {
7
+ configuration: ResolvedPowerSyncConfig;
8
+ };
9
+
10
+ export interface StorageEngineListener extends DisposableListener {
11
+ storageActivated: (storage: BucketStorageFactory) => void;
12
+ }
13
+
14
+ export class StorageEngine extends DisposableObserver<StorageEngineListener> {
15
+ // TODO: This will need to revisited when we actually support multiple storage providers.
16
+ private storageProviders: Map<string, BucketStorageProvider> = new Map();
17
+ private currentActiveStorage: ActiveStorage | null = null;
18
+
19
+ constructor(private options: StorageEngineOptions) {
20
+ super();
21
+ }
22
+
23
+ get activeBucketStorage(): BucketStorageFactory {
24
+ return this.activeStorage.storage;
25
+ }
26
+
27
+ get activeStorage(): ActiveStorage {
28
+ if (!this.currentActiveStorage) {
29
+ throw new Error(`No storage provider has been initialized yet.`);
30
+ }
31
+
32
+ return this.currentActiveStorage;
33
+ }
34
+
35
+ /**
36
+ * Register a provider which generates a {@link BucketStorageFactory}
37
+ * given the matching config specified in the loaded {@link ResolvedPowerSyncConfig}
38
+ */
39
+ registerProvider(provider: BucketStorageProvider) {
40
+ this.storageProviders.set(provider.type, provider);
41
+ }
42
+
43
+ public async start(): Promise<void> {
44
+ logger.info('Starting Storage Engine...');
45
+ const { configuration } = this.options;
46
+ this.currentActiveStorage = await this.storageProviders.get(configuration.storage.type)!.getStorage({
47
+ resolvedConfig: configuration
48
+ });
49
+ this.iterateListeners((cb) => cb.storageActivated?.(this.activeBucketStorage));
50
+ logger.info(`Successfully activated storage: ${configuration.storage.type}.`);
51
+ logger.info('Successfully started Storage Engine.');
52
+ }
53
+
54
+ /**
55
+ * Shutdown the storage engine, safely shutting down any activated storage providers.
56
+ */
57
+ public async shutDown(): Promise<void> {
58
+ logger.info('Shutting down Storage Engine...');
59
+ await this.currentActiveStorage?.shutDown();
60
+ logger.info('Successfully shut down Storage Engine.');
61
+ }
62
+ }
@@ -0,0 +1,27 @@
1
+ import * as util from '../util/util-index.js';
2
+ import { BucketStorageFactory } from './BucketStorage.js';
3
+
4
+ export interface ActiveStorage {
5
+ storage: BucketStorageFactory;
6
+ shutDown(): Promise<void>;
7
+
8
+ /**
9
+ * Tear down / drop the storage permanently
10
+ */
11
+ tearDown(): Promise<boolean>;
12
+ }
13
+
14
+ export interface GetStorageOptions {
15
+ // TODO: This should just be the storage config. Update once the slot name prefix coupling has been removed from the storage
16
+ resolvedConfig: util.ResolvedPowerSyncConfig;
17
+ }
18
+
19
+ export interface BucketStorageProvider {
20
+ /**
21
+ * The storage type that this provider provides.
22
+ * The type should match the `type` field in the config.
23
+ */
24
+ type: string;
25
+
26
+ getStorage(options: GetStorageOptions): Promise<ActiveStorage>;
27
+ }
@@ -0,0 +1,85 @@
1
+ export enum WriteCheckpointMode {
2
+ /**
3
+ * Raw mappings of `user_id` to `write_checkpoint`s should
4
+ * be supplied for each set of sync rules.
5
+ */
6
+ CUSTOM = 'custom',
7
+ /**
8
+ * Write checkpoints are stored as a mapping of `user_id` plus
9
+ * replication HEAD (lsn in Postgres) to an automatically generated
10
+ * incrementing `write_checkpoint` (stored as`client_id`).
11
+ */
12
+ MANAGED = 'managed'
13
+ }
14
+
15
+ export interface BaseWriteCheckpointIdentifier {
16
+ /**
17
+ * Identifier for User's account.
18
+ */
19
+ user_id: string;
20
+ }
21
+
22
+ export interface CustomWriteCheckpointFilters extends BaseWriteCheckpointIdentifier {
23
+ /**
24
+ * Sync rules which were active when this checkpoint was created.
25
+ */
26
+ sync_rules_id: number;
27
+ }
28
+
29
+ export interface BatchedCustomWriteCheckpointOptions extends BaseWriteCheckpointIdentifier {
30
+ /**
31
+ * A supplied incrementing Write Checkpoint number
32
+ */
33
+ checkpoint: bigint;
34
+ }
35
+
36
+ export interface CustomWriteCheckpointOptions extends BatchedCustomWriteCheckpointOptions {
37
+ /**
38
+ * Sync rules which were active when this checkpoint was created.
39
+ */
40
+ sync_rules_id: number;
41
+ }
42
+
43
+ /**
44
+ * Managed Write Checkpoints are a mapping of User ID to replication HEAD
45
+ */
46
+ export interface ManagedWriteCheckpointFilters extends BaseWriteCheckpointIdentifier {
47
+ /**
48
+ * Replication HEAD(s) at the creation of the checkpoint.
49
+ */
50
+ heads: Record<string, string>;
51
+ }
52
+
53
+ export type ManagedWriteCheckpointOptions = ManagedWriteCheckpointFilters;
54
+
55
+ export type SyncStorageLastWriteCheckpointFilters = BaseWriteCheckpointIdentifier | ManagedWriteCheckpointFilters;
56
+ export type LastWriteCheckpointFilters = CustomWriteCheckpointFilters | ManagedWriteCheckpointFilters;
57
+
58
+ export interface BaseWriteCheckpointAPI {
59
+ readonly writeCheckpointMode: WriteCheckpointMode;
60
+ setWriteCheckpointMode(mode: WriteCheckpointMode): void;
61
+ createManagedWriteCheckpoint(checkpoint: ManagedWriteCheckpointOptions): Promise<bigint>;
62
+ }
63
+
64
+ /**
65
+ * Write Checkpoint API to be used in conjunction with a {@link SyncRulesBucketStorage}.
66
+ * This storage corresponds with a set of sync rules. These APIs don't require specifying a
67
+ * sync rules id.
68
+ */
69
+ export interface SyncStorageWriteCheckpointAPI extends BaseWriteCheckpointAPI {
70
+ batchCreateCustomWriteCheckpoints(checkpoints: BatchedCustomWriteCheckpointOptions[]): Promise<void>;
71
+ createCustomWriteCheckpoint(checkpoint: BatchedCustomWriteCheckpointOptions): Promise<bigint>;
72
+ lastWriteCheckpoint(filters: SyncStorageLastWriteCheckpointFilters): Promise<bigint | null>;
73
+ }
74
+
75
+ /**
76
+ * Write Checkpoint API which is interfaced directly with the storage layer. This requires
77
+ * sync rules identifiers for custom write checkpoints.
78
+ */
79
+ export interface WriteCheckpointAPI extends BaseWriteCheckpointAPI {
80
+ batchCreateCustomWriteCheckpoints(checkpoints: CustomWriteCheckpointOptions[]): Promise<void>;
81
+ createCustomWriteCheckpoint(checkpoint: CustomWriteCheckpointOptions): Promise<bigint>;
82
+ lastWriteCheckpoint(filters: LastWriteCheckpointFilters): Promise<bigint | null>;
83
+ }
84
+
85
+ export const DEFAULT_WRITE_CHECKPOINT_MODE = WriteCheckpointMode.MANAGED;