@powersync/service-core 0.0.2

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 (412) hide show
  1. package/.probes/.gitkeep +0 -0
  2. package/CHANGELOG.md +13 -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 +24 -0
  72. package/dist/index.js +26 -0
  73. package/dist/index.js.map +1 -0
  74. package/dist/metrics/metrics.d.ts +16 -0
  75. package/dist/metrics/metrics.js +139 -0
  76. package/dist/metrics/metrics.js.map +1 -0
  77. package/dist/migrations/db/migrations/1684951997326-init.d.ts +3 -0
  78. package/dist/migrations/db/migrations/1684951997326-init.js +31 -0
  79. package/dist/migrations/db/migrations/1684951997326-init.js.map +1 -0
  80. package/dist/migrations/db/migrations/1688556755264-initial-sync-rules.d.ts +2 -0
  81. package/dist/migrations/db/migrations/1688556755264-initial-sync-rules.js +5 -0
  82. package/dist/migrations/db/migrations/1688556755264-initial-sync-rules.js.map +1 -0
  83. package/dist/migrations/db/migrations/1702295701188-sync-rule-state.d.ts +3 -0
  84. package/dist/migrations/db/migrations/1702295701188-sync-rule-state.js +54 -0
  85. package/dist/migrations/db/migrations/1702295701188-sync-rule-state.js.map +1 -0
  86. package/dist/migrations/db/migrations/1711543888062-write-checkpoint-index.d.ts +3 -0
  87. package/dist/migrations/db/migrations/1711543888062-write-checkpoint-index.js +27 -0
  88. package/dist/migrations/db/migrations/1711543888062-write-checkpoint-index.js.map +1 -0
  89. package/dist/migrations/db/store.d.ts +3 -0
  90. package/dist/migrations/db/store.js +10 -0
  91. package/dist/migrations/db/store.js.map +1 -0
  92. package/dist/migrations/migrations.d.ts +10 -0
  93. package/dist/migrations/migrations.js +94 -0
  94. package/dist/migrations/migrations.js.map +1 -0
  95. package/dist/replication/ErrorRateLimiter.d.ts +17 -0
  96. package/dist/replication/ErrorRateLimiter.js +42 -0
  97. package/dist/replication/ErrorRateLimiter.js.map +1 -0
  98. package/dist/replication/PgRelation.d.ts +16 -0
  99. package/dist/replication/PgRelation.js +26 -0
  100. package/dist/replication/PgRelation.js.map +1 -0
  101. package/dist/replication/WalConnection.d.ts +34 -0
  102. package/dist/replication/WalConnection.js +190 -0
  103. package/dist/replication/WalConnection.js.map +1 -0
  104. package/dist/replication/WalStream.d.ts +58 -0
  105. package/dist/replication/WalStream.js +517 -0
  106. package/dist/replication/WalStream.js.map +1 -0
  107. package/dist/replication/WalStreamManager.d.ts +30 -0
  108. package/dist/replication/WalStreamManager.js +199 -0
  109. package/dist/replication/WalStreamManager.js.map +1 -0
  110. package/dist/replication/WalStreamRunner.d.ts +38 -0
  111. package/dist/replication/WalStreamRunner.js +155 -0
  112. package/dist/replication/WalStreamRunner.js.map +1 -0
  113. package/dist/replication/replication-index.d.ts +7 -0
  114. package/dist/replication/replication-index.js +8 -0
  115. package/dist/replication/replication-index.js.map +1 -0
  116. package/dist/replication/util.d.ts +9 -0
  117. package/dist/replication/util.js +62 -0
  118. package/dist/replication/util.js.map +1 -0
  119. package/dist/routes/admin.d.ts +7 -0
  120. package/dist/routes/admin.js +192 -0
  121. package/dist/routes/admin.js.map +1 -0
  122. package/dist/routes/auth.d.ts +58 -0
  123. package/dist/routes/auth.js +182 -0
  124. package/dist/routes/auth.js.map +1 -0
  125. package/dist/routes/checkpointing.d.ts +3 -0
  126. package/dist/routes/checkpointing.js +30 -0
  127. package/dist/routes/checkpointing.js.map +1 -0
  128. package/dist/routes/dev.d.ts +6 -0
  129. package/dist/routes/dev.js +163 -0
  130. package/dist/routes/dev.js.map +1 -0
  131. package/dist/routes/route-generators.d.ts +15 -0
  132. package/dist/routes/route-generators.js +32 -0
  133. package/dist/routes/route-generators.js.map +1 -0
  134. package/dist/routes/router-socket.d.ts +10 -0
  135. package/dist/routes/router-socket.js +5 -0
  136. package/dist/routes/router-socket.js.map +1 -0
  137. package/dist/routes/router.d.ts +13 -0
  138. package/dist/routes/router.js +2 -0
  139. package/dist/routes/router.js.map +1 -0
  140. package/dist/routes/routes-index.d.ts +4 -0
  141. package/dist/routes/routes-index.js +5 -0
  142. package/dist/routes/routes-index.js.map +1 -0
  143. package/dist/routes/socket-route.d.ts +2 -0
  144. package/dist/routes/socket-route.js +119 -0
  145. package/dist/routes/socket-route.js.map +1 -0
  146. package/dist/routes/sync-rules.d.ts +6 -0
  147. package/dist/routes/sync-rules.js +182 -0
  148. package/dist/routes/sync-rules.js.map +1 -0
  149. package/dist/routes/sync-stream.d.ts +5 -0
  150. package/dist/routes/sync-stream.js +74 -0
  151. package/dist/routes/sync-stream.js.map +1 -0
  152. package/dist/runner/teardown.d.ts +2 -0
  153. package/dist/runner/teardown.js +79 -0
  154. package/dist/runner/teardown.js.map +1 -0
  155. package/dist/storage/BucketStorage.d.ts +298 -0
  156. package/dist/storage/BucketStorage.js +25 -0
  157. package/dist/storage/BucketStorage.js.map +1 -0
  158. package/dist/storage/MongoBucketStorage.d.ts +51 -0
  159. package/dist/storage/MongoBucketStorage.js +388 -0
  160. package/dist/storage/MongoBucketStorage.js.map +1 -0
  161. package/dist/storage/SourceTable.d.ts +39 -0
  162. package/dist/storage/SourceTable.js +50 -0
  163. package/dist/storage/SourceTable.js.map +1 -0
  164. package/dist/storage/mongo/MongoBucketBatch.d.ts +48 -0
  165. package/dist/storage/mongo/MongoBucketBatch.js +584 -0
  166. package/dist/storage/mongo/MongoBucketBatch.js.map +1 -0
  167. package/dist/storage/mongo/MongoIdSequence.d.ts +12 -0
  168. package/dist/storage/mongo/MongoIdSequence.js +21 -0
  169. package/dist/storage/mongo/MongoIdSequence.js.map +1 -0
  170. package/dist/storage/mongo/MongoPersistedSyncRules.d.ts +9 -0
  171. package/dist/storage/mongo/MongoPersistedSyncRules.js +9 -0
  172. package/dist/storage/mongo/MongoPersistedSyncRules.js.map +1 -0
  173. package/dist/storage/mongo/MongoPersistedSyncRulesContent.d.ts +20 -0
  174. package/dist/storage/mongo/MongoPersistedSyncRulesContent.js +26 -0
  175. package/dist/storage/mongo/MongoPersistedSyncRulesContent.js.map +1 -0
  176. package/dist/storage/mongo/MongoSyncBucketStorage.d.ts +27 -0
  177. package/dist/storage/mongo/MongoSyncBucketStorage.js +379 -0
  178. package/dist/storage/mongo/MongoSyncBucketStorage.js.map +1 -0
  179. package/dist/storage/mongo/MongoSyncRulesLock.d.ts +16 -0
  180. package/dist/storage/mongo/MongoSyncRulesLock.js +65 -0
  181. package/dist/storage/mongo/MongoSyncRulesLock.js.map +1 -0
  182. package/dist/storage/mongo/OperationBatch.d.ts +26 -0
  183. package/dist/storage/mongo/OperationBatch.js +101 -0
  184. package/dist/storage/mongo/OperationBatch.js.map +1 -0
  185. package/dist/storage/mongo/PersistedBatch.d.ts +42 -0
  186. package/dist/storage/mongo/PersistedBatch.js +200 -0
  187. package/dist/storage/mongo/PersistedBatch.js.map +1 -0
  188. package/dist/storage/mongo/db.d.ts +23 -0
  189. package/dist/storage/mongo/db.js +34 -0
  190. package/dist/storage/mongo/db.js.map +1 -0
  191. package/dist/storage/mongo/models.d.ts +137 -0
  192. package/dist/storage/mongo/models.js +27 -0
  193. package/dist/storage/mongo/models.js.map +1 -0
  194. package/dist/storage/mongo/util.d.ts +26 -0
  195. package/dist/storage/mongo/util.js +81 -0
  196. package/dist/storage/mongo/util.js.map +1 -0
  197. package/dist/storage/storage-index.d.ts +14 -0
  198. package/dist/storage/storage-index.js +15 -0
  199. package/dist/storage/storage-index.js.map +1 -0
  200. package/dist/sync/BroadcastIterable.d.ts +38 -0
  201. package/dist/sync/BroadcastIterable.js +153 -0
  202. package/dist/sync/BroadcastIterable.js.map +1 -0
  203. package/dist/sync/LastValueSink.d.ts +25 -0
  204. package/dist/sync/LastValueSink.js +84 -0
  205. package/dist/sync/LastValueSink.js.map +1 -0
  206. package/dist/sync/merge.d.ts +39 -0
  207. package/dist/sync/merge.js +175 -0
  208. package/dist/sync/merge.js.map +1 -0
  209. package/dist/sync/safeRace.d.ts +1 -0
  210. package/dist/sync/safeRace.js +91 -0
  211. package/dist/sync/safeRace.js.map +1 -0
  212. package/dist/sync/sync-index.d.ts +6 -0
  213. package/dist/sync/sync-index.js +7 -0
  214. package/dist/sync/sync-index.js.map +1 -0
  215. package/dist/sync/sync.d.ts +18 -0
  216. package/dist/sync/sync.js +248 -0
  217. package/dist/sync/sync.js.map +1 -0
  218. package/dist/sync/util.d.ts +26 -0
  219. package/dist/sync/util.js +73 -0
  220. package/dist/sync/util.js.map +1 -0
  221. package/dist/system/CorePowerSyncSystem.d.ts +18 -0
  222. package/dist/system/CorePowerSyncSystem.js +28 -0
  223. package/dist/system/CorePowerSyncSystem.js.map +1 -0
  224. package/dist/util/Mutex.d.ts +47 -0
  225. package/dist/util/Mutex.js +132 -0
  226. package/dist/util/Mutex.js.map +1 -0
  227. package/dist/util/PgManager.d.ts +24 -0
  228. package/dist/util/PgManager.js +55 -0
  229. package/dist/util/PgManager.js.map +1 -0
  230. package/dist/util/alerting.d.ts +4 -0
  231. package/dist/util/alerting.js +14 -0
  232. package/dist/util/alerting.js.map +1 -0
  233. package/dist/util/config/collectors/config-collector.d.ts +29 -0
  234. package/dist/util/config/collectors/config-collector.js +116 -0
  235. package/dist/util/config/collectors/config-collector.js.map +1 -0
  236. package/dist/util/config/collectors/impl/base64-config-collector.d.ts +6 -0
  237. package/dist/util/config/collectors/impl/base64-config-collector.js +15 -0
  238. package/dist/util/config/collectors/impl/base64-config-collector.js.map +1 -0
  239. package/dist/util/config/collectors/impl/fallback-config-collector.d.ts +11 -0
  240. package/dist/util/config/collectors/impl/fallback-config-collector.js +19 -0
  241. package/dist/util/config/collectors/impl/fallback-config-collector.js.map +1 -0
  242. package/dist/util/config/collectors/impl/filesystem-config-collector.d.ts +6 -0
  243. package/dist/util/config/collectors/impl/filesystem-config-collector.js +35 -0
  244. package/dist/util/config/collectors/impl/filesystem-config-collector.js.map +1 -0
  245. package/dist/util/config/compound-config-collector.d.ts +32 -0
  246. package/dist/util/config/compound-config-collector.js +126 -0
  247. package/dist/util/config/compound-config-collector.js.map +1 -0
  248. package/dist/util/config/sync-rules/impl/base64-sync-rules-collector.d.ts +7 -0
  249. package/dist/util/config/sync-rules/impl/base64-sync-rules-collector.js +17 -0
  250. package/dist/util/config/sync-rules/impl/base64-sync-rules-collector.js.map +1 -0
  251. package/dist/util/config/sync-rules/impl/filesystem-sync-rules-collector.d.ts +7 -0
  252. package/dist/util/config/sync-rules/impl/filesystem-sync-rules-collector.js +21 -0
  253. package/dist/util/config/sync-rules/impl/filesystem-sync-rules-collector.js.map +1 -0
  254. package/dist/util/config/sync-rules/impl/inline-sync-rules-collector.d.ts +7 -0
  255. package/dist/util/config/sync-rules/impl/inline-sync-rules-collector.js +17 -0
  256. package/dist/util/config/sync-rules/impl/inline-sync-rules-collector.js.map +1 -0
  257. package/dist/util/config/sync-rules/sync-collector.d.ts +6 -0
  258. package/dist/util/config/sync-rules/sync-collector.js +3 -0
  259. package/dist/util/config/sync-rules/sync-collector.js.map +1 -0
  260. package/dist/util/config/types.d.ts +53 -0
  261. package/dist/util/config/types.js +7 -0
  262. package/dist/util/config/types.js.map +1 -0
  263. package/dist/util/config.d.ts +7 -0
  264. package/dist/util/config.js +35 -0
  265. package/dist/util/config.js.map +1 -0
  266. package/dist/util/env.d.ts +10 -0
  267. package/dist/util/env.js +25 -0
  268. package/dist/util/env.js.map +1 -0
  269. package/dist/util/memory-tracking.d.ts +7 -0
  270. package/dist/util/memory-tracking.js +58 -0
  271. package/dist/util/memory-tracking.js.map +1 -0
  272. package/dist/util/migration_lib.d.ts +11 -0
  273. package/dist/util/migration_lib.js +64 -0
  274. package/dist/util/migration_lib.js.map +1 -0
  275. package/dist/util/pgwire_utils.d.ts +24 -0
  276. package/dist/util/pgwire_utils.js +117 -0
  277. package/dist/util/pgwire_utils.js.map +1 -0
  278. package/dist/util/populate_test_data.d.ts +8 -0
  279. package/dist/util/populate_test_data.js +65 -0
  280. package/dist/util/populate_test_data.js.map +1 -0
  281. package/dist/util/protocol-types.d.ts +178 -0
  282. package/dist/util/protocol-types.js +38 -0
  283. package/dist/util/protocol-types.js.map +1 -0
  284. package/dist/util/secs.d.ts +2 -0
  285. package/dist/util/secs.js +49 -0
  286. package/dist/util/secs.js.map +1 -0
  287. package/dist/util/util-index.d.ts +22 -0
  288. package/dist/util/util-index.js +23 -0
  289. package/dist/util/util-index.js.map +1 -0
  290. package/dist/util/utils.d.ts +14 -0
  291. package/dist/util/utils.js +75 -0
  292. package/dist/util/utils.js.map +1 -0
  293. package/package.json +55 -0
  294. package/src/api/api-index.ts +2 -0
  295. package/src/api/diagnostics.ts +221 -0
  296. package/src/api/schema.ts +99 -0
  297. package/src/auth/CachedKeyCollector.ts +132 -0
  298. package/src/auth/CompoundKeyCollector.ts +33 -0
  299. package/src/auth/JwtPayload.ts +11 -0
  300. package/src/auth/KeyCollector.ts +27 -0
  301. package/src/auth/KeySpec.ts +67 -0
  302. package/src/auth/KeyStore.ts +156 -0
  303. package/src/auth/LeakyBucket.ts +66 -0
  304. package/src/auth/RemoteJWKSCollector.ts +130 -0
  305. package/src/auth/StaticKeyCollector.ts +21 -0
  306. package/src/auth/SupabaseKeyCollector.ts +67 -0
  307. package/src/auth/auth-index.ts +10 -0
  308. package/src/db/db-index.ts +1 -0
  309. package/src/db/mongo.ts +72 -0
  310. package/src/entry/cli-entry.ts +41 -0
  311. package/src/entry/commands/config-command.ts +36 -0
  312. package/src/entry/commands/migrate-action.ts +25 -0
  313. package/src/entry/commands/start-action.ts +24 -0
  314. package/src/entry/commands/teardown-action.ts +23 -0
  315. package/src/entry/entry-index.ts +5 -0
  316. package/src/index.ts +37 -0
  317. package/src/metrics/metrics.ts +169 -0
  318. package/src/migrations/db/migrations/1684951997326-init.ts +33 -0
  319. package/src/migrations/db/migrations/1688556755264-initial-sync-rules.ts +5 -0
  320. package/src/migrations/db/migrations/1702295701188-sync-rule-state.ts +99 -0
  321. package/src/migrations/db/migrations/1711543888062-write-checkpoint-index.ts +32 -0
  322. package/src/migrations/db/store.ts +11 -0
  323. package/src/migrations/migrations.ts +122 -0
  324. package/src/replication/ErrorRateLimiter.ts +49 -0
  325. package/src/replication/PgRelation.ts +42 -0
  326. package/src/replication/WalConnection.ts +227 -0
  327. package/src/replication/WalStream.ts +626 -0
  328. package/src/replication/WalStreamManager.ts +214 -0
  329. package/src/replication/WalStreamRunner.ts +180 -0
  330. package/src/replication/replication-index.ts +7 -0
  331. package/src/replication/util.ts +76 -0
  332. package/src/routes/admin.ts +229 -0
  333. package/src/routes/auth.ts +209 -0
  334. package/src/routes/checkpointing.ts +38 -0
  335. package/src/routes/dev.ts +194 -0
  336. package/src/routes/route-generators.ts +39 -0
  337. package/src/routes/router-socket.ts +13 -0
  338. package/src/routes/router.ts +17 -0
  339. package/src/routes/routes-index.ts +5 -0
  340. package/src/routes/socket-route.ts +131 -0
  341. package/src/routes/sync-rules.ts +210 -0
  342. package/src/routes/sync-stream.ts +92 -0
  343. package/src/runner/teardown.ts +91 -0
  344. package/src/storage/BucketStorage.ts +386 -0
  345. package/src/storage/MongoBucketStorage.ts +493 -0
  346. package/src/storage/SourceTable.ts +60 -0
  347. package/src/storage/mongo/MongoBucketBatch.ts +756 -0
  348. package/src/storage/mongo/MongoIdSequence.ts +24 -0
  349. package/src/storage/mongo/MongoPersistedSyncRules.ts +16 -0
  350. package/src/storage/mongo/MongoPersistedSyncRulesContent.ts +47 -0
  351. package/src/storage/mongo/MongoSyncBucketStorage.ts +517 -0
  352. package/src/storage/mongo/MongoSyncRulesLock.ts +81 -0
  353. package/src/storage/mongo/OperationBatch.ts +115 -0
  354. package/src/storage/mongo/PersistedBatch.ts +245 -0
  355. package/src/storage/mongo/db.ts +69 -0
  356. package/src/storage/mongo/models.ts +157 -0
  357. package/src/storage/mongo/util.ts +88 -0
  358. package/src/storage/storage-index.ts +15 -0
  359. package/src/sync/BroadcastIterable.ts +161 -0
  360. package/src/sync/LastValueSink.ts +100 -0
  361. package/src/sync/merge.ts +200 -0
  362. package/src/sync/safeRace.ts +99 -0
  363. package/src/sync/sync-index.ts +6 -0
  364. package/src/sync/sync.ts +312 -0
  365. package/src/sync/util.ts +98 -0
  366. package/src/system/CorePowerSyncSystem.ts +43 -0
  367. package/src/util/Mutex.ts +159 -0
  368. package/src/util/PgManager.ts +64 -0
  369. package/src/util/alerting.ts +17 -0
  370. package/src/util/config/collectors/config-collector.ts +141 -0
  371. package/src/util/config/collectors/impl/base64-config-collector.ts +18 -0
  372. package/src/util/config/collectors/impl/fallback-config-collector.ts +22 -0
  373. package/src/util/config/collectors/impl/filesystem-config-collector.ts +41 -0
  374. package/src/util/config/compound-config-collector.ts +171 -0
  375. package/src/util/config/sync-rules/impl/base64-sync-rules-collector.ts +21 -0
  376. package/src/util/config/sync-rules/impl/filesystem-sync-rules-collector.ts +26 -0
  377. package/src/util/config/sync-rules/impl/inline-sync-rules-collector.ts +21 -0
  378. package/src/util/config/sync-rules/sync-collector.ts +8 -0
  379. package/src/util/config/types.ts +60 -0
  380. package/src/util/config.ts +39 -0
  381. package/src/util/env.ts +28 -0
  382. package/src/util/memory-tracking.ts +67 -0
  383. package/src/util/migration_lib.ts +79 -0
  384. package/src/util/pgwire_utils.ts +139 -0
  385. package/src/util/populate_test_data.ts +78 -0
  386. package/src/util/protocol-types.ts +223 -0
  387. package/src/util/secs.ts +54 -0
  388. package/src/util/util-index.ts +25 -0
  389. package/src/util/utils.ts +102 -0
  390. package/test/src/__snapshots__/pg_test.test.ts.snap +256 -0
  391. package/test/src/__snapshots__/sync.test.ts.snap +235 -0
  392. package/test/src/auth.test.ts +340 -0
  393. package/test/src/broadcast_iterable.test.ts +156 -0
  394. package/test/src/data_storage.test.ts +1176 -0
  395. package/test/src/env.ts +8 -0
  396. package/test/src/large_batch.test.ts +194 -0
  397. package/test/src/merge_iterable.test.ts +355 -0
  398. package/test/src/pg_test.test.ts +432 -0
  399. package/test/src/schema_changes.test.ts +545 -0
  400. package/test/src/slow_tests.test.ts +257 -0
  401. package/test/src/sql_functions.test.ts +254 -0
  402. package/test/src/sql_operators.test.ts +132 -0
  403. package/test/src/sync.test.ts +293 -0
  404. package/test/src/sync_rules.test.ts +1051 -0
  405. package/test/src/util.ts +67 -0
  406. package/test/src/validation.test.ts +63 -0
  407. package/test/src/wal_stream.test.ts +310 -0
  408. package/test/src/wal_stream_utils.ts +147 -0
  409. package/test/tsconfig.json +20 -0
  410. package/tsconfig.json +20 -0
  411. package/tsconfig.tsbuildinfo +1 -0
  412. package/vitest.config.ts +11 -0
@@ -0,0 +1,3 @@
1
+ import * as utils from '../../../util/util-index.js';
2
+ export declare const up: (context?: utils.MigrationContext) => Promise<void>;
3
+ export declare const down: (context?: utils.MigrationContext) => Promise<void>;
@@ -0,0 +1,54 @@
1
+ import * as mongo from '../../../db/mongo.js';
2
+ import * as storage from '../../../storage/storage-index.js';
3
+ import * as utils from '../../../util/util-index.js';
4
+ export const up = async (context) => {
5
+ const config = await utils.loadConfig(context?.runner_config);
6
+ const db = storage.createPowerSyncMongo(config.storage);
7
+ await mongo.waitForAuth(db.db);
8
+ try {
9
+ // We keep the old flags for existing deployments still shutting down.
10
+ // 1. New sync rules: `active = false, snapshot_done = false, replicating = true, auto_activate = true`
11
+ await db.sync_rules.updateMany({
12
+ active: { $ne: true },
13
+ replicating: true,
14
+ auto_activate: true
15
+ }, { $set: { state: storage.SyncRuleState.PROCESSING } });
16
+ // 2. Snapshot done: `active = true, snapshot_done = true, replicating = true, auto_activate = false`
17
+ await db.sync_rules.updateMany({
18
+ active: true
19
+ }, { $set: { state: storage.SyncRuleState.ACTIVE } });
20
+ // 3. Stopped: `active = false, snapshot_done = true, replicating = false, auto_activate = false`.
21
+ await db.sync_rules.updateMany({
22
+ active: { $ne: true },
23
+ replicating: { $ne: true },
24
+ auto_activate: { $ne: true }
25
+ }, { $set: { state: storage.SyncRuleState.STOP } });
26
+ const remaining = await db.sync_rules.find({ state: null }).toArray();
27
+ if (remaining.length > 0) {
28
+ const slots = remaining.map((doc) => doc.slot_name).join(', ');
29
+ throw new Error(`Invalid state for sync rules: ${slots}`);
30
+ }
31
+ }
32
+ finally {
33
+ await db.client.close();
34
+ }
35
+ };
36
+ export const down = async (context) => {
37
+ const config = await utils.loadConfig(context?.runner_config);
38
+ const db = storage.createPowerSyncMongo(config.storage);
39
+ try {
40
+ await db.sync_rules.updateMany({
41
+ state: storage.SyncRuleState.ACTIVE
42
+ }, { $set: { active: true, replicating: true } });
43
+ await db.sync_rules.updateMany({
44
+ state: storage.SyncRuleState.PROCESSING
45
+ }, { $set: { active: false, replicating: true, auto_activate: true } });
46
+ await db.sync_rules.updateMany({
47
+ $or: [{ state: storage.SyncRuleState.STOP }, { state: storage.SyncRuleState.TERMINATED }]
48
+ }, { $set: { active: false, replicating: false, auto_activate: false } });
49
+ }
50
+ finally {
51
+ await db.client.close();
52
+ }
53
+ };
54
+ //# sourceMappingURL=1702295701188-sync-rule-state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"1702295701188-sync-rule-state.js","sourceRoot":"","sources":["../../../../src/migrations/db/migrations/1702295701188-sync-rule-state.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import * as utils from '../../../util/util-index.js';
2
+ export declare const up: (context?: utils.MigrationContext) => Promise<void>;
3
+ export declare const down: (context?: utils.MigrationContext) => Promise<void>;
@@ -0,0 +1,27 @@
1
+ import * as storage from '../../../storage/storage-index.js';
2
+ import * as utils from '../../../util/util-index.js';
3
+ export const up = async (context) => {
4
+ const config = await utils.loadConfig(context?.runner_config);
5
+ const db = storage.createPowerSyncMongo(config.storage);
6
+ try {
7
+ await db.write_checkpoints.createIndex({
8
+ user_id: 1
9
+ }, { name: 'user_id' });
10
+ }
11
+ finally {
12
+ await db.client.close();
13
+ }
14
+ };
15
+ export const down = async (context) => {
16
+ const config = await utils.loadConfig(context?.runner_config);
17
+ const db = storage.createPowerSyncMongo(config.storage);
18
+ try {
19
+ if (await db.write_checkpoints.indexExists('user_id')) {
20
+ await db.write_checkpoints.dropIndex('user_id');
21
+ }
22
+ }
23
+ finally {
24
+ await db.client.close();
25
+ }
26
+ };
27
+ //# sourceMappingURL=1711543888062-write-checkpoint-index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"1711543888062-write-checkpoint-index.js","sourceRoot":"","sources":["../../../../src/migrations/db/migrations/1711543888062-write-checkpoint-index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,4BAA4B,CAAC;AACtD,OAAO,KAAK,KAAK,MAAM,sBAAsB,CAAC;AAE9C,MAAM,CAAC,MAAM,EAAE,GAAG,KAAK,EAAE,OAAgC,EAAE,EAAE;IAC3D,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,UAAU,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC;IAC9D,MAAM,EAAE,GAAG,OAAO,CAAC,oBAAoB,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAExD,IAAI,CAAC;QACH,MAAM,EAAE,CAAC,iBAAiB,CAAC,WAAW,CACpC;YACE,OAAO,EAAE,CAAC;SACX,EACD,EAAE,IAAI,EAAE,SAAS,EAAE,CACpB,CAAC;IACJ,CAAC;YAAS,CAAC;QACT,MAAM,EAAE,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;IAC1B,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,IAAI,GAAG,KAAK,EAAE,OAAgC,EAAE,EAAE;IAC7D,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,UAAU,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC;IAE9D,MAAM,EAAE,GAAG,OAAO,CAAC,oBAAoB,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAExD,IAAI,CAAC;QACH,IAAI,MAAM,EAAE,CAAC,iBAAiB,CAAC,WAAW,CAAC,SAAS,CAAC,EAAE,CAAC;YACtD,MAAM,EAAE,CAAC,iBAAiB,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;QAClD,CAAC;IACH,CAAC;YAAS,CAAC;QACT,MAAM,EAAE,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;IAC1B,CAAC;AACH,CAAC,CAAC"}
@@ -0,0 +1,3 @@
1
+ import * as micro_migrate from '@journeyapps-platform/micro-migrate';
2
+ declare const _default: micro_migrate.MigrationStore;
3
+ export default _default;
@@ -0,0 +1,10 @@
1
+ import * as micro_migrate from '@journeyapps-platform/micro-migrate';
2
+ import * as utils from '../../util/util-index.js';
3
+ const config = await utils.loadConfig();
4
+ export default micro_migrate.createMongoMigrationStore({
5
+ uri: config.storage.uri,
6
+ database: config.storage.database,
7
+ username: config.storage.username,
8
+ password: config.storage.password
9
+ });
10
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../../../src/migrations/db/store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,aAAa,MAAM,qCAAqC,CAAC;AACrE,OAAO,KAAK,KAAK,MAAM,sBAAsB,CAAC;AAE9C,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,UAAU,EAAE,CAAC;AAExC,eAAe,aAAa,CAAC,yBAAyB,CAAC;IACrD,GAAG,EAAE,MAAM,CAAC,OAAO,CAAC,GAAG;IACvB,QAAQ,EAAE,MAAM,CAAC,OAAO,CAAC,QAAQ;IACjC,QAAQ,EAAE,MAAM,CAAC,OAAO,CAAC,QAAQ;IACjC,QAAQ,EAAE,MAAM,CAAC,OAAO,CAAC,QAAQ;CAClC,CAAC,CAAC"}
@@ -0,0 +1,10 @@
1
+ import { Direction } from '@journeyapps-platform/micro-migrate';
2
+ import * as util from '../util/util-index.js';
3
+ export type MigrationOptions = {
4
+ direction: Direction;
5
+ runner_config: util.RunnerConfig;
6
+ };
7
+ /**
8
+ * Runs migration scripts exclusively using Mongo locks
9
+ */
10
+ export declare const migrate: (options: MigrationOptions) => Promise<void>;
@@ -0,0 +1,94 @@
1
+ import * as fs from 'fs/promises';
2
+ import * as path from 'path';
3
+ import { fileURLToPath } from 'url';
4
+ import { createMongoLockManager } from '@journeyapps-platform/micro-locks';
5
+ import { createMongoMigrationStore, execute, writeLogsToStore } from '@journeyapps-platform/micro-migrate';
6
+ import * as db from '../db/db-index.js';
7
+ import * as util from '../util/util-index.js';
8
+ const DEFAULT_MONGO_LOCK_COLLECTION = 'locks';
9
+ const MONGO_LOCK_PROCESS = 'migrations';
10
+ const __filename = fileURLToPath(import.meta.url);
11
+ const __dirname = path.dirname(__filename);
12
+ const MIGRATIONS_DIR = path.join(__dirname, '/db/migrations');
13
+ /**
14
+ * Loads migrations and injects a custom context for loading the specified
15
+ * runner configuration.
16
+ */
17
+ const loadMigrations = async (dir, runner_config) => {
18
+ const files = await fs.readdir(dir);
19
+ const migrations = files.filter((file) => {
20
+ return path.extname(file) === '.js';
21
+ });
22
+ const context = {
23
+ runner_config
24
+ };
25
+ return await Promise.all(migrations.map(async (migration) => {
26
+ const module = await import(path.resolve(dir, migration));
27
+ return {
28
+ name: path.basename(migration).replace(path.extname(migration), ''),
29
+ up: () => module.up(context),
30
+ down: () => module.down(context)
31
+ };
32
+ }));
33
+ };
34
+ /**
35
+ * Runs migration scripts exclusively using Mongo locks
36
+ */
37
+ export const migrate = async (options) => {
38
+ const { direction, runner_config } = options;
39
+ /**
40
+ * Try and get Mongo from config file.
41
+ * But this might not be available in Journey Micro as we use the standard Mongo.
42
+ */
43
+ const config = await util.loadConfig(runner_config);
44
+ const { storage } = config;
45
+ const client = db.mongo.createMongoClient(storage);
46
+ await client.connect();
47
+ const clientDB = client.db(storage.database);
48
+ const collection = clientDB.collection(DEFAULT_MONGO_LOCK_COLLECTION);
49
+ const manager = createMongoLockManager(collection, {
50
+ name: MONGO_LOCK_PROCESS
51
+ });
52
+ // Only one process should execute this at a time.
53
+ const lockId = await manager.acquire();
54
+ if (!lockId) {
55
+ throw new Error('Could not acquire lock_id');
56
+ }
57
+ let isReleased = false;
58
+ const releaseLock = async () => {
59
+ if (isReleased) {
60
+ return;
61
+ }
62
+ await manager.release(lockId);
63
+ isReleased = true;
64
+ };
65
+ // For the case where the migration is terminated
66
+ process.addListener('beforeExit', releaseLock);
67
+ try {
68
+ const migrations = await loadMigrations(MIGRATIONS_DIR, runner_config);
69
+ // Use the provided config to connect to Mongo
70
+ const store = createMongoMigrationStore({
71
+ uri: storage.uri,
72
+ database: storage.database,
73
+ username: storage.username,
74
+ password: storage.password
75
+ });
76
+ const state = await store.load();
77
+ const logStream = execute({
78
+ direction: direction,
79
+ migrations,
80
+ state
81
+ });
82
+ await writeLogsToStore({
83
+ log_stream: logStream,
84
+ store,
85
+ state
86
+ });
87
+ }
88
+ finally {
89
+ await releaseLock();
90
+ await client.close(true);
91
+ process.removeListener('beforeExit', releaseLock);
92
+ }
93
+ };
94
+ //# sourceMappingURL=migrations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migrations.js","sourceRoot":"","sources":["../../src/migrations/migrations.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /// <reference types="node" resolution-mode="require"/>
2
+ export interface ErrorRateLimiter {
3
+ waitUntilAllowed(options?: {
4
+ signal?: AbortSignal;
5
+ }): Promise<void>;
6
+ reportError(e: any): void;
7
+ mayPing(): boolean;
8
+ }
9
+ export declare class DefaultErrorRateLimiter implements ErrorRateLimiter {
10
+ nextAllowed: number;
11
+ waitUntilAllowed(options?: {
12
+ signal?: AbortSignal | undefined;
13
+ } | undefined): Promise<void>;
14
+ mayPing(): boolean;
15
+ reportError(e: any): void;
16
+ private setDelay;
17
+ }
@@ -0,0 +1,42 @@
1
+ import { setTimeout } from 'timers/promises';
2
+ export class DefaultErrorRateLimiter {
3
+ constructor() {
4
+ this.nextAllowed = Date.now();
5
+ }
6
+ async waitUntilAllowed(options) {
7
+ const delay = Math.max(0, this.nextAllowed - Date.now());
8
+ this.setDelay(5000);
9
+ await setTimeout(delay, undefined, { signal: options?.signal });
10
+ }
11
+ mayPing() {
12
+ return Date.now() >= this.nextAllowed;
13
+ }
14
+ reportError(e) {
15
+ const message = e.message ?? '';
16
+ if (message.includes('password authentication failed')) {
17
+ // Wait 15 minutes, to avoid triggering Supabase's fail2ban
18
+ this.setDelay(900000);
19
+ }
20
+ else if (message.includes('ENOTFOUND')) {
21
+ // DNS lookup issue - incorrect URI or deleted instance
22
+ this.setDelay(120000);
23
+ }
24
+ else if (message.includes('ECONNREFUSED')) {
25
+ // Could be fail2ban or similar
26
+ this.setDelay(120000);
27
+ }
28
+ else if (message.includes('Unable to do postgres query on ended pool') ||
29
+ message.includes('Postgres unexpectedly closed connection')) {
30
+ // Connection timed out - ignore / immediately retry
31
+ // We don't explicitly set the delay to 0, since there could have been another error that
32
+ // we need to respect.
33
+ }
34
+ else {
35
+ this.setDelay(30000);
36
+ }
37
+ }
38
+ setDelay(delay) {
39
+ this.nextAllowed = Math.max(this.nextAllowed, Date.now() + delay);
40
+ }
41
+ }
42
+ //# sourceMappingURL=ErrorRateLimiter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ErrorRateLimiter.js","sourceRoot":"","sources":["../../src/replication/ErrorRateLimiter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAS7C,MAAM,OAAO,uBAAuB;IAApC;QACE,gBAAW,GAAW,IAAI,CAAC,GAAG,EAAE,CAAC;IAsCnC,CAAC;IApCC,KAAK,CAAC,gBAAgB,CAAC,OAA0D;QAC/E,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;QACzD,IAAI,CAAC,QAAQ,CAAC,IAAK,CAAC,CAAC;QACrB,MAAM,UAAU,CAAC,KAAK,EAAE,SAAS,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;IAClE,CAAC;IAED,OAAO;QACL,OAAO,IAAI,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC,WAAW,CAAC;IACxC,CAAC;IAED,WAAW,CAAC,CAAM;QAChB,MAAM,OAAO,GAAI,CAAC,CAAC,OAAkB,IAAI,EAAE,CAAC;QAC5C,IAAI,OAAO,CAAC,QAAQ,CAAC,gCAAgC,CAAC,EAAE,CAAC;YACvD,2DAA2D;YAC3D,IAAI,CAAC,QAAQ,CAAC,MAAO,CAAC,CAAC;QACzB,CAAC;aAAM,IAAI,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;YACzC,uDAAuD;YACvD,IAAI,CAAC,QAAQ,CAAC,MAAO,CAAC,CAAC;QACzB,CAAC;aAAM,IAAI,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC;YAC5C,+BAA+B;YAC/B,IAAI,CAAC,QAAQ,CAAC,MAAO,CAAC,CAAC;QACzB,CAAC;aAAM,IACL,OAAO,CAAC,QAAQ,CAAC,2CAA2C,CAAC;YAC7D,OAAO,CAAC,QAAQ,CAAC,yCAAyC,CAAC,EAC3D,CAAC;YACD,oDAAoD;YACpD,yFAAyF;YACzF,sBAAsB;QACxB,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,QAAQ,CAAC,KAAM,CAAC,CAAC;QACxB,CAAC;IACH,CAAC;IAEO,QAAQ,CAAC,KAAa;QAC5B,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,CAAC;IACpE,CAAC;CACF"}
@@ -0,0 +1,16 @@
1
+ import { PgoutputRelation } from '@powersync/service-jpgwire';
2
+ export interface PgRelation {
3
+ readonly relationId: number;
4
+ readonly schema: string;
5
+ readonly name: string;
6
+ readonly replicaIdentity: ReplicationIdentity;
7
+ readonly replicationColumns: ReplicationColumn[];
8
+ }
9
+ export type ReplicationIdentity = 'default' | 'nothing' | 'full' | 'index';
10
+ export interface ReplicationColumn {
11
+ readonly name: string;
12
+ readonly typeOid: number;
13
+ }
14
+ export declare function getReplicaIdColumns(relation: PgoutputRelation): ReplicationColumn[];
15
+ export declare function getRelId(source: PgoutputRelation): number;
16
+ export declare function getPgOutputRelation(source: PgoutputRelation): PgRelation;
@@ -0,0 +1,26 @@
1
+ export function getReplicaIdColumns(relation) {
2
+ if (relation.replicaIdentity == 'nothing') {
3
+ return [];
4
+ }
5
+ else {
6
+ return relation.columns.filter((c) => (c.flags & 0b1) != 0).map((c) => ({ name: c.name, typeOid: c.typeOid }));
7
+ }
8
+ }
9
+ export function getRelId(source) {
10
+ // Source types are wrong here
11
+ const relId = source.relationOid;
12
+ if (relId == null || typeof relId != 'number') {
13
+ throw new Error(`No relation id!`);
14
+ }
15
+ return relId;
16
+ }
17
+ export function getPgOutputRelation(source) {
18
+ return {
19
+ name: source.name,
20
+ schema: source.schema,
21
+ relationId: getRelId(source),
22
+ replicaIdentity: source.replicaIdentity,
23
+ replicationColumns: getReplicaIdColumns(source)
24
+ };
25
+ }
26
+ //# sourceMappingURL=PgRelation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PgRelation.js","sourceRoot":"","sources":["../../src/replication/PgRelation.ts"],"names":[],"mappings":"AAiBA,MAAM,UAAU,mBAAmB,CAAC,QAA0B;IAC5D,IAAI,QAAQ,CAAC,eAAe,IAAI,SAAS,EAAE,CAAC;QAC1C,OAAO,EAAE,CAAC;IACZ,CAAC;SAAM,CAAC;QACN,OAAO,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;IACjH,CAAC;AACH,CAAC;AACD,MAAM,UAAU,QAAQ,CAAC,MAAwB;IAC/C,8BAA8B;IAC9B,MAAM,KAAK,GAAI,MAAc,CAAC,WAAqB,CAAC;IACpD,IAAI,KAAK,IAAI,IAAI,IAAI,OAAO,KAAK,IAAI,QAAQ,EAAE,CAAC;QAC9C,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAC;IACrC,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,MAAwB;IAC1D,OAAO;QACL,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,UAAU,EAAE,QAAQ,CAAC,MAAM,CAAC;QAC5B,eAAe,EAAE,MAAM,CAAC,eAAe;QACvC,kBAAkB,EAAE,mBAAmB,CAAC,MAAM,CAAC;KAChD,CAAC;AACJ,CAAC"}
@@ -0,0 +1,34 @@
1
+ import * as pgwire from '@powersync/service-jpgwire';
2
+ import { SqlSyncRules, TablePattern } from '@powersync/service-sync-rules';
3
+ import { TableInfo } from '@powersync/service-types';
4
+ /**
5
+ * Connection that _manages_ WAL, but does not do streaming.
6
+ */
7
+ export declare class WalConnection {
8
+ db: pgwire.PgClient;
9
+ connectionTag: string;
10
+ publication_name: string;
11
+ sync_rules: SqlSyncRules;
12
+ /**
13
+ * db can be a PgConnection or PgPool.
14
+ *
15
+ * No transactions are used here, but it is up to the client to ensure
16
+ * nothing here is called in the middle of another transaction if
17
+ * PgConnection is used.
18
+ */
19
+ constructor(options: {
20
+ db: pgwire.PgClient;
21
+ sync_rules: SqlSyncRules;
22
+ });
23
+ checkSourceConfiguration(): Promise<void>;
24
+ getDebugTableInfo(tablePattern: TablePattern, name: string, relationId: number | null): Promise<TableInfo>;
25
+ getDebugTablesInfo(tablePatterns: TablePattern[]): Promise<PatternResult[]>;
26
+ }
27
+ export interface PatternResult {
28
+ schema: string;
29
+ pattern: string;
30
+ wildcard: boolean;
31
+ tables?: TableInfo[];
32
+ table?: TableInfo;
33
+ }
34
+ export declare function checkSourceConfiguration(db: pgwire.PgClient): Promise<void>;
@@ -0,0 +1,190 @@
1
+ import { pgwireRows } from '@powersync/service-jpgwire';
2
+ import { DEFAULT_TAG } from '@powersync/service-sync-rules';
3
+ import * as storage from '../storage/storage-index.js';
4
+ import * as util from '../util/util-index.js';
5
+ import { getReplicationIdentityColumns } from './util.js';
6
+ /**
7
+ * Connection that _manages_ WAL, but does not do streaming.
8
+ */
9
+ export class WalConnection {
10
+ /**
11
+ * db can be a PgConnection or PgPool.
12
+ *
13
+ * No transactions are used here, but it is up to the client to ensure
14
+ * nothing here is called in the middle of another transaction if
15
+ * PgConnection is used.
16
+ */
17
+ constructor(options) {
18
+ this.connectionTag = DEFAULT_TAG;
19
+ this.publication_name = 'powersync';
20
+ this.db = options.db;
21
+ this.sync_rules = options.sync_rules;
22
+ }
23
+ async checkSourceConfiguration() {
24
+ await checkSourceConfiguration(this.db);
25
+ }
26
+ async getDebugTableInfo(tablePattern, name, relationId) {
27
+ const schema = tablePattern.schema;
28
+ let id_columns_result = undefined;
29
+ let id_columns_error = null;
30
+ if (relationId != null) {
31
+ try {
32
+ id_columns_result = await getReplicationIdentityColumns(this.db, relationId);
33
+ }
34
+ catch (e) {
35
+ id_columns_error = { level: 'fatal', message: e.message };
36
+ }
37
+ }
38
+ const id_columns = id_columns_result?.columns ?? [];
39
+ const sourceTable = new storage.SourceTable(0, this.connectionTag, relationId ?? 0, schema, name, id_columns, true);
40
+ const syncData = this.sync_rules.tableSyncsData(sourceTable);
41
+ const syncParameters = this.sync_rules.tableSyncsParameters(sourceTable);
42
+ if (relationId == null) {
43
+ return {
44
+ schema: schema,
45
+ name: name,
46
+ pattern: tablePattern.isWildcard ? tablePattern.tablePattern : undefined,
47
+ replication_id: [],
48
+ data_queries: syncData,
49
+ parameter_queries: syncParameters,
50
+ // Also
51
+ errors: [{ level: 'warning', message: `Table ${sourceTable.qualifiedName} not found.` }]
52
+ };
53
+ }
54
+ if (id_columns.length == 0 && id_columns_error == null) {
55
+ let message = `No replication id found for ${sourceTable.qualifiedName}. Replica identity: ${id_columns_result?.replicationIdentity}.`;
56
+ if (id_columns_result?.replicationIdentity == 'default') {
57
+ message += ' Configure a primary key on the table.';
58
+ }
59
+ id_columns_error = { level: 'fatal', message };
60
+ }
61
+ let selectError = null;
62
+ try {
63
+ await util.retriedQuery(this.db, `SELECT * FROM ${sourceTable.escapedIdentifier} LIMIT 1`);
64
+ }
65
+ catch (e) {
66
+ selectError = { level: 'fatal', message: e.message };
67
+ }
68
+ let replicateError = null;
69
+ const publications = await util.retriedQuery(this.db, {
70
+ statement: `SELECT tablename FROM pg_publication_tables WHERE pubname = $1 AND schemaname = $2 AND tablename = $3`,
71
+ params: [
72
+ { type: 'varchar', value: this.publication_name },
73
+ { type: 'varchar', value: tablePattern.schema },
74
+ { type: 'varchar', value: name }
75
+ ]
76
+ });
77
+ if (publications.rows.length == 0) {
78
+ replicateError = {
79
+ level: 'fatal',
80
+ message: `Table ${sourceTable.qualifiedName} is not part of publication '${this.publication_name}'. Run: \`ALTER PUBLICATION ${this.publication_name} ADD TABLE ${sourceTable.qualifiedName}\`.`
81
+ };
82
+ }
83
+ return {
84
+ schema: schema,
85
+ name: name,
86
+ pattern: tablePattern.isWildcard ? tablePattern.tablePattern : undefined,
87
+ replication_id: id_columns.map((c) => c.name),
88
+ data_queries: syncData,
89
+ parameter_queries: syncParameters,
90
+ errors: [id_columns_error, selectError, replicateError].filter((error) => error != null)
91
+ };
92
+ }
93
+ async getDebugTablesInfo(tablePatterns) {
94
+ let result = [];
95
+ for (let tablePattern of tablePatterns) {
96
+ const schema = tablePattern.schema;
97
+ let patternResult = {
98
+ schema: schema,
99
+ pattern: tablePattern.tablePattern,
100
+ wildcard: tablePattern.isWildcard
101
+ };
102
+ result.push(patternResult);
103
+ if (tablePattern.isWildcard) {
104
+ patternResult.tables = [];
105
+ const prefix = tablePattern.tablePrefix;
106
+ const results = await util.retriedQuery(this.db, {
107
+ statement: `SELECT c.oid AS relid, c.relname AS table_name
108
+ FROM pg_class c
109
+ JOIN pg_namespace n ON n.oid = c.relnamespace
110
+ WHERE n.nspname = $1
111
+ AND c.relkind = 'r'
112
+ AND c.relname LIKE $2`,
113
+ params: [
114
+ { type: 'varchar', value: schema },
115
+ { type: 'varchar', value: tablePattern.tablePattern }
116
+ ]
117
+ });
118
+ for (let row of pgwireRows(results)) {
119
+ const name = row.table_name;
120
+ const relationId = row.relid;
121
+ if (!name.startsWith(prefix)) {
122
+ continue;
123
+ }
124
+ const details = await this.getDebugTableInfo(tablePattern, name, relationId);
125
+ patternResult.tables.push(details);
126
+ }
127
+ }
128
+ else {
129
+ const results = await util.retriedQuery(this.db, {
130
+ statement: `SELECT c.oid AS relid, c.relname AS table_name
131
+ FROM pg_class c
132
+ JOIN pg_namespace n ON n.oid = c.relnamespace
133
+ WHERE n.nspname = $1
134
+ AND c.relkind = 'r'
135
+ AND c.relname = $2`,
136
+ params: [
137
+ { type: 'varchar', value: schema },
138
+ { type: 'varchar', value: tablePattern.tablePattern }
139
+ ]
140
+ });
141
+ if (results.rows.length == 0) {
142
+ // Table not found
143
+ const details = await this.getDebugTableInfo(tablePattern, tablePattern.name, null);
144
+ patternResult.table = details;
145
+ }
146
+ else {
147
+ const row = pgwireRows(results)[0];
148
+ const name = row.table_name;
149
+ const relationId = row.relid;
150
+ patternResult.table = await this.getDebugTableInfo(tablePattern, name, relationId);
151
+ }
152
+ }
153
+ }
154
+ return result;
155
+ }
156
+ }
157
+ export async function checkSourceConfiguration(db) {
158
+ // TODO: configurable
159
+ const publication_name = 'powersync';
160
+ // Check basic config
161
+ await util.retriedQuery(db, `DO $$
162
+ BEGIN
163
+ if current_setting('wal_level') is distinct from 'logical' then
164
+ 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');
165
+ end if;
166
+ if (current_setting('max_replication_slots')::int >= 1) is not true then
167
+ raise exception 'Your max_replication_slots setting is too low, it must be greater than 1. Please edit your config file and restart PostgreSQL.';
168
+ end if;
169
+ if (current_setting('max_wal_senders')::int >= 1) is not true then
170
+ raise exception 'Your max_wal_senders setting is too low, it must be greater than 1. Please edit your config file and restart PostgreSQL.';
171
+ end if;
172
+ end;
173
+ $$ LANGUAGE plpgsql;`);
174
+ // Check that publication exists
175
+ const rs = await util.retriedQuery(db, {
176
+ statement: `SELECT * FROM pg_publication WHERE pubname = $1`,
177
+ params: [{ type: 'varchar', value: publication_name }]
178
+ });
179
+ const row = pgwireRows(rs)[0];
180
+ if (row == null) {
181
+ throw new Error(`Publication '${publication_name}' does not exist. Run: \`CREATE PUBLICATION ${publication_name} FOR ALL TABLES\`, or read the documentation for details.`);
182
+ }
183
+ if (row.pubinsert == false || row.pubupdate == false || row.pubdelete == false || row.pubtruncate == false) {
184
+ throw new Error(`Publication '${publication_name}' does not publish all changes. Create a publication using \`WITH (publish = "insert, update, delete, truncate")\` (the default).`);
185
+ }
186
+ if (row.pubviaroot) {
187
+ throw new Error(`'${publication_name}' uses publish_via_partition_root, which is not supported.`);
188
+ }
189
+ }
190
+ //# sourceMappingURL=WalConnection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WalConnection.js","sourceRoot":"","sources":["../../src/replication/WalConnection.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,58 @@
1
+ /// <reference types="node" resolution-mode="require"/>
2
+ import * as pgwire from '@powersync/service-jpgwire';
3
+ import { SqliteRow, SqlSyncRules, TablePattern } from '@powersync/service-sync-rules';
4
+ import * as storage from '../storage/storage-index.js';
5
+ import * as util from '../util/util-index.js';
6
+ import { PgRelation } from './PgRelation.js';
7
+ import { WalConnection } from './WalConnection.js';
8
+ export declare const ZERO_LSN = "00000000/00000000";
9
+ export interface WalStreamOptions {
10
+ connections: util.PgManager;
11
+ factory: storage.BucketStorageFactory;
12
+ storage: storage.SyncRulesBucketStorage;
13
+ abort_signal: AbortSignal;
14
+ }
15
+ interface InitResult {
16
+ needsInitialSync: boolean;
17
+ }
18
+ export declare class MissingReplicationSlotError extends Error {
19
+ constructor(message: string);
20
+ }
21
+ export declare class WalStream {
22
+ sync_rules: SqlSyncRules;
23
+ group_id: number;
24
+ wal_connection: WalConnection;
25
+ connection_id: number;
26
+ private readonly storage;
27
+ private slot_name;
28
+ private connections;
29
+ private abort_signal;
30
+ private relation_cache;
31
+ private startedStreaming;
32
+ constructor(options: WalStreamOptions);
33
+ get publication_name(): string;
34
+ get connectionTag(): string;
35
+ get stopped(): boolean;
36
+ getQualifiedTableNames(batch: storage.BucketStorageBatch, db: pgwire.PgConnection, tablePattern: TablePattern): Promise<storage.SourceTable[]>;
37
+ initSlot(): Promise<InitResult>;
38
+ estimatedCount(db: pgwire.PgConnection, table: storage.SourceTable): Promise<string>;
39
+ /**
40
+ * Start initial replication.
41
+ *
42
+ * If (partial) replication was done before on this slot, this clears the state
43
+ * and starts again from scratch.
44
+ */
45
+ startInitialReplication(replicationConnection: pgwire.PgConnection): Promise<void>;
46
+ initialReplication(db: pgwire.PgConnection, lsn: string): Promise<void>;
47
+ static getQueryData(results: Iterable<pgwire.DatabaseInputRow>): Generator<SqliteRow>;
48
+ private snapshotTable;
49
+ handleRelation(batch: storage.BucketStorageBatch, relation: PgRelation, snapshot: boolean): Promise<storage.SourceTable>;
50
+ private getTable;
51
+ writeChange(batch: storage.BucketStorageBatch, msg: pgwire.PgoutputMessage): Promise<storage.FlushedResult | null>;
52
+ replicate(): Promise<void>;
53
+ initReplication(replicationConnection: pgwire.PgConnection): Promise<void>;
54
+ streamChanges(replicationConnection: pgwire.PgConnection): Promise<void>;
55
+ ack(lsn: string, replicationStream: pgwire.ReplicationStream): Promise<void>;
56
+ }
57
+ export declare function touch(): Promise<void>;
58
+ export {};