@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
@@ -1,11 +0,0 @@
1
- import * as pgwire from '@powersync/service-jpgwire';
2
- export type MigrationFunction = (db: pgwire.PgConnection) => Promise<void>;
3
- export declare class Migrations {
4
- private migrations;
5
- add(id: number, name: string, up: MigrationFunction): void;
6
- up(db: pgwire.PgConnection): Promise<void>;
7
- getCurrentMigration(db: pgwire.PgConnection): Promise<{
8
- id: number;
9
- }>;
10
- ensureMigrationsTable(db: pgwire.PgConnection): Promise<void>;
11
- }
@@ -1,64 +0,0 @@
1
- // Very loosely based on https://github.com/porsager/postgres-shift/
2
- export class Migrations {
3
- constructor() {
4
- this.migrations = [];
5
- }
6
- add(id, name, up) {
7
- if (this.migrations.length > 0 && this.migrations[this.migrations.length - 1].id >= id) {
8
- throw new Error('Migration ids must be strictly incrementing');
9
- }
10
- this.migrations.push({ id, up, name });
11
- }
12
- async up(db) {
13
- await db.query('BEGIN');
14
- try {
15
- await this.ensureMigrationsTable(db);
16
- const current = await this.getCurrentMigration(db);
17
- let currentId = current ? current.id : 0;
18
- for (let migration of this.migrations) {
19
- if (migration.id <= currentId) {
20
- continue;
21
- }
22
- await migration.up(db);
23
- await db.query({
24
- statement: `
25
- insert into migrations (
26
- migration_id,
27
- name
28
- ) values (
29
- $1,
30
- $2
31
- )
32
- `,
33
- params: [
34
- { type: 'int4', value: migration.id },
35
- { type: 'varchar', value: migration.name }
36
- ]
37
- });
38
- }
39
- await db.query('COMMIT');
40
- }
41
- catch (e) {
42
- await db.query('ROLLBACK');
43
- throw e;
44
- }
45
- }
46
- getCurrentMigration(db) {
47
- return db
48
- .query(`
49
- select migration_id as id from migrations
50
- order by migration_id desc
51
- limit 1
52
- `)
53
- .then((results) => ({ id: results.rows[0][0] }));
54
- }
55
- async ensureMigrationsTable(db) {
56
- await db.query(`create table if not exists migrations (
57
- migration_id serial primary key,
58
- created_at timestamp with time zone not null default now(),
59
- name text
60
- )
61
- `);
62
- }
63
- }
64
- //# sourceMappingURL=migration_lib.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"migration_lib.js","sourceRoot":"","sources":["../../src/util/migration_lib.ts"],"names":[],"mappings":"AAUA,oEAAoE;AACpE,MAAM,OAAO,UAAU;IAAvB;QACU,eAAU,GAAgB,EAAE,CAAC;IAkEvC,CAAC;IAhEC,GAAG,CAAC,EAAU,EAAE,IAAY,EAAE,EAAqB;QACjD,IAAI,IAAI,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE;YACtF,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;SAChE;QACD,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;IACzC,CAAC;IAED,KAAK,CAAC,EAAE,CAAC,EAAuB;QAC9B,MAAM,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACxB,IAAI;YACF,MAAM,IAAI,CAAC,qBAAqB,CAAC,EAAE,CAAC,CAAC;YACrC,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,mBAAmB,CAAC,EAAE,CAAC,CAAC;YACnD,IAAI,SAAS,GAAG,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;YAEzC,KAAK,IAAI,SAAS,IAAI,IAAI,CAAC,UAAU,EAAE;gBACrC,IAAI,SAAS,CAAC,EAAE,IAAI,SAAS,EAAE;oBAC7B,SAAS;iBACV;gBACD,MAAM,SAAS,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;gBAEvB,MAAM,EAAE,CAAC,KAAK,CAAC;oBACb,SAAS,EAAE;;;;;;;;KAQhB;oBACK,MAAM,EAAE;wBACN,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,CAAC,EAAE,EAAE;wBACrC,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,CAAC,IAAI,EAAE;qBAC3C;iBACF,CAAC,CAAC;aACJ;YAED,MAAM,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;SAC1B;QAAC,OAAO,CAAC,EAAE;YACV,MAAM,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;YAC3B,MAAM,CAAC,CAAC;SACT;IACH,CAAC;IAED,mBAAmB,CAAC,EAAuB;QACzC,OAAO,EAAE;aACN,KAAK,CACJ;;;;KAIH,CACE;aACA,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAW,EAAE,CAAC,CAAC,CAAC;IAC/D,CAAC;IAED,KAAK,CAAC,qBAAqB,CAAC,EAAuB;QACjD,MAAM,EAAE,CAAC,KAAK,CAAC;;;;;KAKd,CAAC,CAAC;IACL,CAAC;CACF"}
@@ -1,24 +0,0 @@
1
- import * as bson from 'bson';
2
- import * as pgwire from '@powersync/service-jpgwire';
3
- import { SqliteJsonValue, SqliteRow, ToastableSqliteRow } from '@powersync/service-sync-rules';
4
- import * as replication from '../replication/replication-index.js';
5
- /**
6
- * pgwire message -> SQLite row.
7
- * @param message
8
- */
9
- export declare function constructAfterRecord(message: pgwire.PgoutputInsert | pgwire.PgoutputUpdate): SqliteRow;
10
- export declare function hasToastedValues(row: ToastableSqliteRow): boolean;
11
- export declare function isCompleteRow(row: ToastableSqliteRow): row is SqliteRow;
12
- /**
13
- * pgwire message -> SQLite row.
14
- * @param message
15
- */
16
- export declare function constructBeforeRecord(message: pgwire.PgoutputDelete | pgwire.PgoutputUpdate): SqliteRow | undefined;
17
- export declare function getUuidReplicaIdentityString(tuple: ToastableSqliteRow, columns: replication.ReplicationColumn[]): string;
18
- export declare function uuidForRow(row: SqliteRow): string;
19
- export declare function getUuidReplicaIdentityBson(tuple: ToastableSqliteRow, columns: replication.ReplicationColumn[]): bson.UUID;
20
- export declare function uuidForRowBson(row: SqliteRow): bson.UUID;
21
- export declare function escapeIdentifier(identifier: string): string;
22
- export declare function autoParameter(arg: SqliteJsonValue | boolean): pgwire.StatementParam;
23
- export declare function retriedQuery(db: pgwire.PgClient, ...statements: pgwire.Statement[]): Promise<pgwire.PgResult>;
24
- export declare function retriedQuery(db: pgwire.PgClient, query: string): Promise<pgwire.PgResult>;
@@ -1,117 +0,0 @@
1
- // Adapted from https://github.com/kagis/pgwire/blob/0dc927f9f8990a903f238737326e53ba1c8d094f/mod.js#L2218
2
- import * as bson from 'bson';
3
- import * as uuid from 'uuid';
4
- import * as pgwire from '@powersync/service-jpgwire';
5
- import { toSyncRulesRow } from '@powersync/service-sync-rules';
6
- import { logger } from '@powersync/lib-services-framework';
7
- /**
8
- * pgwire message -> SQLite row.
9
- * @param message
10
- */
11
- export function constructAfterRecord(message) {
12
- const rawData = message.afterRaw;
13
- const record = pgwire.decodeTuple(message.relation, rawData);
14
- return toSyncRulesRow(record);
15
- }
16
- export function hasToastedValues(row) {
17
- for (let key in row) {
18
- if (typeof row[key] == 'undefined') {
19
- return true;
20
- }
21
- }
22
- return false;
23
- }
24
- export function isCompleteRow(row) {
25
- return !hasToastedValues(row);
26
- }
27
- /**
28
- * pgwire message -> SQLite row.
29
- * @param message
30
- */
31
- export function constructBeforeRecord(message) {
32
- const rawData = message.beforeRaw;
33
- if (rawData == null) {
34
- return undefined;
35
- }
36
- const record = pgwire.decodeTuple(message.relation, rawData);
37
- return toSyncRulesRow(record);
38
- }
39
- function getRawReplicaIdentity(tuple, columns) {
40
- let result = {};
41
- for (let column of columns) {
42
- const name = column.name;
43
- result[name] = tuple[name];
44
- }
45
- return result;
46
- }
47
- const ID_NAMESPACE = 'a396dd91-09fc-4017-a28d-3df722f651e9';
48
- export function getUuidReplicaIdentityString(tuple, columns) {
49
- const rawIdentity = getRawReplicaIdentity(tuple, columns);
50
- return uuidForRow(rawIdentity);
51
- }
52
- export function uuidForRow(row) {
53
- // Important: This must not change, since it will affect how ids are generated.
54
- // Use BSON so that it's a well-defined format without encoding ambiguities.
55
- const repr = bson.serialize(row);
56
- return uuid.v5(repr, ID_NAMESPACE);
57
- }
58
- export function getUuidReplicaIdentityBson(tuple, columns) {
59
- if (columns.length == 0) {
60
- // REPLICA IDENTITY NOTHING - generate random id
61
- return new bson.UUID(uuid.v4());
62
- }
63
- const rawIdentity = getRawReplicaIdentity(tuple, columns);
64
- return uuidForRowBson(rawIdentity);
65
- }
66
- export function uuidForRowBson(row) {
67
- // Important: This must not change, since it will affect how ids are generated.
68
- // Use BSON so that it's a well-defined format without encoding ambiguities.
69
- const repr = bson.serialize(row);
70
- const buffer = Buffer.alloc(16);
71
- return new bson.UUID(uuid.v5(repr, ID_NAMESPACE, buffer));
72
- }
73
- export function escapeIdentifier(identifier) {
74
- return `"${identifier.replace(/"/g, '""').replace(/\./g, '"."')}"`;
75
- }
76
- export function autoParameter(arg) {
77
- if (arg == null) {
78
- return { type: 'varchar', value: null };
79
- }
80
- else if (typeof arg == 'string') {
81
- return { type: 'varchar', value: arg };
82
- }
83
- else if (typeof arg == 'number') {
84
- if (Number.isInteger(arg)) {
85
- return { type: 'int8', value: arg };
86
- }
87
- else {
88
- return { type: 'float8', value: arg };
89
- }
90
- }
91
- else if (typeof arg == 'boolean') {
92
- return { type: 'bool', value: arg };
93
- }
94
- else if (typeof arg == 'bigint') {
95
- return { type: 'int8', value: arg };
96
- }
97
- else {
98
- throw new Error(`Unsupported query parameter: ${typeof arg}`);
99
- }
100
- }
101
- /**
102
- * Retry a simple query - up to 2 attempts total.
103
- */
104
- export async function retriedQuery(db, ...args) {
105
- for (let tries = 2;; tries--) {
106
- try {
107
- return await db.query(...args);
108
- }
109
- catch (e) {
110
- if (tries == 1) {
111
- throw e;
112
- }
113
- logger.warn('Query error, retrying', e);
114
- }
115
- }
116
- }
117
- //# sourceMappingURL=pgwire_utils.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"pgwire_utils.js","sourceRoot":"","sources":["../../src/util/pgwire_utils.ts"],"names":[],"mappings":"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"}
@@ -1,8 +0,0 @@
1
- import { NormalizedPostgresConnection } from '@powersync/service-types';
2
- export interface PopulateDataOptions {
3
- connection: NormalizedPostgresConnection;
4
- num_transactions: number;
5
- per_transaction: number;
6
- size: number;
7
- }
8
- export declare function populateData(options: PopulateDataOptions): Promise<number>;
@@ -1,65 +0,0 @@
1
- import * as crypto from 'crypto';
2
- import { Worker, isMainThread, parentPort, workerData } from 'node:worker_threads';
3
- import { connectPgWire } from '@powersync/service-jpgwire';
4
- if (isMainThread || parentPort == null) {
5
- // Not a worker - ignore
6
- }
7
- else {
8
- try {
9
- const options = workerData;
10
- const result = await populateDataInner(options);
11
- parentPort.postMessage(result);
12
- process.exit(0);
13
- }
14
- catch (e) {
15
- // This is a bug, not a connection issue
16
- console.error(e);
17
- // Only closes the Worker thread
18
- process.exit(2);
19
- }
20
- }
21
- async function populateDataInner(options) {
22
- // Dedicated connection so we can release the memory easily
23
- const initialDb = await connectPgWire(options.connection, { type: 'standard' });
24
- const largeDescription = crypto.randomBytes(options.size / 2).toString('hex');
25
- let operation_count = 0;
26
- for (let i = 0; i < options.num_transactions; i++) {
27
- const prefix = `test${i}K`;
28
- await initialDb.query({
29
- statement: `INSERT INTO test_data(id, description, other) SELECT $1 || i, $2, 'foo' FROM generate_series(1, $3) i`,
30
- params: [
31
- { type: 'varchar', value: prefix },
32
- { type: 'varchar', value: largeDescription },
33
- { type: 'int4', value: options.per_transaction }
34
- ]
35
- });
36
- operation_count += options.per_transaction;
37
- }
38
- await initialDb.end();
39
- return operation_count;
40
- }
41
- export async function populateData(options) {
42
- const WORKER_TIMEOUT = 30000;
43
- const worker = new Worker(new URL('./populate_test_data.js', import.meta.url), {
44
- workerData: options
45
- });
46
- const timeout = setTimeout(() => {
47
- // Exits with code 1 below
48
- worker.terminate();
49
- }, WORKER_TIMEOUT);
50
- try {
51
- return await new Promise((resolve, reject) => {
52
- worker.on('message', resolve);
53
- worker.on('error', reject);
54
- worker.on('exit', (code) => {
55
- if (code !== 0) {
56
- reject(new Error(`Populating data failed with exit code ${code}`));
57
- }
58
- });
59
- });
60
- }
61
- finally {
62
- clearTimeout(timeout);
63
- }
64
- }
65
- //# sourceMappingURL=populate_test_data.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"populate_test_data.js","sourceRoot":"","sources":["../../src/util/populate_test_data.ts"],"names":[],"mappings":"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"}
@@ -1,67 +0,0 @@
1
- import * as jose from 'jose';
2
- import * as pgwire from '@powersync/service-jpgwire';
3
- import { connectPgWirePool, pgwireRows } from '@powersync/service-jpgwire';
4
- import { KeyCollector } from './KeyCollector.js';
5
- import { KeyOptions, KeySpec } from './KeySpec.js';
6
- import { retriedQuery } from '../util/pgwire_utils.js';
7
- import { ResolvedConnection } from '../util/config/types.js';
8
-
9
- /**
10
- * Fetches key from the Supabase database.
11
- *
12
- * Unfortunately, despite the JWTs containing a kid, we have no way to lookup that kid
13
- * before receiving a valid token.
14
- */
15
- export class SupabaseKeyCollector implements KeyCollector {
16
- private pool: pgwire.PgClient;
17
-
18
- private keyOptions: KeyOptions = {
19
- requiresAudience: ['authenticated'],
20
- maxLifetimeSeconds: 86400 * 7 + 1200 // 1 week + 20 minutes margin
21
- };
22
-
23
- constructor(connection: ResolvedConnection) {
24
- this.pool = connectPgWirePool(connection, {
25
- // To avoid overloading the source database with open connections,
26
- // limit to a single connection, and close the connection shortly
27
- // after using it.
28
- idleTimeout: 5_000,
29
- maxSize: 1
30
- });
31
- }
32
-
33
- async getKeys() {
34
- let row: { jwt_secret: string };
35
- try {
36
- const rows = pgwireRows(
37
- await retriedQuery(this.pool, `SELECT current_setting('app.settings.jwt_secret') as jwt_secret`)
38
- );
39
- row = rows[0] as any;
40
- } catch (e) {
41
- if (e.message?.includes('unrecognized configuration parameter')) {
42
- throw new jose.errors.JOSEError(`Generate a new JWT secret on Supabase. Cause: ${e.message}`);
43
- } else {
44
- throw e;
45
- }
46
- }
47
- const secret = row?.jwt_secret as string | undefined;
48
- if (secret == null) {
49
- return {
50
- keys: [],
51
- errors: [new jose.errors.JWKSNoMatchingKey()]
52
- };
53
- } else {
54
- const key: jose.JWK = {
55
- kty: 'oct',
56
- alg: 'HS256',
57
- // While the secret is valid base64, the base64-encoded form is the secret value.
58
- k: Buffer.from(secret, 'utf8').toString('base64url')
59
- };
60
- const imported = await KeySpec.importKey(key, this.keyOptions);
61
- return {
62
- keys: [imported],
63
- errors: []
64
- };
65
- }
66
- }
67
- }
@@ -1,42 +0,0 @@
1
- import { PgoutputRelation } from '@powersync/service-jpgwire';
2
-
3
- export interface PgRelation {
4
- readonly relationId: number;
5
- readonly schema: string;
6
- readonly name: string;
7
- readonly replicaIdentity: ReplicationIdentity;
8
- readonly replicationColumns: ReplicationColumn[];
9
- }
10
-
11
- export type ReplicationIdentity = 'default' | 'nothing' | 'full' | 'index';
12
-
13
- export interface ReplicationColumn {
14
- readonly name: string;
15
- readonly typeOid: number;
16
- }
17
-
18
- export function getReplicaIdColumns(relation: PgoutputRelation): ReplicationColumn[] {
19
- if (relation.replicaIdentity == 'nothing') {
20
- return [];
21
- } else {
22
- return relation.columns.filter((c) => (c.flags & 0b1) != 0).map((c) => ({ name: c.name, typeOid: c.typeOid }));
23
- }
24
- }
25
- export function getRelId(source: PgoutputRelation): number {
26
- // Source types are wrong here
27
- const relId = (source as any).relationOid as number;
28
- if (relId == null || typeof relId != 'number') {
29
- throw new Error(`No relation id!`);
30
- }
31
- return relId;
32
- }
33
-
34
- export function getPgOutputRelation(source: PgoutputRelation): PgRelation {
35
- return {
36
- name: source.name,
37
- schema: source.schema,
38
- relationId: getRelId(source),
39
- replicaIdentity: source.replicaIdentity,
40
- replicationColumns: getReplicaIdColumns(source)
41
- };
42
- }
@@ -1,227 +0,0 @@
1
- import * as pgwire from '@powersync/service-jpgwire';
2
- import { pgwireRows } from '@powersync/service-jpgwire';
3
- import { DEFAULT_TAG, SqlSyncRules, TablePattern } from '@powersync/service-sync-rules';
4
- import { ReplicationError, TableInfo } from '@powersync/service-types';
5
-
6
- import * as storage from '../storage/storage-index.js';
7
- import * as util from '../util/util-index.js';
8
-
9
- import { ReplicaIdentityResult, getReplicationIdentityColumns } from './util.js';
10
- /**
11
- * Connection that _manages_ WAL, but does not do streaming.
12
- */
13
- export class WalConnection {
14
- db: pgwire.PgClient;
15
- connectionTag = DEFAULT_TAG;
16
- publication_name = 'powersync';
17
-
18
- sync_rules: SqlSyncRules;
19
-
20
- /**
21
- * db can be a PgConnection or PgPool.
22
- *
23
- * No transactions are used here, but it is up to the client to ensure
24
- * nothing here is called in the middle of another transaction if
25
- * PgConnection is used.
26
- */
27
- constructor(options: { db: pgwire.PgClient; sync_rules: SqlSyncRules }) {
28
- this.db = options.db;
29
- this.sync_rules = options.sync_rules;
30
- }
31
-
32
- async checkSourceConfiguration() {
33
- await checkSourceConfiguration(this.db);
34
- }
35
-
36
- async getDebugTableInfo(tablePattern: TablePattern, name: string, relationId: number | null): Promise<TableInfo> {
37
- const schema = tablePattern.schema;
38
- let id_columns_result: ReplicaIdentityResult | undefined = undefined;
39
- let id_columns_error = null;
40
-
41
- if (relationId != null) {
42
- try {
43
- id_columns_result = await getReplicationIdentityColumns(this.db, relationId);
44
- } catch (e) {
45
- id_columns_error = { level: 'fatal', message: e.message };
46
- }
47
- }
48
-
49
- const id_columns = id_columns_result?.columns ?? [];
50
-
51
- const sourceTable = new storage.SourceTable(0, this.connectionTag, relationId ?? 0, schema, name, id_columns, true);
52
-
53
- const syncData = this.sync_rules.tableSyncsData(sourceTable);
54
- const syncParameters = this.sync_rules.tableSyncsParameters(sourceTable);
55
-
56
- if (relationId == null) {
57
- return {
58
- schema: schema,
59
- name: name,
60
- pattern: tablePattern.isWildcard ? tablePattern.tablePattern : undefined,
61
- replication_id: [],
62
- data_queries: syncData,
63
- parameter_queries: syncParameters,
64
- // Also
65
- errors: [{ level: 'warning', message: `Table ${sourceTable.qualifiedName} not found.` }]
66
- };
67
- }
68
- if (id_columns.length == 0 && id_columns_error == null) {
69
- let message = `No replication id found for ${sourceTable.qualifiedName}. Replica identity: ${id_columns_result?.replicationIdentity}.`;
70
- if (id_columns_result?.replicationIdentity == 'default') {
71
- message += ' Configure a primary key on the table.';
72
- }
73
- id_columns_error = { level: 'fatal', message };
74
- }
75
-
76
- let selectError = null;
77
- try {
78
- await util.retriedQuery(this.db, `SELECT * FROM ${sourceTable.escapedIdentifier} LIMIT 1`);
79
- } catch (e) {
80
- selectError = { level: 'fatal', message: e.message };
81
- }
82
-
83
- let replicateError = null;
84
-
85
- const publications = await util.retriedQuery(this.db, {
86
- statement: `SELECT tablename FROM pg_publication_tables WHERE pubname = $1 AND schemaname = $2 AND tablename = $3`,
87
- params: [
88
- { type: 'varchar', value: this.publication_name },
89
- { type: 'varchar', value: tablePattern.schema },
90
- { type: 'varchar', value: name }
91
- ]
92
- });
93
- if (publications.rows.length == 0) {
94
- replicateError = {
95
- level: 'fatal',
96
- message: `Table ${sourceTable.qualifiedName} is not part of publication '${this.publication_name}'. Run: \`ALTER PUBLICATION ${this.publication_name} ADD TABLE ${sourceTable.qualifiedName}\`.`
97
- };
98
- }
99
-
100
- return {
101
- schema: schema,
102
- name: name,
103
- pattern: tablePattern.isWildcard ? tablePattern.tablePattern : undefined,
104
- replication_id: id_columns.map((c) => c.name),
105
- data_queries: syncData,
106
- parameter_queries: syncParameters,
107
- errors: [id_columns_error, selectError, replicateError].filter((error) => error != null) as ReplicationError[]
108
- };
109
- }
110
-
111
- async getDebugTablesInfo(tablePatterns: TablePattern[]): Promise<PatternResult[]> {
112
- let result: PatternResult[] = [];
113
-
114
- for (let tablePattern of tablePatterns) {
115
- const schema = tablePattern.schema;
116
-
117
- let patternResult: PatternResult = {
118
- schema: schema,
119
- pattern: tablePattern.tablePattern,
120
- wildcard: tablePattern.isWildcard
121
- };
122
- result.push(patternResult);
123
-
124
- if (tablePattern.isWildcard) {
125
- patternResult.tables = [];
126
- const prefix = tablePattern.tablePrefix;
127
- const results = await util.retriedQuery(this.db, {
128
- statement: `SELECT c.oid AS relid, c.relname AS table_name
129
- FROM pg_class c
130
- JOIN pg_namespace n ON n.oid = c.relnamespace
131
- WHERE n.nspname = $1
132
- AND c.relkind = 'r'
133
- AND c.relname LIKE $2`,
134
- params: [
135
- { type: 'varchar', value: schema },
136
- { type: 'varchar', value: tablePattern.tablePattern }
137
- ]
138
- });
139
-
140
- for (let row of pgwireRows(results)) {
141
- const name = row.table_name as string;
142
- const relationId = row.relid as number;
143
- if (!name.startsWith(prefix)) {
144
- continue;
145
- }
146
- const details = await this.getDebugTableInfo(tablePattern, name, relationId);
147
- patternResult.tables.push(details);
148
- }
149
- } else {
150
- const results = await util.retriedQuery(this.db, {
151
- statement: `SELECT c.oid AS relid, c.relname AS table_name
152
- FROM pg_class c
153
- JOIN pg_namespace n ON n.oid = c.relnamespace
154
- WHERE n.nspname = $1
155
- AND c.relkind = 'r'
156
- AND c.relname = $2`,
157
- params: [
158
- { type: 'varchar', value: schema },
159
- { type: 'varchar', value: tablePattern.tablePattern }
160
- ]
161
- });
162
- if (results.rows.length == 0) {
163
- // Table not found
164
- const details = await this.getDebugTableInfo(tablePattern, tablePattern.name, null);
165
- patternResult.table = details;
166
- } else {
167
- const row = pgwireRows(results)[0];
168
- const name = row.table_name as string;
169
- const relationId = row.relid as number;
170
- patternResult.table = await this.getDebugTableInfo(tablePattern, name, relationId);
171
- }
172
- }
173
- }
174
- return result;
175
- }
176
- }
177
-
178
- export interface PatternResult {
179
- schema: string;
180
- pattern: string;
181
- wildcard: boolean;
182
- tables?: TableInfo[];
183
- table?: TableInfo;
184
- }
185
-
186
- export async function checkSourceConfiguration(db: pgwire.PgClient) {
187
- // TODO: configurable
188
- const publication_name = 'powersync';
189
-
190
- // Check basic config
191
- await util.retriedQuery(
192
- db,
193
- `DO $$
194
- BEGIN
195
- if current_setting('wal_level') is distinct from 'logical' then
196
- raise exception 'wal_level must be set to ''logical'', your database has it set to ''%''. Please edit your config file and restart PostgreSQL.', current_setting('wal_level');
197
- end if;
198
- if (current_setting('max_replication_slots')::int >= 1) is not true then
199
- raise exception 'Your max_replication_slots setting is too low, it must be greater than 1. Please edit your config file and restart PostgreSQL.';
200
- end if;
201
- if (current_setting('max_wal_senders')::int >= 1) is not true then
202
- raise exception 'Your max_wal_senders setting is too low, it must be greater than 1. Please edit your config file and restart PostgreSQL.';
203
- end if;
204
- end;
205
- $$ LANGUAGE plpgsql;`
206
- );
207
-
208
- // Check that publication exists
209
- const rs = await util.retriedQuery(db, {
210
- statement: `SELECT * FROM pg_publication WHERE pubname = $1`,
211
- params: [{ type: 'varchar', value: publication_name }]
212
- });
213
- const row = pgwireRows(rs)[0];
214
- if (row == null) {
215
- throw new Error(
216
- `Publication '${publication_name}' does not exist. Run: \`CREATE PUBLICATION ${publication_name} FOR ALL TABLES\`, or read the documentation for details.`
217
- );
218
- }
219
- if (row.pubinsert == false || row.pubupdate == false || row.pubdelete == false || row.pubtruncate == false) {
220
- throw new Error(
221
- `Publication '${publication_name}' does not publish all changes. Create a publication using \`WITH (publish = "insert, update, delete, truncate")\` (the default).`
222
- );
223
- }
224
- if (row.pubviaroot) {
225
- throw new Error(`'${publication_name}' uses publish_via_partition_root, which is not supported.`);
226
- }
227
- }