@powersync/service-core 0.0.0-dev-20240620165206

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 (454) hide show
  1. package/.probes/.gitkeep +0 -0
  2. package/CHANGELOG.md +82 -0
  3. package/LICENSE +67 -0
  4. package/README.md +3 -0
  5. package/dist/api/api-index.d.ts +2 -0
  6. package/dist/api/api-index.js +3 -0
  7. package/dist/api/api-index.js.map +1 -0
  8. package/dist/api/diagnostics.d.ts +21 -0
  9. package/dist/api/diagnostics.js +183 -0
  10. package/dist/api/diagnostics.js.map +1 -0
  11. package/dist/api/schema.d.ts +5 -0
  12. package/dist/api/schema.js +88 -0
  13. package/dist/api/schema.js.map +1 -0
  14. package/dist/auth/CachedKeyCollector.d.ts +46 -0
  15. package/dist/auth/CachedKeyCollector.js +116 -0
  16. package/dist/auth/CachedKeyCollector.js.map +1 -0
  17. package/dist/auth/CompoundKeyCollector.d.ts +8 -0
  18. package/dist/auth/CompoundKeyCollector.js +23 -0
  19. package/dist/auth/CompoundKeyCollector.js.map +1 -0
  20. package/dist/auth/JwtPayload.d.ts +10 -0
  21. package/dist/auth/JwtPayload.js +2 -0
  22. package/dist/auth/JwtPayload.js.map +1 -0
  23. package/dist/auth/KeyCollector.d.ts +24 -0
  24. package/dist/auth/KeyCollector.js +2 -0
  25. package/dist/auth/KeyCollector.js.map +1 -0
  26. package/dist/auth/KeySpec.d.ts +26 -0
  27. package/dist/auth/KeySpec.js +49 -0
  28. package/dist/auth/KeySpec.js.map +1 -0
  29. package/dist/auth/KeyStore.d.ts +39 -0
  30. package/dist/auth/KeyStore.js +131 -0
  31. package/dist/auth/KeyStore.js.map +1 -0
  32. package/dist/auth/LeakyBucket.d.ts +39 -0
  33. package/dist/auth/LeakyBucket.js +57 -0
  34. package/dist/auth/LeakyBucket.js.map +1 -0
  35. package/dist/auth/RemoteJWKSCollector.d.ts +24 -0
  36. package/dist/auth/RemoteJWKSCollector.js +106 -0
  37. package/dist/auth/RemoteJWKSCollector.js.map +1 -0
  38. package/dist/auth/StaticKeyCollector.d.ts +14 -0
  39. package/dist/auth/StaticKeyCollector.js +19 -0
  40. package/dist/auth/StaticKeyCollector.js.map +1 -0
  41. package/dist/auth/SupabaseKeyCollector.d.ts +22 -0
  42. package/dist/auth/SupabaseKeyCollector.js +61 -0
  43. package/dist/auth/SupabaseKeyCollector.js.map +1 -0
  44. package/dist/auth/auth-index.d.ts +10 -0
  45. package/dist/auth/auth-index.js +11 -0
  46. package/dist/auth/auth-index.js.map +1 -0
  47. package/dist/db/db-index.d.ts +1 -0
  48. package/dist/db/db-index.js +2 -0
  49. package/dist/db/db-index.js.map +1 -0
  50. package/dist/db/mongo.d.ts +29 -0
  51. package/dist/db/mongo.js +65 -0
  52. package/dist/db/mongo.js.map +1 -0
  53. package/dist/entry/cli-entry.d.ts +15 -0
  54. package/dist/entry/cli-entry.js +36 -0
  55. package/dist/entry/cli-entry.js.map +1 -0
  56. package/dist/entry/commands/config-command.d.ts +10 -0
  57. package/dist/entry/commands/config-command.js +21 -0
  58. package/dist/entry/commands/config-command.js.map +1 -0
  59. package/dist/entry/commands/migrate-action.d.ts +2 -0
  60. package/dist/entry/commands/migrate-action.js +18 -0
  61. package/dist/entry/commands/migrate-action.js.map +1 -0
  62. package/dist/entry/commands/start-action.d.ts +3 -0
  63. package/dist/entry/commands/start-action.js +15 -0
  64. package/dist/entry/commands/start-action.js.map +1 -0
  65. package/dist/entry/commands/teardown-action.d.ts +2 -0
  66. package/dist/entry/commands/teardown-action.js +17 -0
  67. package/dist/entry/commands/teardown-action.js.map +1 -0
  68. package/dist/entry/entry-index.d.ts +5 -0
  69. package/dist/entry/entry-index.js +6 -0
  70. package/dist/entry/entry-index.js.map +1 -0
  71. package/dist/index.d.ts +25 -0
  72. package/dist/index.js +28 -0
  73. package/dist/index.js.map +1 -0
  74. package/dist/locks/LockManager.d.ts +10 -0
  75. package/dist/locks/LockManager.js +7 -0
  76. package/dist/locks/LockManager.js.map +1 -0
  77. package/dist/locks/MongoLocks.d.ts +36 -0
  78. package/dist/locks/MongoLocks.js +81 -0
  79. package/dist/locks/MongoLocks.js.map +1 -0
  80. package/dist/locks/locks-index.d.ts +2 -0
  81. package/dist/locks/locks-index.js +3 -0
  82. package/dist/locks/locks-index.js.map +1 -0
  83. package/dist/metrics/Metrics.d.ts +30 -0
  84. package/dist/metrics/Metrics.js +176 -0
  85. package/dist/metrics/Metrics.js.map +1 -0
  86. package/dist/migrations/db/migrations/1684951997326-init.d.ts +3 -0
  87. package/dist/migrations/db/migrations/1684951997326-init.js +31 -0
  88. package/dist/migrations/db/migrations/1684951997326-init.js.map +1 -0
  89. package/dist/migrations/db/migrations/1688556755264-initial-sync-rules.d.ts +2 -0
  90. package/dist/migrations/db/migrations/1688556755264-initial-sync-rules.js +5 -0
  91. package/dist/migrations/db/migrations/1688556755264-initial-sync-rules.js.map +1 -0
  92. package/dist/migrations/db/migrations/1702295701188-sync-rule-state.d.ts +3 -0
  93. package/dist/migrations/db/migrations/1702295701188-sync-rule-state.js +54 -0
  94. package/dist/migrations/db/migrations/1702295701188-sync-rule-state.js.map +1 -0
  95. package/dist/migrations/db/migrations/1711543888062-write-checkpoint-index.d.ts +3 -0
  96. package/dist/migrations/db/migrations/1711543888062-write-checkpoint-index.js +27 -0
  97. package/dist/migrations/db/migrations/1711543888062-write-checkpoint-index.js.map +1 -0
  98. package/dist/migrations/definitions.d.ts +18 -0
  99. package/dist/migrations/definitions.js +6 -0
  100. package/dist/migrations/definitions.js.map +1 -0
  101. package/dist/migrations/executor.d.ts +16 -0
  102. package/dist/migrations/executor.js +64 -0
  103. package/dist/migrations/executor.js.map +1 -0
  104. package/dist/migrations/migrations-index.d.ts +3 -0
  105. package/dist/migrations/migrations-index.js +4 -0
  106. package/dist/migrations/migrations-index.js.map +1 -0
  107. package/dist/migrations/migrations.d.ts +10 -0
  108. package/dist/migrations/migrations.js +90 -0
  109. package/dist/migrations/migrations.js.map +1 -0
  110. package/dist/migrations/store/migration-store.d.ts +11 -0
  111. package/dist/migrations/store/migration-store.js +46 -0
  112. package/dist/migrations/store/migration-store.js.map +1 -0
  113. package/dist/replication/ErrorRateLimiter.d.ts +17 -0
  114. package/dist/replication/ErrorRateLimiter.js +43 -0
  115. package/dist/replication/ErrorRateLimiter.js.map +1 -0
  116. package/dist/replication/PgRelation.d.ts +16 -0
  117. package/dist/replication/PgRelation.js +26 -0
  118. package/dist/replication/PgRelation.js.map +1 -0
  119. package/dist/replication/WalConnection.d.ts +34 -0
  120. package/dist/replication/WalConnection.js +190 -0
  121. package/dist/replication/WalConnection.js.map +1 -0
  122. package/dist/replication/WalStream.d.ts +57 -0
  123. package/dist/replication/WalStream.js +515 -0
  124. package/dist/replication/WalStream.js.map +1 -0
  125. package/dist/replication/WalStreamManager.d.ts +30 -0
  126. package/dist/replication/WalStreamManager.js +198 -0
  127. package/dist/replication/WalStreamManager.js.map +1 -0
  128. package/dist/replication/WalStreamRunner.d.ts +38 -0
  129. package/dist/replication/WalStreamRunner.js +155 -0
  130. package/dist/replication/WalStreamRunner.js.map +1 -0
  131. package/dist/replication/replication-index.d.ts +7 -0
  132. package/dist/replication/replication-index.js +8 -0
  133. package/dist/replication/replication-index.js.map +1 -0
  134. package/dist/replication/util.d.ts +9 -0
  135. package/dist/replication/util.js +62 -0
  136. package/dist/replication/util.js.map +1 -0
  137. package/dist/routes/auth.d.ts +56 -0
  138. package/dist/routes/auth.js +182 -0
  139. package/dist/routes/auth.js.map +1 -0
  140. package/dist/routes/endpoints/admin.d.ts +1011 -0
  141. package/dist/routes/endpoints/admin.js +207 -0
  142. package/dist/routes/endpoints/admin.js.map +1 -0
  143. package/dist/routes/endpoints/checkpointing.d.ts +76 -0
  144. package/dist/routes/endpoints/checkpointing.js +36 -0
  145. package/dist/routes/endpoints/checkpointing.js.map +1 -0
  146. package/dist/routes/endpoints/dev.d.ts +312 -0
  147. package/dist/routes/endpoints/dev.js +172 -0
  148. package/dist/routes/endpoints/dev.js.map +1 -0
  149. package/dist/routes/endpoints/route-endpoints-index.d.ts +6 -0
  150. package/dist/routes/endpoints/route-endpoints-index.js +7 -0
  151. package/dist/routes/endpoints/route-endpoints-index.js.map +1 -0
  152. package/dist/routes/endpoints/socket-route.d.ts +2 -0
  153. package/dist/routes/endpoints/socket-route.js +119 -0
  154. package/dist/routes/endpoints/socket-route.js.map +1 -0
  155. package/dist/routes/endpoints/sync-rules.d.ts +174 -0
  156. package/dist/routes/endpoints/sync-rules.js +202 -0
  157. package/dist/routes/endpoints/sync-rules.js.map +1 -0
  158. package/dist/routes/endpoints/sync-stream.d.ts +132 -0
  159. package/dist/routes/endpoints/sync-stream.js +83 -0
  160. package/dist/routes/endpoints/sync-stream.js.map +1 -0
  161. package/dist/routes/hooks.d.ts +10 -0
  162. package/dist/routes/hooks.js +32 -0
  163. package/dist/routes/hooks.js.map +1 -0
  164. package/dist/routes/route-register.d.ts +10 -0
  165. package/dist/routes/route-register.js +87 -0
  166. package/dist/routes/route-register.js.map +1 -0
  167. package/dist/routes/router-socket.d.ts +10 -0
  168. package/dist/routes/router-socket.js +5 -0
  169. package/dist/routes/router-socket.js.map +1 -0
  170. package/dist/routes/router.d.ts +26 -0
  171. package/dist/routes/router.js +7 -0
  172. package/dist/routes/router.js.map +1 -0
  173. package/dist/routes/routes-index.d.ts +6 -0
  174. package/dist/routes/routes-index.js +7 -0
  175. package/dist/routes/routes-index.js.map +1 -0
  176. package/dist/runner/teardown.d.ts +2 -0
  177. package/dist/runner/teardown.js +94 -0
  178. package/dist/runner/teardown.js.map +1 -0
  179. package/dist/storage/BucketStorage.d.ts +307 -0
  180. package/dist/storage/BucketStorage.js +25 -0
  181. package/dist/storage/BucketStorage.js.map +1 -0
  182. package/dist/storage/ChecksumCache.d.ts +50 -0
  183. package/dist/storage/ChecksumCache.js +234 -0
  184. package/dist/storage/ChecksumCache.js.map +1 -0
  185. package/dist/storage/MongoBucketStorage.d.ts +52 -0
  186. package/dist/storage/MongoBucketStorage.js +409 -0
  187. package/dist/storage/MongoBucketStorage.js.map +1 -0
  188. package/dist/storage/SourceTable.d.ts +39 -0
  189. package/dist/storage/SourceTable.js +50 -0
  190. package/dist/storage/SourceTable.js.map +1 -0
  191. package/dist/storage/mongo/MongoBucketBatch.d.ts +48 -0
  192. package/dist/storage/mongo/MongoBucketBatch.js +581 -0
  193. package/dist/storage/mongo/MongoBucketBatch.js.map +1 -0
  194. package/dist/storage/mongo/MongoIdSequence.d.ts +12 -0
  195. package/dist/storage/mongo/MongoIdSequence.js +21 -0
  196. package/dist/storage/mongo/MongoIdSequence.js.map +1 -0
  197. package/dist/storage/mongo/MongoPersistedSyncRules.d.ts +9 -0
  198. package/dist/storage/mongo/MongoPersistedSyncRules.js +9 -0
  199. package/dist/storage/mongo/MongoPersistedSyncRules.js.map +1 -0
  200. package/dist/storage/mongo/MongoPersistedSyncRulesContent.d.ts +20 -0
  201. package/dist/storage/mongo/MongoPersistedSyncRulesContent.js +26 -0
  202. package/dist/storage/mongo/MongoPersistedSyncRulesContent.js.map +1 -0
  203. package/dist/storage/mongo/MongoSyncBucketStorage.d.ts +29 -0
  204. package/dist/storage/mongo/MongoSyncBucketStorage.js +391 -0
  205. package/dist/storage/mongo/MongoSyncBucketStorage.js.map +1 -0
  206. package/dist/storage/mongo/MongoSyncRulesLock.d.ts +16 -0
  207. package/dist/storage/mongo/MongoSyncRulesLock.js +65 -0
  208. package/dist/storage/mongo/MongoSyncRulesLock.js.map +1 -0
  209. package/dist/storage/mongo/OperationBatch.d.ts +26 -0
  210. package/dist/storage/mongo/OperationBatch.js +101 -0
  211. package/dist/storage/mongo/OperationBatch.js.map +1 -0
  212. package/dist/storage/mongo/PersistedBatch.d.ts +46 -0
  213. package/dist/storage/mongo/PersistedBatch.js +213 -0
  214. package/dist/storage/mongo/PersistedBatch.js.map +1 -0
  215. package/dist/storage/mongo/db.d.ts +26 -0
  216. package/dist/storage/mongo/db.js +35 -0
  217. package/dist/storage/mongo/db.js.map +1 -0
  218. package/dist/storage/mongo/models.d.ts +140 -0
  219. package/dist/storage/mongo/models.js +27 -0
  220. package/dist/storage/mongo/models.js.map +1 -0
  221. package/dist/storage/mongo/util.d.ts +26 -0
  222. package/dist/storage/mongo/util.js +81 -0
  223. package/dist/storage/mongo/util.js.map +1 -0
  224. package/dist/storage/storage-index.d.ts +14 -0
  225. package/dist/storage/storage-index.js +15 -0
  226. package/dist/storage/storage-index.js.map +1 -0
  227. package/dist/sync/BroadcastIterable.d.ts +38 -0
  228. package/dist/sync/BroadcastIterable.js +153 -0
  229. package/dist/sync/BroadcastIterable.js.map +1 -0
  230. package/dist/sync/LastValueSink.d.ts +25 -0
  231. package/dist/sync/LastValueSink.js +84 -0
  232. package/dist/sync/LastValueSink.js.map +1 -0
  233. package/dist/sync/merge.d.ts +39 -0
  234. package/dist/sync/merge.js +175 -0
  235. package/dist/sync/merge.js.map +1 -0
  236. package/dist/sync/safeRace.d.ts +1 -0
  237. package/dist/sync/safeRace.js +91 -0
  238. package/dist/sync/safeRace.js.map +1 -0
  239. package/dist/sync/sync-index.d.ts +6 -0
  240. package/dist/sync/sync-index.js +7 -0
  241. package/dist/sync/sync-index.js.map +1 -0
  242. package/dist/sync/sync.d.ts +18 -0
  243. package/dist/sync/sync.js +259 -0
  244. package/dist/sync/sync.js.map +1 -0
  245. package/dist/sync/util.d.ts +26 -0
  246. package/dist/sync/util.js +73 -0
  247. package/dist/sync/util.js.map +1 -0
  248. package/dist/system/CorePowerSyncSystem.d.ts +23 -0
  249. package/dist/system/CorePowerSyncSystem.js +52 -0
  250. package/dist/system/CorePowerSyncSystem.js.map +1 -0
  251. package/dist/system/system-index.d.ts +1 -0
  252. package/dist/system/system-index.js +2 -0
  253. package/dist/system/system-index.js.map +1 -0
  254. package/dist/util/Mutex.d.ts +47 -0
  255. package/dist/util/Mutex.js +132 -0
  256. package/dist/util/Mutex.js.map +1 -0
  257. package/dist/util/PgManager.d.ts +24 -0
  258. package/dist/util/PgManager.js +55 -0
  259. package/dist/util/PgManager.js.map +1 -0
  260. package/dist/util/alerting.d.ts +2 -0
  261. package/dist/util/alerting.js +8 -0
  262. package/dist/util/alerting.js.map +1 -0
  263. package/dist/util/config/collectors/config-collector.d.ts +29 -0
  264. package/dist/util/config/collectors/config-collector.js +116 -0
  265. package/dist/util/config/collectors/config-collector.js.map +1 -0
  266. package/dist/util/config/collectors/impl/base64-config-collector.d.ts +6 -0
  267. package/dist/util/config/collectors/impl/base64-config-collector.js +15 -0
  268. package/dist/util/config/collectors/impl/base64-config-collector.js.map +1 -0
  269. package/dist/util/config/collectors/impl/fallback-config-collector.d.ts +11 -0
  270. package/dist/util/config/collectors/impl/fallback-config-collector.js +19 -0
  271. package/dist/util/config/collectors/impl/fallback-config-collector.js.map +1 -0
  272. package/dist/util/config/collectors/impl/filesystem-config-collector.d.ts +6 -0
  273. package/dist/util/config/collectors/impl/filesystem-config-collector.js +37 -0
  274. package/dist/util/config/collectors/impl/filesystem-config-collector.js.map +1 -0
  275. package/dist/util/config/compound-config-collector.d.ts +32 -0
  276. package/dist/util/config/compound-config-collector.js +130 -0
  277. package/dist/util/config/compound-config-collector.js.map +1 -0
  278. package/dist/util/config/sync-rules/impl/base64-sync-rules-collector.d.ts +7 -0
  279. package/dist/util/config/sync-rules/impl/base64-sync-rules-collector.js +17 -0
  280. package/dist/util/config/sync-rules/impl/base64-sync-rules-collector.js.map +1 -0
  281. package/dist/util/config/sync-rules/impl/filesystem-sync-rules-collector.d.ts +7 -0
  282. package/dist/util/config/sync-rules/impl/filesystem-sync-rules-collector.js +21 -0
  283. package/dist/util/config/sync-rules/impl/filesystem-sync-rules-collector.js.map +1 -0
  284. package/dist/util/config/sync-rules/impl/inline-sync-rules-collector.d.ts +7 -0
  285. package/dist/util/config/sync-rules/impl/inline-sync-rules-collector.js +17 -0
  286. package/dist/util/config/sync-rules/impl/inline-sync-rules-collector.js.map +1 -0
  287. package/dist/util/config/sync-rules/sync-collector.d.ts +6 -0
  288. package/dist/util/config/sync-rules/sync-collector.js +3 -0
  289. package/dist/util/config/sync-rules/sync-collector.js.map +1 -0
  290. package/dist/util/config/types.d.ts +57 -0
  291. package/dist/util/config/types.js +7 -0
  292. package/dist/util/config/types.js.map +1 -0
  293. package/dist/util/config.d.ts +7 -0
  294. package/dist/util/config.js +35 -0
  295. package/dist/util/config.js.map +1 -0
  296. package/dist/util/env.d.ts +9 -0
  297. package/dist/util/env.js +26 -0
  298. package/dist/util/env.js.map +1 -0
  299. package/dist/util/memory-tracking.d.ts +7 -0
  300. package/dist/util/memory-tracking.js +58 -0
  301. package/dist/util/memory-tracking.js.map +1 -0
  302. package/dist/util/migration_lib.d.ts +11 -0
  303. package/dist/util/migration_lib.js +64 -0
  304. package/dist/util/migration_lib.js.map +1 -0
  305. package/dist/util/pgwire_utils.d.ts +24 -0
  306. package/dist/util/pgwire_utils.js +117 -0
  307. package/dist/util/pgwire_utils.js.map +1 -0
  308. package/dist/util/populate_test_data.d.ts +8 -0
  309. package/dist/util/populate_test_data.js +65 -0
  310. package/dist/util/populate_test_data.js.map +1 -0
  311. package/dist/util/protocol-types.d.ts +182 -0
  312. package/dist/util/protocol-types.js +42 -0
  313. package/dist/util/protocol-types.js.map +1 -0
  314. package/dist/util/secs.d.ts +2 -0
  315. package/dist/util/secs.js +49 -0
  316. package/dist/util/secs.js.map +1 -0
  317. package/dist/util/util-index.d.ts +22 -0
  318. package/dist/util/util-index.js +23 -0
  319. package/dist/util/util-index.js.map +1 -0
  320. package/dist/util/utils.d.ts +17 -0
  321. package/dist/util/utils.js +92 -0
  322. package/dist/util/utils.js.map +1 -0
  323. package/package.json +59 -0
  324. package/src/api/api-index.ts +2 -0
  325. package/src/api/diagnostics.ts +221 -0
  326. package/src/api/schema.ts +99 -0
  327. package/src/auth/CachedKeyCollector.ts +132 -0
  328. package/src/auth/CompoundKeyCollector.ts +33 -0
  329. package/src/auth/JwtPayload.ts +11 -0
  330. package/src/auth/KeyCollector.ts +27 -0
  331. package/src/auth/KeySpec.ts +67 -0
  332. package/src/auth/KeyStore.ts +156 -0
  333. package/src/auth/LeakyBucket.ts +66 -0
  334. package/src/auth/RemoteJWKSCollector.ts +130 -0
  335. package/src/auth/StaticKeyCollector.ts +21 -0
  336. package/src/auth/SupabaseKeyCollector.ts +67 -0
  337. package/src/auth/auth-index.ts +10 -0
  338. package/src/db/db-index.ts +1 -0
  339. package/src/db/mongo.ts +72 -0
  340. package/src/entry/cli-entry.ts +40 -0
  341. package/src/entry/commands/config-command.ts +36 -0
  342. package/src/entry/commands/migrate-action.ts +25 -0
  343. package/src/entry/commands/start-action.ts +24 -0
  344. package/src/entry/commands/teardown-action.ts +23 -0
  345. package/src/entry/entry-index.ts +5 -0
  346. package/src/index.ts +40 -0
  347. package/src/locks/LockManager.ts +16 -0
  348. package/src/locks/MongoLocks.ts +142 -0
  349. package/src/locks/locks-index.ts +2 -0
  350. package/src/metrics/Metrics.ts +265 -0
  351. package/src/migrations/db/migrations/1684951997326-init.ts +33 -0
  352. package/src/migrations/db/migrations/1688556755264-initial-sync-rules.ts +5 -0
  353. package/src/migrations/db/migrations/1702295701188-sync-rule-state.ts +99 -0
  354. package/src/migrations/db/migrations/1711543888062-write-checkpoint-index.ts +32 -0
  355. package/src/migrations/definitions.ts +21 -0
  356. package/src/migrations/executor.ts +87 -0
  357. package/src/migrations/migrations-index.ts +3 -0
  358. package/src/migrations/migrations.ts +118 -0
  359. package/src/migrations/store/migration-store.ts +63 -0
  360. package/src/replication/ErrorRateLimiter.ts +50 -0
  361. package/src/replication/PgRelation.ts +42 -0
  362. package/src/replication/WalConnection.ts +227 -0
  363. package/src/replication/WalStream.ts +624 -0
  364. package/src/replication/WalStreamManager.ts +213 -0
  365. package/src/replication/WalStreamRunner.ts +180 -0
  366. package/src/replication/replication-index.ts +7 -0
  367. package/src/replication/util.ts +76 -0
  368. package/src/routes/auth.ts +215 -0
  369. package/src/routes/endpoints/admin.ts +237 -0
  370. package/src/routes/endpoints/checkpointing.ts +41 -0
  371. package/src/routes/endpoints/dev.ts +199 -0
  372. package/src/routes/endpoints/route-endpoints-index.ts +6 -0
  373. package/src/routes/endpoints/socket-route.ts +135 -0
  374. package/src/routes/endpoints/sync-rules.ts +227 -0
  375. package/src/routes/endpoints/sync-stream.ts +101 -0
  376. package/src/routes/hooks.ts +46 -0
  377. package/src/routes/route-register.ts +104 -0
  378. package/src/routes/router-socket.ts +13 -0
  379. package/src/routes/router.ts +46 -0
  380. package/src/routes/routes-index.ts +6 -0
  381. package/src/runner/teardown.ts +108 -0
  382. package/src/storage/BucketStorage.ts +396 -0
  383. package/src/storage/ChecksumCache.ts +294 -0
  384. package/src/storage/MongoBucketStorage.ts +519 -0
  385. package/src/storage/SourceTable.ts +60 -0
  386. package/src/storage/mongo/MongoBucketBatch.ts +752 -0
  387. package/src/storage/mongo/MongoIdSequence.ts +24 -0
  388. package/src/storage/mongo/MongoPersistedSyncRules.ts +16 -0
  389. package/src/storage/mongo/MongoPersistedSyncRulesContent.ts +47 -0
  390. package/src/storage/mongo/MongoSyncBucketStorage.ts +533 -0
  391. package/src/storage/mongo/MongoSyncRulesLock.ts +81 -0
  392. package/src/storage/mongo/OperationBatch.ts +115 -0
  393. package/src/storage/mongo/PersistedBatch.ts +268 -0
  394. package/src/storage/mongo/db.ts +73 -0
  395. package/src/storage/mongo/models.ts +162 -0
  396. package/src/storage/mongo/util.ts +88 -0
  397. package/src/storage/storage-index.ts +15 -0
  398. package/src/sync/BroadcastIterable.ts +161 -0
  399. package/src/sync/LastValueSink.ts +100 -0
  400. package/src/sync/merge.ts +200 -0
  401. package/src/sync/safeRace.ts +99 -0
  402. package/src/sync/sync-index.ts +6 -0
  403. package/src/sync/sync.ts +319 -0
  404. package/src/sync/util.ts +98 -0
  405. package/src/system/CorePowerSyncSystem.ts +64 -0
  406. package/src/system/system-index.ts +1 -0
  407. package/src/util/Mutex.ts +159 -0
  408. package/src/util/PgManager.ts +64 -0
  409. package/src/util/alerting.ts +9 -0
  410. package/src/util/config/collectors/config-collector.ts +143 -0
  411. package/src/util/config/collectors/impl/base64-config-collector.ts +18 -0
  412. package/src/util/config/collectors/impl/fallback-config-collector.ts +22 -0
  413. package/src/util/config/collectors/impl/filesystem-config-collector.ts +43 -0
  414. package/src/util/config/compound-config-collector.ts +176 -0
  415. package/src/util/config/sync-rules/impl/base64-sync-rules-collector.ts +21 -0
  416. package/src/util/config/sync-rules/impl/filesystem-sync-rules-collector.ts +26 -0
  417. package/src/util/config/sync-rules/impl/inline-sync-rules-collector.ts +21 -0
  418. package/src/util/config/sync-rules/sync-collector.ts +8 -0
  419. package/src/util/config/types.ts +66 -0
  420. package/src/util/config.ts +39 -0
  421. package/src/util/env.ts +30 -0
  422. package/src/util/memory-tracking.ts +67 -0
  423. package/src/util/migration_lib.ts +79 -0
  424. package/src/util/pgwire_utils.ts +139 -0
  425. package/src/util/populate_test_data.ts +78 -0
  426. package/src/util/protocol-types.ts +228 -0
  427. package/src/util/secs.ts +54 -0
  428. package/src/util/util-index.ts +25 -0
  429. package/src/util/utils.ts +122 -0
  430. package/test/src/__snapshots__/pg_test.test.ts.snap +256 -0
  431. package/test/src/__snapshots__/sync.test.ts.snap +247 -0
  432. package/test/src/auth.test.ts +342 -0
  433. package/test/src/broadcast_iterable.test.ts +156 -0
  434. package/test/src/checksum_cache.test.ts +436 -0
  435. package/test/src/data_storage.test.ts +1176 -0
  436. package/test/src/env.ts +8 -0
  437. package/test/src/large_batch.test.ts +194 -0
  438. package/test/src/merge_iterable.test.ts +355 -0
  439. package/test/src/pg_test.test.ts +450 -0
  440. package/test/src/schema_changes.test.ts +545 -0
  441. package/test/src/setup.ts +7 -0
  442. package/test/src/slow_tests.test.ts +257 -0
  443. package/test/src/sql_functions.test.ts +254 -0
  444. package/test/src/sql_operators.test.ts +132 -0
  445. package/test/src/sync.test.ts +293 -0
  446. package/test/src/sync_rules.test.ts +1053 -0
  447. package/test/src/util.ts +76 -0
  448. package/test/src/validation.test.ts +63 -0
  449. package/test/src/wal_stream.test.ts +319 -0
  450. package/test/src/wal_stream_utils.ts +147 -0
  451. package/test/tsconfig.json +20 -0
  452. package/tsconfig.json +31 -0
  453. package/tsconfig.tsbuildinfo +1 -0
  454. package/vitest.config.ts +9 -0
@@ -0,0 +1,87 @@
1
+ import { logger } from '@powersync/lib-services-framework';
2
+ import * as defs from './definitions.js';
3
+ import { MigrationStore } from './store/migration-store.js';
4
+
5
+ type ExecuteParams = {
6
+ migrations: defs.Migration[];
7
+ state?: defs.MigrationState;
8
+
9
+ direction: defs.Direction;
10
+ count?: number;
11
+ };
12
+
13
+ export async function* execute(params: ExecuteParams): AsyncGenerator<defs.ExecutedMigration> {
14
+ let migrations = [...params.migrations];
15
+ if (params.direction === defs.Direction.Down) {
16
+ migrations = migrations.reverse();
17
+ }
18
+
19
+ let index = 0;
20
+
21
+ if (params.state) {
22
+ // Find the index of the last run
23
+ index = migrations.findIndex((migration) => {
24
+ return migration.name === params.state!.last_run;
25
+ });
26
+
27
+ if (index === -1) {
28
+ throw new Error(`The last run migration ${params.state?.last_run} was not found in the given set of migrations`);
29
+ }
30
+
31
+ // If we are migrating down then we want to include the last run migration, otherwise we want to start at the next one
32
+ if (params.direction === defs.Direction.Up) {
33
+ index += 1;
34
+ }
35
+ }
36
+
37
+ migrations = migrations.slice(index);
38
+
39
+ let i = 0;
40
+ for (const migration of migrations) {
41
+ if (params.count && params.count === i) {
42
+ return;
43
+ }
44
+
45
+ logger.info(`Executing ${migration.name} (${params.direction})`);
46
+ try {
47
+ switch (params.direction) {
48
+ case defs.Direction.Up: {
49
+ await migration.up();
50
+ break;
51
+ }
52
+ case defs.Direction.Down: {
53
+ await migration.down();
54
+ break;
55
+ }
56
+ }
57
+ logger.debug(`Success`);
58
+ } catch (err) {
59
+ logger.error(`Failed`, err);
60
+ process.exit(1);
61
+ }
62
+
63
+ yield {
64
+ name: migration.name,
65
+ direction: params.direction,
66
+ timestamp: new Date()
67
+ };
68
+
69
+ i++;
70
+ }
71
+ }
72
+
73
+ type WriteLogsParams = {
74
+ store: MigrationStore;
75
+ state?: defs.MigrationState;
76
+ log_stream: Iterable<defs.ExecutedMigration> | AsyncIterable<defs.ExecutedMigration>;
77
+ };
78
+ export const writeLogsToStore = async (params: WriteLogsParams): Promise<void> => {
79
+ const log = [...(params.state?.log || [])];
80
+ for await (const migration of params.log_stream) {
81
+ log.push(migration);
82
+ await params.store.save({
83
+ last_run: migration.name,
84
+ log: log
85
+ });
86
+ }
87
+ };
@@ -0,0 +1,3 @@
1
+ export * from './definitions.js';
2
+ export * from './executor.js';
3
+ export * from './migrations.js';
@@ -0,0 +1,118 @@
1
+ import * as fs from 'fs/promises';
2
+ import * as path from 'path';
3
+ import { fileURLToPath } from 'url';
4
+
5
+ import * as db from '../db/db-index.js';
6
+ import * as util from '../util/util-index.js';
7
+ import * as locks from '../locks/locks-index.js';
8
+ import { Direction } from './definitions.js';
9
+ import { createMongoMigrationStore } from './store/migration-store.js';
10
+ import { execute, writeLogsToStore } from './executor.js';
11
+
12
+ const DEFAULT_MONGO_LOCK_COLLECTION = 'locks';
13
+ const MONGO_LOCK_PROCESS = 'migrations';
14
+
15
+ const __filename = fileURLToPath(import.meta.url);
16
+ const __dirname = path.dirname(__filename);
17
+
18
+ const MIGRATIONS_DIR = path.join(__dirname, '/db/migrations');
19
+
20
+ export type MigrationOptions = {
21
+ direction: Direction;
22
+ runner_config: util.RunnerConfig;
23
+ };
24
+
25
+ /**
26
+ * Loads migrations and injects a custom context for loading the specified
27
+ * runner configuration.
28
+ */
29
+ const loadMigrations = async (dir: string, runner_config: util.RunnerConfig) => {
30
+ const files = await fs.readdir(dir);
31
+ const migrations = files.filter((file) => {
32
+ return path.extname(file) === '.js';
33
+ });
34
+
35
+ const context: util.MigrationContext = {
36
+ runner_config
37
+ };
38
+
39
+ return await Promise.all(
40
+ migrations.map(async (migration) => {
41
+ const module = await import(path.resolve(dir, migration));
42
+ return {
43
+ name: path.basename(migration).replace(path.extname(migration), ''),
44
+ up: () => module.up(context),
45
+ down: () => module.down(context)
46
+ };
47
+ })
48
+ );
49
+ };
50
+
51
+ /**
52
+ * Runs migration scripts exclusively using Mongo locks
53
+ */
54
+ export const migrate = async (options: MigrationOptions) => {
55
+ const { direction, runner_config } = options;
56
+
57
+ /**
58
+ * Try and get Mongo from config file.
59
+ * But this might not be available in Journey Micro as we use the standard Mongo.
60
+ */
61
+
62
+ const config = await util.loadConfig(runner_config);
63
+ const { storage } = config;
64
+
65
+ const client = db.mongo.createMongoClient(storage);
66
+ await client.connect();
67
+
68
+ const clientDB = client.db(storage.database);
69
+ const collection = clientDB.collection<locks.Lock>(DEFAULT_MONGO_LOCK_COLLECTION);
70
+
71
+ const manager = locks.createMongoLockManager(collection, {
72
+ name: MONGO_LOCK_PROCESS
73
+ });
74
+
75
+ // Only one process should execute this at a time.
76
+ const lockId = await manager.acquire();
77
+
78
+ if (!lockId) {
79
+ throw new Error('Could not acquire lock_id');
80
+ }
81
+
82
+ let isReleased = false;
83
+ const releaseLock = async () => {
84
+ if (isReleased) {
85
+ return;
86
+ }
87
+ await manager.release(lockId);
88
+ isReleased = true;
89
+ };
90
+
91
+ // For the case where the migration is terminated
92
+ process.addListener('beforeExit', releaseLock);
93
+
94
+ try {
95
+ const migrations = await loadMigrations(MIGRATIONS_DIR, runner_config);
96
+
97
+ // Use the provided config to connect to Mongo
98
+ const store = createMongoMigrationStore(client);
99
+
100
+ const state = await store.load();
101
+
102
+ const logStream = execute({
103
+ direction: direction,
104
+ migrations,
105
+ state
106
+ });
107
+
108
+ await writeLogsToStore({
109
+ log_stream: logStream,
110
+ store,
111
+ state
112
+ });
113
+ } finally {
114
+ await releaseLock();
115
+ await client.close(true);
116
+ process.removeListener('beforeExit', releaseLock);
117
+ }
118
+ };
@@ -0,0 +1,63 @@
1
+ import Mongo from 'mongodb';
2
+ import * as path from 'path';
3
+ import * as defs from '../definitions.js';
4
+
5
+ export type MigrationStore = {
6
+ load: () => Promise<defs.MigrationState | undefined>;
7
+ save: (state: defs.MigrationState) => Promise<void>;
8
+ };
9
+
10
+ /**
11
+ * A custom store for node-migrate which is used to save and load migrations that have
12
+ * been operated on to mongo.
13
+ */
14
+ export const createMongoMigrationStore = (client: Mongo.MongoClient): MigrationStore => {
15
+ const collection = client.db().collection<defs.MigrationState>('migrations');
16
+
17
+ return {
18
+ load: async () => {
19
+ const state_entry = await collection.findOne();
20
+ if (!state_entry) {
21
+ return;
22
+ }
23
+
24
+ const { _id, ...state } = state_entry;
25
+
26
+ /**
27
+ * This is for backwards compatibility. A previous version of the migration tool used to save
28
+ * state as `lastRun`.
29
+ */
30
+ let last_run = state.last_run;
31
+ if ('lastRun' in state) {
32
+ last_run = (state as any).lastRun;
33
+ }
34
+
35
+ /**
36
+ * This is for backwards compatibility. A previous version of the migration tool used to include the
37
+ * file extension in migration names. This strips that extension off if it exists
38
+ */
39
+ const extension = path.extname(last_run);
40
+ if (extension) {
41
+ last_run = last_run.replace(extension, '');
42
+ }
43
+
44
+ return {
45
+ last_run,
46
+ log: state.log || []
47
+ };
48
+ },
49
+
50
+ save: async (state: defs.MigrationState) => {
51
+ await collection.replaceOne(
52
+ {},
53
+ {
54
+ last_run: state.last_run,
55
+ log: state.log
56
+ },
57
+ {
58
+ upsert: true
59
+ }
60
+ );
61
+ }
62
+ };
63
+ };
@@ -0,0 +1,50 @@
1
+ import { setTimeout } from 'timers/promises';
2
+
3
+ export interface ErrorRateLimiter {
4
+ waitUntilAllowed(options?: { signal?: AbortSignal }): Promise<void>;
5
+ reportError(e: any): void;
6
+
7
+ mayPing(): boolean;
8
+ }
9
+
10
+ export class DefaultErrorRateLimiter implements ErrorRateLimiter {
11
+ nextAllowed: number = Date.now();
12
+
13
+ async waitUntilAllowed(options?: { signal?: AbortSignal | undefined } | undefined): Promise<void> {
14
+ const delay = Math.max(0, this.nextAllowed - Date.now());
15
+ // Minimum delay between connections, even without errors
16
+ this.setDelay(500);
17
+ await setTimeout(delay, undefined, { signal: options?.signal });
18
+ }
19
+
20
+ mayPing(): boolean {
21
+ return Date.now() >= this.nextAllowed;
22
+ }
23
+
24
+ reportError(e: any): void {
25
+ const message = (e.message as string) ?? '';
26
+ if (message.includes('password authentication failed')) {
27
+ // Wait 15 minutes, to avoid triggering Supabase's fail2ban
28
+ this.setDelay(900_000);
29
+ } else if (message.includes('ENOTFOUND')) {
30
+ // DNS lookup issue - incorrect URI or deleted instance
31
+ this.setDelay(120_000);
32
+ } else if (message.includes('ECONNREFUSED')) {
33
+ // Could be fail2ban or similar
34
+ this.setDelay(120_000);
35
+ } else if (
36
+ message.includes('Unable to do postgres query on ended pool') ||
37
+ message.includes('Postgres unexpectedly closed connection')
38
+ ) {
39
+ // Connection timed out - ignore / immediately retry
40
+ // We don't explicitly set the delay to 0, since there could have been another error that
41
+ // we need to respect.
42
+ } else {
43
+ this.setDelay(30_000);
44
+ }
45
+ }
46
+
47
+ private setDelay(delay: number) {
48
+ this.nextAllowed = Math.max(this.nextAllowed, Date.now() + delay);
49
+ }
50
+ }
@@ -0,0 +1,42 @@
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
+ }
@@ -0,0 +1,227 @@
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
+ }