@powersync/service-core 0.8.8 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (376) hide show
  1. package/CHANGELOG.md +43 -0
  2. package/dist/api/RouteAPI.d.ts +67 -0
  3. package/dist/api/RouteAPI.js +2 -0
  4. package/dist/api/RouteAPI.js.map +1 -0
  5. package/dist/api/api-index.d.ts +1 -0
  6. package/dist/api/api-index.js +1 -0
  7. package/dist/api/api-index.js.map +1 -1
  8. package/dist/api/diagnostics.d.ts +4 -4
  9. package/dist/api/diagnostics.js +170 -158
  10. package/dist/api/diagnostics.js.map +1 -1
  11. package/dist/api/schema.d.ts +3 -5
  12. package/dist/api/schema.js +14 -80
  13. package/dist/api/schema.js.map +1 -1
  14. package/dist/auth/CachedKeyCollector.js.map +1 -1
  15. package/dist/auth/KeySpec.js.map +1 -1
  16. package/dist/auth/KeyStore.d.ts +7 -4
  17. package/dist/auth/KeyStore.js +1 -1
  18. package/dist/auth/KeyStore.js.map +1 -1
  19. package/dist/auth/LeakyBucket.js.map +1 -1
  20. package/dist/auth/RemoteJWKSCollector.d.ts +0 -2
  21. package/dist/auth/RemoteJWKSCollector.js.map +1 -1
  22. package/dist/auth/StaticSupabaseKeyCollector.d.ts +19 -0
  23. package/dist/auth/StaticSupabaseKeyCollector.js +28 -0
  24. package/dist/auth/StaticSupabaseKeyCollector.js.map +1 -0
  25. package/dist/auth/auth-index.d.ts +1 -1
  26. package/dist/auth/auth-index.js +1 -1
  27. package/dist/auth/auth-index.js.map +1 -1
  28. package/dist/db/mongo.js +5 -3
  29. package/dist/db/mongo.js.map +1 -1
  30. package/dist/entry/cli-entry.js +3 -2
  31. package/dist/entry/cli-entry.js.map +1 -1
  32. package/dist/entry/commands/compact-action.js +90 -14
  33. package/dist/entry/commands/compact-action.js.map +1 -1
  34. package/dist/entry/commands/migrate-action.js +4 -5
  35. package/dist/entry/commands/migrate-action.js.map +1 -1
  36. package/dist/entry/commands/teardown-action.js +2 -2
  37. package/dist/entry/commands/teardown-action.js.map +1 -1
  38. package/dist/index.d.ts +4 -2
  39. package/dist/index.js +4 -2
  40. package/dist/index.js.map +1 -1
  41. package/dist/locks/MongoLocks.js.map +1 -1
  42. package/dist/metrics/Metrics.d.ts +2 -2
  43. package/dist/metrics/Metrics.js +5 -13
  44. package/dist/metrics/Metrics.js.map +1 -1
  45. package/dist/migrations/db/migrations/1684951997326-init.d.ts +2 -2
  46. package/dist/migrations/db/migrations/1684951997326-init.js +4 -2
  47. package/dist/migrations/db/migrations/1684951997326-init.js.map +1 -1
  48. package/dist/migrations/db/migrations/1702295701188-sync-rule-state.d.ts +2 -2
  49. package/dist/migrations/db/migrations/1702295701188-sync-rule-state.js +4 -2
  50. package/dist/migrations/db/migrations/1702295701188-sync-rule-state.js.map +1 -1
  51. package/dist/migrations/db/migrations/1711543888062-write-checkpoint-index.d.ts +2 -2
  52. package/dist/migrations/db/migrations/1711543888062-write-checkpoint-index.js +4 -2
  53. package/dist/migrations/db/migrations/1711543888062-write-checkpoint-index.js.map +1 -1
  54. package/dist/migrations/db/migrations/1727099539247-custom-write-checkpoint-index.d.ts +3 -0
  55. package/dist/migrations/db/migrations/1727099539247-custom-write-checkpoint-index.js +31 -0
  56. package/dist/migrations/db/migrations/1727099539247-custom-write-checkpoint-index.js.map +1 -0
  57. package/dist/migrations/executor.js.map +1 -1
  58. package/dist/migrations/migrations.d.ts +8 -0
  59. package/dist/migrations/migrations.js +19 -7
  60. package/dist/migrations/migrations.js.map +1 -1
  61. package/dist/migrations/store/migration-store.js.map +1 -1
  62. package/dist/modules/AbstractModule.d.ts +26 -0
  63. package/dist/modules/AbstractModule.js +11 -0
  64. package/dist/modules/AbstractModule.js.map +1 -0
  65. package/dist/modules/ModuleManager.d.ts +11 -0
  66. package/dist/modules/ModuleManager.js +32 -0
  67. package/dist/modules/ModuleManager.js.map +1 -0
  68. package/dist/modules/modules-index.d.ts +2 -0
  69. package/dist/modules/modules-index.js +3 -0
  70. package/dist/modules/modules-index.js.map +1 -0
  71. package/dist/replication/AbstractReplicationJob.d.ts +37 -0
  72. package/dist/replication/AbstractReplicationJob.js +51 -0
  73. package/dist/replication/AbstractReplicationJob.js.map +1 -0
  74. package/dist/replication/AbstractReplicator.d.ts +53 -0
  75. package/dist/replication/AbstractReplicator.js +250 -0
  76. package/dist/replication/AbstractReplicator.js.map +1 -0
  77. package/dist/replication/ErrorRateLimiter.d.ts +0 -10
  78. package/dist/replication/ErrorRateLimiter.js +1 -42
  79. package/dist/replication/ErrorRateLimiter.js.map +1 -1
  80. package/dist/replication/ReplicationEngine.d.ts +18 -0
  81. package/dist/replication/ReplicationEngine.js +41 -0
  82. package/dist/replication/ReplicationEngine.js.map +1 -0
  83. package/dist/replication/ReplicationModule.d.ts +51 -0
  84. package/dist/replication/ReplicationModule.js +68 -0
  85. package/dist/replication/ReplicationModule.js.map +1 -0
  86. package/dist/replication/replication-index.d.ts +4 -6
  87. package/dist/replication/replication-index.js +4 -6
  88. package/dist/replication/replication-index.js.map +1 -1
  89. package/dist/routes/RouterEngine.d.ts +42 -0
  90. package/dist/routes/RouterEngine.js +80 -0
  91. package/dist/routes/RouterEngine.js.map +1 -0
  92. package/dist/routes/auth.d.ts +2 -2
  93. package/dist/routes/auth.js +11 -11
  94. package/dist/routes/auth.js.map +1 -1
  95. package/dist/routes/configure-fastify.d.ts +37 -23
  96. package/dist/routes/configure-fastify.js +18 -18
  97. package/dist/routes/configure-fastify.js.map +1 -1
  98. package/dist/routes/configure-rsocket.d.ts +3 -4
  99. package/dist/routes/configure-rsocket.js +7 -4
  100. package/dist/routes/configure-rsocket.js.map +1 -1
  101. package/dist/routes/endpoints/admin.d.ts +30 -0
  102. package/dist/routes/endpoints/admin.js +46 -67
  103. package/dist/routes/endpoints/admin.js.map +1 -1
  104. package/dist/routes/endpoints/checkpointing.js +103 -15
  105. package/dist/routes/endpoints/checkpointing.js.map +1 -1
  106. package/dist/routes/endpoints/socket-route.js +8 -6
  107. package/dist/routes/endpoints/socket-route.js.map +1 -1
  108. package/dist/routes/endpoints/sync-rules.d.ts +1 -1
  109. package/dist/routes/endpoints/sync-rules.js +32 -23
  110. package/dist/routes/endpoints/sync-rules.js.map +1 -1
  111. package/dist/routes/endpoints/sync-stream.d.ts +0 -1
  112. package/dist/routes/endpoints/sync-stream.js +8 -8
  113. package/dist/routes/endpoints/sync-stream.js.map +1 -1
  114. package/dist/routes/hooks.js.map +1 -1
  115. package/dist/routes/route-register.js.map +1 -1
  116. package/dist/routes/router.d.ts +9 -2
  117. package/dist/routes/router.js.map +1 -1
  118. package/dist/routes/routes-index.d.ts +1 -0
  119. package/dist/routes/routes-index.js +1 -0
  120. package/dist/routes/routes-index.js.map +1 -1
  121. package/dist/runner/teardown.js +109 -76
  122. package/dist/runner/teardown.js.map +1 -1
  123. package/dist/storage/BucketStorage.d.ts +86 -36
  124. package/dist/storage/BucketStorage.js +6 -10
  125. package/dist/storage/BucketStorage.js.map +1 -1
  126. package/dist/storage/ChecksumCache.js.map +1 -1
  127. package/dist/storage/MongoBucketStorage.d.ts +7 -11
  128. package/dist/storage/MongoBucketStorage.js +48 -41
  129. package/dist/storage/MongoBucketStorage.js.map +1 -1
  130. package/dist/storage/ReplicationEventPayload.d.ts +14 -0
  131. package/dist/storage/ReplicationEventPayload.js +2 -0
  132. package/dist/storage/ReplicationEventPayload.js.map +1 -0
  133. package/dist/storage/SourceEntity.d.ts +20 -0
  134. package/dist/storage/SourceEntity.js +2 -0
  135. package/dist/storage/SourceEntity.js.map +1 -0
  136. package/dist/storage/SourceTable.d.ts +12 -5
  137. package/dist/storage/SourceTable.js +12 -5
  138. package/dist/storage/SourceTable.js.map +1 -1
  139. package/dist/storage/StorageEngine.d.ts +28 -0
  140. package/dist/storage/StorageEngine.js +45 -0
  141. package/dist/storage/StorageEngine.js.map +1 -0
  142. package/dist/storage/StorageProvider.d.ts +21 -0
  143. package/dist/storage/StorageProvider.js +2 -0
  144. package/dist/storage/StorageProvider.js.map +1 -0
  145. package/dist/storage/WriteCheckpointAPI.d.ts +74 -0
  146. package/dist/storage/WriteCheckpointAPI.js +16 -0
  147. package/dist/storage/WriteCheckpointAPI.js.map +1 -0
  148. package/dist/storage/mongo/MongoBucketBatch.d.ts +24 -5
  149. package/dist/storage/mongo/MongoBucketBatch.js +119 -62
  150. package/dist/storage/mongo/MongoBucketBatch.js.map +1 -1
  151. package/dist/storage/mongo/MongoCompactor.js +20 -3
  152. package/dist/storage/mongo/MongoCompactor.js.map +1 -1
  153. package/dist/storage/mongo/MongoIdSequence.js.map +1 -1
  154. package/dist/storage/mongo/MongoPersistedSyncRulesContent.d.ts +2 -2
  155. package/dist/storage/mongo/MongoPersistedSyncRulesContent.js +2 -2
  156. package/dist/storage/mongo/MongoPersistedSyncRulesContent.js.map +1 -1
  157. package/dist/storage/mongo/MongoStorageProvider.d.ts +5 -0
  158. package/dist/storage/mongo/MongoStorageProvider.js +26 -0
  159. package/dist/storage/mongo/MongoStorageProvider.js.map +1 -0
  160. package/dist/storage/mongo/MongoSyncBucketStorage.d.ts +18 -10
  161. package/dist/storage/mongo/MongoSyncBucketStorage.js +140 -25
  162. package/dist/storage/mongo/MongoSyncBucketStorage.js.map +1 -1
  163. package/dist/storage/mongo/MongoSyncRulesLock.js +1 -1
  164. package/dist/storage/mongo/MongoSyncRulesLock.js.map +1 -1
  165. package/dist/storage/mongo/MongoWriteCheckpointAPI.d.ts +20 -0
  166. package/dist/storage/mongo/MongoWriteCheckpointAPI.js +103 -0
  167. package/dist/storage/mongo/MongoWriteCheckpointAPI.js.map +1 -0
  168. package/dist/storage/mongo/OperationBatch.d.ts +13 -4
  169. package/dist/storage/mongo/OperationBatch.js +25 -7
  170. package/dist/storage/mongo/OperationBatch.js.map +1 -1
  171. package/dist/storage/mongo/PersistedBatch.d.ts +3 -3
  172. package/dist/storage/mongo/PersistedBatch.js +2 -2
  173. package/dist/storage/mongo/PersistedBatch.js.map +1 -1
  174. package/dist/storage/mongo/config.d.ts +19 -0
  175. package/dist/storage/mongo/config.js +26 -0
  176. package/dist/storage/mongo/config.js.map +1 -0
  177. package/dist/storage/mongo/db.d.ts +3 -2
  178. package/dist/storage/mongo/db.js +1 -0
  179. package/dist/storage/mongo/db.js.map +1 -1
  180. package/dist/storage/mongo/models.d.ts +20 -5
  181. package/dist/storage/mongo/models.js.map +1 -1
  182. package/dist/storage/mongo/util.d.ts +12 -1
  183. package/dist/storage/mongo/util.js +50 -2
  184. package/dist/storage/mongo/util.js.map +1 -1
  185. package/dist/storage/storage-index.d.ts +8 -2
  186. package/dist/storage/storage-index.js +8 -2
  187. package/dist/storage/storage-index.js.map +1 -1
  188. package/dist/sync/BroadcastIterable.d.ts +0 -1
  189. package/dist/sync/BroadcastIterable.js.map +1 -1
  190. package/dist/sync/LastValueSink.d.ts +0 -1
  191. package/dist/sync/LastValueSink.js.map +1 -1
  192. package/dist/sync/merge.d.ts +0 -1
  193. package/dist/sync/merge.js.map +1 -1
  194. package/dist/sync/safeRace.js.map +1 -1
  195. package/dist/sync/sync.d.ts +1 -1
  196. package/dist/sync/sync.js +5 -5
  197. package/dist/sync/sync.js.map +1 -1
  198. package/dist/sync/util.d.ts +0 -2
  199. package/dist/sync/util.js.map +1 -1
  200. package/dist/system/ServiceContext.d.ts +37 -0
  201. package/dist/system/ServiceContext.js +48 -0
  202. package/dist/system/ServiceContext.js.map +1 -0
  203. package/dist/system/system-index.d.ts +1 -1
  204. package/dist/system/system-index.js +1 -1
  205. package/dist/system/system-index.js.map +1 -1
  206. package/dist/util/Mutex.js.map +1 -1
  207. package/dist/util/config/collectors/config-collector.js.map +1 -1
  208. package/dist/util/config/collectors/impl/base64-config-collector.js.map +1 -1
  209. package/dist/util/config/collectors/impl/filesystem-config-collector.js.map +1 -1
  210. package/dist/util/config/compound-config-collector.d.ts +9 -2
  211. package/dist/util/config/compound-config-collector.js +31 -23
  212. package/dist/util/config/compound-config-collector.js.map +1 -1
  213. package/dist/util/config/sync-rules/impl/base64-sync-rules-collector.js.map +1 -1
  214. package/dist/util/config/sync-rules/impl/filesystem-sync-rules-collector.js.map +1 -1
  215. package/dist/util/config/sync-rules/impl/inline-sync-rules-collector.js.map +1 -1
  216. package/dist/util/config/sync-rules/sync-rules-provider.d.ts +9 -0
  217. package/dist/util/config/sync-rules/sync-rules-provider.js +15 -0
  218. package/dist/util/config/sync-rules/sync-rules-provider.js.map +1 -0
  219. package/dist/util/config/types.d.ts +7 -4
  220. package/dist/util/config/types.js.map +1 -1
  221. package/dist/util/config.d.ts +3 -4
  222. package/dist/util/config.js +5 -20
  223. package/dist/util/config.js.map +1 -1
  224. package/dist/util/memory-tracking.js.map +1 -1
  225. package/dist/util/secs.js.map +1 -1
  226. package/dist/util/util-index.d.ts +3 -6
  227. package/dist/util/util-index.js +3 -6
  228. package/dist/util/util-index.js.map +1 -1
  229. package/dist/util/utils.d.ts +10 -7
  230. package/dist/util/utils.js +36 -25
  231. package/dist/util/utils.js.map +1 -1
  232. package/package.json +8 -12
  233. package/src/api/RouteAPI.ts +78 -0
  234. package/src/api/api-index.ts +1 -0
  235. package/src/api/diagnostics.ts +18 -70
  236. package/src/api/schema.ts +18 -90
  237. package/src/auth/KeyStore.ts +9 -6
  238. package/src/auth/RemoteJWKSCollector.ts +4 -1
  239. package/src/auth/StaticSupabaseKeyCollector.ts +31 -0
  240. package/src/auth/auth-index.ts +1 -1
  241. package/src/db/mongo.ts +5 -3
  242. package/src/entry/cli-entry.ts +3 -2
  243. package/src/entry/commands/compact-action.ts +24 -12
  244. package/src/entry/commands/migrate-action.ts +5 -8
  245. package/src/entry/commands/teardown-action.ts +2 -2
  246. package/src/index.ts +5 -2
  247. package/src/metrics/Metrics.ts +6 -16
  248. package/src/migrations/db/migrations/1684951997326-init.ts +9 -4
  249. package/src/migrations/db/migrations/1702295701188-sync-rule-state.ts +7 -4
  250. package/src/migrations/db/migrations/1711543888062-write-checkpoint-index.ts +6 -4
  251. package/src/migrations/db/migrations/1727099539247-custom-write-checkpoint-index.ts +37 -0
  252. package/src/migrations/migrations.ts +24 -8
  253. package/src/modules/AbstractModule.ts +37 -0
  254. package/src/modules/ModuleManager.ts +34 -0
  255. package/src/modules/modules-index.ts +2 -0
  256. package/src/replication/AbstractReplicationJob.ts +79 -0
  257. package/src/replication/AbstractReplicator.ts +228 -0
  258. package/src/replication/ErrorRateLimiter.ts +0 -44
  259. package/src/replication/ReplicationEngine.ts +43 -0
  260. package/src/replication/ReplicationModule.ts +122 -0
  261. package/src/replication/replication-index.ts +4 -6
  262. package/src/routes/RouterEngine.ts +120 -0
  263. package/src/routes/auth.ts +21 -12
  264. package/src/routes/configure-fastify.ts +26 -27
  265. package/src/routes/configure-rsocket.ts +13 -8
  266. package/src/routes/endpoints/admin.ts +72 -76
  267. package/src/routes/endpoints/checkpointing.ts +51 -11
  268. package/src/routes/endpoints/socket-route.ts +10 -6
  269. package/src/routes/endpoints/sync-rules.ts +41 -25
  270. package/src/routes/endpoints/sync-stream.ts +8 -8
  271. package/src/routes/router.ts +8 -3
  272. package/src/routes/routes-index.ts +1 -0
  273. package/src/runner/teardown.ts +50 -88
  274. package/src/storage/BucketStorage.ts +103 -41
  275. package/src/storage/MongoBucketStorage.ts +65 -53
  276. package/src/storage/ReplicationEventPayload.ts +16 -0
  277. package/src/storage/SourceEntity.ts +22 -0
  278. package/src/storage/SourceTable.ts +14 -7
  279. package/src/storage/StorageEngine.ts +62 -0
  280. package/src/storage/StorageProvider.ts +27 -0
  281. package/src/storage/WriteCheckpointAPI.ts +85 -0
  282. package/src/storage/mongo/MongoBucketBatch.ts +164 -84
  283. package/src/storage/mongo/MongoCompactor.ts +25 -4
  284. package/src/storage/mongo/MongoPersistedSyncRulesContent.ts +7 -4
  285. package/src/storage/mongo/MongoStorageProvider.ts +31 -0
  286. package/src/storage/mongo/MongoSyncBucketStorage.ts +118 -41
  287. package/src/storage/mongo/MongoSyncRulesLock.ts +7 -3
  288. package/src/storage/mongo/MongoWriteCheckpointAPI.ts +151 -0
  289. package/src/storage/mongo/OperationBatch.ts +28 -12
  290. package/src/storage/mongo/PersistedBatch.ts +10 -6
  291. package/src/storage/mongo/config.ts +40 -0
  292. package/src/storage/mongo/db.ts +4 -1
  293. package/src/storage/mongo/models.ts +21 -5
  294. package/src/storage/mongo/util.ts +48 -3
  295. package/src/storage/storage-index.ts +8 -2
  296. package/src/sync/sync.ts +7 -4
  297. package/src/sync/util.ts +0 -1
  298. package/src/system/ServiceContext.ts +68 -0
  299. package/src/system/system-index.ts +1 -1
  300. package/src/util/config/compound-config-collector.ts +48 -30
  301. package/src/util/config/sync-rules/sync-rules-provider.ts +18 -0
  302. package/src/util/config/types.ts +7 -5
  303. package/src/util/config.ts +6 -23
  304. package/src/util/util-index.ts +3 -6
  305. package/src/util/utils.ts +48 -41
  306. package/test/src/__snapshots__/sync.test.ts.snap +14 -14
  307. package/test/src/auth.test.ts +7 -7
  308. package/test/src/broadcast_iterable.test.ts +1 -1
  309. package/test/src/compacting.test.ts +50 -40
  310. package/test/src/data_storage.test.ts +382 -202
  311. package/test/src/env.ts +1 -3
  312. package/test/src/merge_iterable.test.ts +1 -6
  313. package/test/src/routes/probes.integration.test.ts +34 -30
  314. package/test/src/setup.ts +1 -1
  315. package/test/src/stream_utils.ts +42 -0
  316. package/test/src/sync.test.ts +115 -39
  317. package/test/src/util.ts +48 -51
  318. package/test/tsconfig.json +1 -1
  319. package/tsconfig.tsbuildinfo +1 -1
  320. package/vitest.config.ts +7 -1
  321. package/dist/auth/SupabaseKeyCollector.d.ts +0 -22
  322. package/dist/auth/SupabaseKeyCollector.js +0 -61
  323. package/dist/auth/SupabaseKeyCollector.js.map +0 -1
  324. package/dist/replication/PgRelation.d.ts +0 -16
  325. package/dist/replication/PgRelation.js +0 -26
  326. package/dist/replication/PgRelation.js.map +0 -1
  327. package/dist/replication/WalConnection.d.ts +0 -34
  328. package/dist/replication/WalConnection.js +0 -190
  329. package/dist/replication/WalConnection.js.map +0 -1
  330. package/dist/replication/WalStream.d.ts +0 -57
  331. package/dist/replication/WalStream.js +0 -519
  332. package/dist/replication/WalStream.js.map +0 -1
  333. package/dist/replication/WalStreamManager.d.ts +0 -30
  334. package/dist/replication/WalStreamManager.js +0 -198
  335. package/dist/replication/WalStreamManager.js.map +0 -1
  336. package/dist/replication/WalStreamRunner.d.ts +0 -38
  337. package/dist/replication/WalStreamRunner.js +0 -155
  338. package/dist/replication/WalStreamRunner.js.map +0 -1
  339. package/dist/replication/util.d.ts +0 -9
  340. package/dist/replication/util.js +0 -62
  341. package/dist/replication/util.js.map +0 -1
  342. package/dist/system/CorePowerSyncSystem.d.ts +0 -23
  343. package/dist/system/CorePowerSyncSystem.js +0 -52
  344. package/dist/system/CorePowerSyncSystem.js.map +0 -1
  345. package/dist/util/PgManager.d.ts +0 -24
  346. package/dist/util/PgManager.js +0 -55
  347. package/dist/util/PgManager.js.map +0 -1
  348. package/dist/util/migration_lib.d.ts +0 -11
  349. package/dist/util/migration_lib.js +0 -64
  350. package/dist/util/migration_lib.js.map +0 -1
  351. package/dist/util/pgwire_utils.d.ts +0 -24
  352. package/dist/util/pgwire_utils.js +0 -117
  353. package/dist/util/pgwire_utils.js.map +0 -1
  354. package/dist/util/populate_test_data.d.ts +0 -8
  355. package/dist/util/populate_test_data.js +0 -65
  356. package/dist/util/populate_test_data.js.map +0 -1
  357. package/src/auth/SupabaseKeyCollector.ts +0 -67
  358. package/src/replication/PgRelation.ts +0 -42
  359. package/src/replication/WalConnection.ts +0 -227
  360. package/src/replication/WalStream.ts +0 -631
  361. package/src/replication/WalStreamManager.ts +0 -213
  362. package/src/replication/WalStreamRunner.ts +0 -180
  363. package/src/replication/util.ts +0 -76
  364. package/src/system/CorePowerSyncSystem.ts +0 -64
  365. package/src/util/PgManager.ts +0 -64
  366. package/src/util/migration_lib.ts +0 -79
  367. package/src/util/pgwire_utils.ts +0 -139
  368. package/src/util/populate_test_data.ts +0 -78
  369. package/test/src/__snapshots__/pg_test.test.ts.snap +0 -256
  370. package/test/src/large_batch.test.ts +0 -194
  371. package/test/src/pg_test.test.ts +0 -450
  372. package/test/src/schema_changes.test.ts +0 -545
  373. package/test/src/slow_tests.test.ts +0 -338
  374. package/test/src/validation.test.ts +0 -63
  375. package/test/src/wal_stream.test.ts +0 -319
  376. package/test/src/wal_stream_utils.ts +0 -156
@@ -1,139 +0,0 @@
1
- // Adapted from https://github.com/kagis/pgwire/blob/0dc927f9f8990a903f238737326e53ba1c8d094f/mod.js#L2218
2
-
3
- import * as bson from 'bson';
4
- import * as uuid from 'uuid';
5
- import * as pgwire from '@powersync/service-jpgwire';
6
- import { SqliteJsonValue, SqliteRow, ToastableSqliteRow, toSyncRulesRow } from '@powersync/service-sync-rules';
7
-
8
- import * as replication from '../replication/replication-index.js';
9
- import { logger } from '@powersync/lib-services-framework';
10
-
11
- /**
12
- * pgwire message -> SQLite row.
13
- * @param message
14
- */
15
- export function constructAfterRecord(message: pgwire.PgoutputInsert | pgwire.PgoutputUpdate): SqliteRow {
16
- const rawData = (message as any).afterRaw;
17
-
18
- const record = pgwire.decodeTuple(message.relation, rawData);
19
- return toSyncRulesRow(record);
20
- }
21
-
22
- export function hasToastedValues(row: ToastableSqliteRow) {
23
- for (let key in row) {
24
- if (typeof row[key] == 'undefined') {
25
- return true;
26
- }
27
- }
28
- return false;
29
- }
30
-
31
- export function isCompleteRow(row: ToastableSqliteRow): row is SqliteRow {
32
- return !hasToastedValues(row);
33
- }
34
-
35
- /**
36
- * pgwire message -> SQLite row.
37
- * @param message
38
- */
39
- export function constructBeforeRecord(message: pgwire.PgoutputDelete | pgwire.PgoutputUpdate): SqliteRow | undefined {
40
- const rawData = (message as any).beforeRaw;
41
- if (rawData == null) {
42
- return undefined;
43
- }
44
- const record = pgwire.decodeTuple(message.relation, rawData);
45
- return toSyncRulesRow(record);
46
- }
47
-
48
- function getRawReplicaIdentity(
49
- tuple: ToastableSqliteRow,
50
- columns: replication.ReplicationColumn[]
51
- ): Record<string, any> {
52
- let result: Record<string, any> = {};
53
- for (let column of columns) {
54
- const name = column.name;
55
- result[name] = tuple[name];
56
- }
57
- return result;
58
- }
59
- const ID_NAMESPACE = 'a396dd91-09fc-4017-a28d-3df722f651e9';
60
-
61
- export function getUuidReplicaIdentityString(
62
- tuple: ToastableSqliteRow,
63
- columns: replication.ReplicationColumn[]
64
- ): string {
65
- const rawIdentity = getRawReplicaIdentity(tuple, columns);
66
-
67
- return uuidForRow(rawIdentity);
68
- }
69
-
70
- export function uuidForRow(row: SqliteRow): string {
71
- // Important: This must not change, since it will affect how ids are generated.
72
- // Use BSON so that it's a well-defined format without encoding ambiguities.
73
- const repr = bson.serialize(row);
74
- return uuid.v5(repr, ID_NAMESPACE);
75
- }
76
-
77
- export function getUuidReplicaIdentityBson(
78
- tuple: ToastableSqliteRow,
79
- columns: replication.ReplicationColumn[]
80
- ): bson.UUID {
81
- if (columns.length == 0) {
82
- // REPLICA IDENTITY NOTHING - generate random id
83
- return new bson.UUID(uuid.v4());
84
- }
85
- const rawIdentity = getRawReplicaIdentity(tuple, columns);
86
-
87
- return uuidForRowBson(rawIdentity);
88
- }
89
-
90
- export function uuidForRowBson(row: SqliteRow): bson.UUID {
91
- // Important: This must not change, since it will affect how ids are generated.
92
- // Use BSON so that it's a well-defined format without encoding ambiguities.
93
- const repr = bson.serialize(row);
94
- const buffer = Buffer.alloc(16);
95
- return new bson.UUID(uuid.v5(repr, ID_NAMESPACE, buffer));
96
- }
97
-
98
- export function escapeIdentifier(identifier: string) {
99
- return `"${identifier.replace(/"/g, '""').replace(/\./g, '"."')}"`;
100
- }
101
-
102
- export function autoParameter(arg: SqliteJsonValue | boolean): pgwire.StatementParam {
103
- if (arg == null) {
104
- return { type: 'varchar', value: null };
105
- } else if (typeof arg == 'string') {
106
- return { type: 'varchar', value: arg };
107
- } else if (typeof arg == 'number') {
108
- if (Number.isInteger(arg)) {
109
- return { type: 'int8', value: arg };
110
- } else {
111
- return { type: 'float8', value: arg };
112
- }
113
- } else if (typeof arg == 'boolean') {
114
- return { type: 'bool', value: arg };
115
- } else if (typeof arg == 'bigint') {
116
- return { type: 'int8', value: arg };
117
- } else {
118
- throw new Error(`Unsupported query parameter: ${typeof arg}`);
119
- }
120
- }
121
-
122
- export async function retriedQuery(db: pgwire.PgClient, ...statements: pgwire.Statement[]): Promise<pgwire.PgResult>;
123
- export async function retriedQuery(db: pgwire.PgClient, query: string): Promise<pgwire.PgResult>;
124
-
125
- /**
126
- * Retry a simple query - up to 2 attempts total.
127
- */
128
- export async function retriedQuery(db: pgwire.PgClient, ...args: any[]) {
129
- for (let tries = 2; ; tries--) {
130
- try {
131
- return await db.query(...args);
132
- } catch (e) {
133
- if (tries == 1) {
134
- throw e;
135
- }
136
- logger.warn('Query error, retrying', e);
137
- }
138
- }
139
- }
@@ -1,78 +0,0 @@
1
- import * as crypto from 'crypto';
2
- import { Worker, isMainThread, parentPort, workerData } from 'node:worker_threads';
3
-
4
- import { connectPgWire } from '@powersync/service-jpgwire';
5
- import { NormalizedPostgresConnection } from '@powersync/service-types';
6
-
7
- // This util is actually for tests only, but we need it compiled to JS for the service to work, so it's placed in the service.
8
-
9
- export interface PopulateDataOptions {
10
- connection: NormalizedPostgresConnection;
11
- num_transactions: number;
12
- per_transaction: number;
13
- size: number;
14
- }
15
-
16
- if (isMainThread || parentPort == null) {
17
- // Not a worker - ignore
18
- } else {
19
- try {
20
- const options = workerData as PopulateDataOptions;
21
-
22
- const result = await populateDataInner(options);
23
- parentPort.postMessage(result);
24
- process.exit(0);
25
- } catch (e) {
26
- // This is a bug, not a connection issue
27
- console.error(e);
28
- // Only closes the Worker thread
29
- process.exit(2);
30
- }
31
- }
32
-
33
- async function populateDataInner(options: PopulateDataOptions) {
34
- // Dedicated connection so we can release the memory easily
35
- const initialDb = await connectPgWire(options.connection, { type: 'standard' });
36
- const largeDescription = crypto.randomBytes(options.size / 2).toString('hex');
37
- let operation_count = 0;
38
- for (let i = 0; i < options.num_transactions; i++) {
39
- const prefix = `test${i}K`;
40
-
41
- await initialDb.query({
42
- statement: `INSERT INTO test_data(id, description, other) SELECT $1 || i, $2, 'foo' FROM generate_series(1, $3) i`,
43
- params: [
44
- { type: 'varchar', value: prefix },
45
- { type: 'varchar', value: largeDescription },
46
- { type: 'int4', value: options.per_transaction }
47
- ]
48
- });
49
- operation_count += options.per_transaction;
50
- }
51
- await initialDb.end();
52
- return operation_count;
53
- }
54
-
55
- export async function populateData(options: PopulateDataOptions) {
56
- const WORKER_TIMEOUT = 30_000;
57
-
58
- const worker = new Worker(new URL('./populate_test_data.js', import.meta.url), {
59
- workerData: options
60
- });
61
- const timeout = setTimeout(() => {
62
- // Exits with code 1 below
63
- worker.terminate();
64
- }, WORKER_TIMEOUT);
65
- try {
66
- return await new Promise<number>((resolve, reject) => {
67
- worker.on('message', resolve);
68
- worker.on('error', reject);
69
- worker.on('exit', (code) => {
70
- if (code !== 0) {
71
- reject(new Error(`Populating data failed with exit code ${code}`));
72
- }
73
- });
74
- });
75
- } finally {
76
- clearTimeout(timeout);
77
- }
78
- }
@@ -1,256 +0,0 @@
1
- // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
-
3
- exports[`pg data types > schema 1`] = `
4
- [
5
- {
6
- "name": "public",
7
- "tables": [
8
- {
9
- "columns": [
10
- {
11
- "name": "id",
12
- "pg_type": "int4",
13
- "type": "integer",
14
- },
15
- {
16
- "name": "text",
17
- "pg_type": "text",
18
- "type": "text",
19
- },
20
- {
21
- "name": "uuid",
22
- "pg_type": "uuid",
23
- "type": "uuid",
24
- },
25
- {
26
- "name": "varchar",
27
- "pg_type": "varchar",
28
- "type": "character varying(255)",
29
- },
30
- {
31
- "name": "bool",
32
- "pg_type": "bool",
33
- "type": "boolean",
34
- },
35
- {
36
- "name": "bytea",
37
- "pg_type": "bytea",
38
- "type": "bytea",
39
- },
40
- {
41
- "name": "int2",
42
- "pg_type": "int2",
43
- "type": "smallint",
44
- },
45
- {
46
- "name": "int4",
47
- "pg_type": "int4",
48
- "type": "integer",
49
- },
50
- {
51
- "name": "int8",
52
- "pg_type": "int8",
53
- "type": "bigint",
54
- },
55
- {
56
- "name": "float4",
57
- "pg_type": "float4",
58
- "type": "real",
59
- },
60
- {
61
- "name": "float8",
62
- "pg_type": "float8",
63
- "type": "double precision",
64
- },
65
- {
66
- "name": "numeric",
67
- "pg_type": "numeric",
68
- "type": "numeric",
69
- },
70
- {
71
- "name": "json",
72
- "pg_type": "json",
73
- "type": "json",
74
- },
75
- {
76
- "name": "jsonb",
77
- "pg_type": "jsonb",
78
- "type": "jsonb",
79
- },
80
- {
81
- "name": "pg_lsn",
82
- "pg_type": "pg_lsn",
83
- "type": "pg_lsn",
84
- },
85
- {
86
- "name": "date",
87
- "pg_type": "date",
88
- "type": "date",
89
- },
90
- {
91
- "name": "time",
92
- "pg_type": "time",
93
- "type": "time without time zone",
94
- },
95
- {
96
- "name": "timestamp",
97
- "pg_type": "timestamp",
98
- "type": "timestamp without time zone",
99
- },
100
- {
101
- "name": "timestamptz",
102
- "pg_type": "timestamptz",
103
- "type": "timestamp with time zone",
104
- },
105
- {
106
- "name": "interval",
107
- "pg_type": "interval",
108
- "type": "interval",
109
- },
110
- {
111
- "name": "macaddr",
112
- "pg_type": "macaddr",
113
- "type": "macaddr",
114
- },
115
- {
116
- "name": "inet",
117
- "pg_type": "inet",
118
- "type": "inet",
119
- },
120
- {
121
- "name": "oid",
122
- "pg_type": "oid",
123
- "type": "oid",
124
- },
125
- ],
126
- "name": "test_data",
127
- },
128
- {
129
- "columns": [
130
- {
131
- "name": "id",
132
- "pg_type": "int4",
133
- "type": "integer",
134
- },
135
- {
136
- "name": "text",
137
- "pg_type": "text[]",
138
- "type": "text[]",
139
- },
140
- {
141
- "name": "uuid",
142
- "pg_type": "uuid[]",
143
- "type": "uuid[]",
144
- },
145
- {
146
- "name": "varchar",
147
- "pg_type": "varchar[]",
148
- "type": "character varying(255)[]",
149
- },
150
- {
151
- "name": "bool",
152
- "pg_type": "bool[]",
153
- "type": "boolean[]",
154
- },
155
- {
156
- "name": "bytea",
157
- "pg_type": "bytea[]",
158
- "type": "bytea[]",
159
- },
160
- {
161
- "name": "int2",
162
- "pg_type": "int2[]",
163
- "type": "smallint[]",
164
- },
165
- {
166
- "name": "int4",
167
- "pg_type": "int4[]",
168
- "type": "integer[]",
169
- },
170
- {
171
- "name": "int8",
172
- "pg_type": "int8[]",
173
- "type": "bigint[]",
174
- },
175
- {
176
- "name": "float4",
177
- "pg_type": "float4[]",
178
- "type": "real[]",
179
- },
180
- {
181
- "name": "float8",
182
- "pg_type": "float8[]",
183
- "type": "double precision[]",
184
- },
185
- {
186
- "name": "numeric",
187
- "pg_type": "numeric[]",
188
- "type": "numeric[]",
189
- },
190
- {
191
- "name": "json",
192
- "pg_type": "json[]",
193
- "type": "json[]",
194
- },
195
- {
196
- "name": "jsonb",
197
- "pg_type": "jsonb[]",
198
- "type": "jsonb[]",
199
- },
200
- {
201
- "name": "pg_lsn",
202
- "pg_type": "pg_lsn[]",
203
- "type": "pg_lsn[]",
204
- },
205
- {
206
- "name": "date",
207
- "pg_type": "date[]",
208
- "type": "date[]",
209
- },
210
- {
211
- "name": "time",
212
- "pg_type": "time[]",
213
- "type": "time without time zone[]",
214
- },
215
- {
216
- "name": "timestamp",
217
- "pg_type": "timestamp[]",
218
- "type": "timestamp without time zone[]",
219
- },
220
- {
221
- "name": "timestamptz",
222
- "pg_type": "timestamptz[]",
223
- "type": "timestamp with time zone[]",
224
- },
225
- {
226
- "name": "interval",
227
- "pg_type": "interval[]",
228
- "type": "interval[]",
229
- },
230
- {
231
- "name": "macaddr",
232
- "pg_type": "macaddr[]",
233
- "type": "macaddr[]",
234
- },
235
- {
236
- "name": "inet",
237
- "pg_type": "inet[]",
238
- "type": "inet[]",
239
- },
240
- {
241
- "name": "oid",
242
- "pg_type": "oid[]",
243
- "type": "oid[]",
244
- },
245
- {
246
- "name": "multidimensional",
247
- "pg_type": "text[]",
248
- "type": "text[]",
249
- },
250
- ],
251
- "name": "test_data_arrays",
252
- },
253
- ],
254
- },
255
- ]
256
- `;
@@ -1,194 +0,0 @@
1
- import { describe, expect, test } from 'vitest';
2
- import { env } from './env.js';
3
- import { MONGO_STORAGE_FACTORY, StorageFactory, TEST_CONNECTION_OPTIONS } from './util.js';
4
- import { walStreamTest } from './wal_stream_utils.js';
5
- import { populateData } from '../../dist/util/populate_test_data.js';
6
-
7
- describe('batch replication tests - mongodb', function () {
8
- // These are slow but consistent tests.
9
- // Not run on every test run, but we do run on CI, or when manually debugging issues.
10
- if (env.CI || env.SLOW_TESTS) {
11
- defineBatchTests(MONGO_STORAGE_FACTORY);
12
- } else {
13
- // Need something in this file.
14
- test('no-op', () => {});
15
- }
16
- });
17
-
18
- const BASIC_SYNC_RULES = `bucket_definitions:
19
- global:
20
- data:
21
- - SELECT id, description, other FROM "test_data"`;
22
-
23
- function defineBatchTests(factory: StorageFactory) {
24
- test(
25
- 'update large record',
26
- walStreamTest(factory, async (context) => {
27
- // This test generates a large transaction in MongoDB, despite the replicated data
28
- // not being that large.
29
- // If we don't limit transaction size, we could run into this error:
30
- // > -31800: transaction is too large and will not fit in the storage engine cache
31
- await context.updateSyncRules(BASIC_SYNC_RULES);
32
- const { pool } = context;
33
-
34
- await pool.query(`CREATE TABLE test_data(id text primary key, description text, other text)`);
35
-
36
- await context.replicateSnapshot();
37
-
38
- let operation_count = await populateData({
39
- num_transactions: 1,
40
- per_transaction: 80,
41
- size: 4_000_000,
42
- connection: TEST_CONNECTION_OPTIONS
43
- });
44
-
45
- const start = Date.now();
46
-
47
- context.startStreaming();
48
-
49
- const checkpoint = await context.getCheckpoint({ timeout: 100_000 });
50
- const duration = Date.now() - start;
51
- const used = Math.round(process.memoryUsage().heapUsed / 1024 / 1024);
52
- const checksum = await context.storage!.getChecksums(checkpoint, ['global[]']);
53
- expect(checksum.get('global[]')!.count).toEqual(operation_count);
54
- const perSecond = Math.round((operation_count / duration) * 1000);
55
- console.log(`${operation_count} ops in ${duration}ms ${perSecond} ops/s. ${used}MB heap`);
56
- }),
57
- { timeout: 120_000 }
58
- );
59
-
60
- test(
61
- 'initial replication performance',
62
- walStreamTest(factory, async (context) => {
63
- // Manual test to check initial replication performance and memory usage
64
- await context.updateSyncRules(BASIC_SYNC_RULES);
65
- const { pool } = context;
66
-
67
- await pool.query(`CREATE TABLE test_data(id text primary key, description text, other text)`);
68
-
69
- // Some stats (varies a lot):
70
- // Old 'postgres' driver, using cursor(2)
71
- // 15 ops in 19559ms 1 ops/s. 354MB RSS, 115MB heap, 137MB external
72
- // 25 ops in 42984ms 1 ops/s. 377MB RSS, 129MB heap, 137MB external
73
- // 35 ops in 41337ms 1 ops/s. 365MB RSS, 115MB heap, 137MB external
74
-
75
- // streaming with pgwire
76
- // 15 ops in 26423ms 1 ops/s. 379MB RSS, 128MB heap, 182MB external, 165MB ArrayBuffers
77
- // 35 ops in 78897ms 0 ops/s. 539MB RSS, 52MB heap, 87MB external, 83MB ArrayBuffers
78
-
79
- let operation_count = await populateData({
80
- num_transactions: 1,
81
- per_transaction: 35,
82
- size: 14_000_000,
83
- connection: TEST_CONNECTION_OPTIONS
84
- });
85
-
86
- global.gc?.();
87
-
88
- // Note that we could already have high memory usage at this point
89
- printMemoryUsage();
90
-
91
- let interval = setInterval(() => {
92
- printMemoryUsage();
93
- }, 2000);
94
- try {
95
- const start = Date.now();
96
-
97
- await context.replicateSnapshot();
98
- await context.storage!.autoActivate();
99
- context.startStreaming();
100
-
101
- const checkpoint = await context.getCheckpoint({ timeout: 100_000 });
102
- const duration = Date.now() - start;
103
- const checksum = await context.storage!.getChecksums(checkpoint, ['global[]']);
104
- expect(checksum.get('global[]')!.count).toEqual(operation_count);
105
- const perSecond = Math.round((operation_count / duration) * 1000);
106
- console.log(`${operation_count} ops in ${duration}ms ${perSecond} ops/s.`);
107
- printMemoryUsage();
108
- } finally {
109
- clearInterval(interval);
110
- }
111
- }),
112
- { timeout: 120_000 }
113
- );
114
-
115
- test(
116
- 'large number of operations',
117
- walStreamTest(factory, async (context) => {
118
- // This just tests performance of a large number of operations inside a transaction.
119
- await context.updateSyncRules(BASIC_SYNC_RULES);
120
- const { pool } = context;
121
-
122
- await pool.query(`CREATE TABLE test_data(id text primary key, description text, other text)`);
123
-
124
- await context.replicateSnapshot();
125
-
126
- const numTransactions = 20;
127
- const perTransaction = 1500;
128
- let operationCount = 0;
129
-
130
- const description = 'description';
131
-
132
- for (let i = 0; i < numTransactions; i++) {
133
- const prefix = `test${i}K`;
134
-
135
- await pool.query(
136
- {
137
- statement: `INSERT INTO test_data(id, description, other) SELECT $1 || i, $2 || i, 'foo' FROM generate_series(1, $3) i`,
138
- params: [
139
- { type: 'varchar', value: prefix },
140
- { type: 'varchar', value: description },
141
- { type: 'int4', value: perTransaction }
142
- ]
143
- },
144
- {
145
- statement: `UPDATE test_data SET other = other || '#' WHERE id LIKE $1 || '%'`,
146
- params: [{ type: 'varchar', value: prefix }]
147
- }
148
- );
149
- operationCount += perTransaction * 2;
150
- }
151
-
152
- const start = Date.now();
153
-
154
- context.startStreaming();
155
-
156
- const checkpoint = await context.getCheckpoint({ timeout: 50_000 });
157
- const duration = Date.now() - start;
158
- const used = Math.round(process.memoryUsage().heapUsed / 1024 / 1024);
159
- const checksum = await context.storage!.getChecksums(checkpoint, ['global[]']);
160
- expect(checksum.get('global[]')!.count).toEqual(operationCount);
161
- const perSecond = Math.round((operationCount / duration) * 1000);
162
- // This number depends on the test machine, so we keep the test significantly
163
- // lower than expected numbers.
164
- expect(perSecond).toBeGreaterThan(1000);
165
- console.log(`${operationCount} ops in ${duration}ms ${perSecond} ops/s. ${used}MB heap`);
166
-
167
- // Truncating is fast (~10k ops/second).
168
- // We'd need a really large set of data to actually run into limits when truncating,
169
- // but we just test with the data we have here.
170
- const truncateStart = Date.now();
171
- await pool.query(`TRUNCATE test_data`);
172
-
173
- const checkpoint2 = await context.getCheckpoint({ timeout: 20_000 });
174
- const truncateDuration = Date.now() - truncateStart;
175
-
176
- const checksum2 = await context.storage!.getChecksums(checkpoint2, ['global[]']);
177
- const truncateCount = checksum2.get('global[]')!.count - checksum.get('global[]')!.count;
178
- expect(truncateCount).toEqual(numTransactions * perTransaction);
179
- const truncatePerSecond = Math.round((truncateCount / truncateDuration) * 1000);
180
- console.log(`Truncated ${truncateCount} ops in ${truncateDuration}ms ${truncatePerSecond} ops/s. ${used}MB heap`);
181
- }),
182
- { timeout: 90_000 }
183
- );
184
-
185
- function printMemoryUsage() {
186
- const memoryUsage = process.memoryUsage();
187
-
188
- const rss = Math.round(memoryUsage.rss / 1024 / 1024);
189
- const heap = Math.round(memoryUsage.heapUsed / 1024 / 1024);
190
- const external = Math.round(memoryUsage.external / 1024 / 1024);
191
- const arrayBuffers = Math.round(memoryUsage.arrayBuffers / 1024 / 1024);
192
- console.log(`${rss}MB RSS, ${heap}MB heap, ${external}MB external, ${arrayBuffers}MB ArrayBuffers`);
193
- }
194
- }