@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,340 @@
1
+ import { describe, expect, test } from 'vitest';
2
+ import { StaticKeyCollector } from '../../src/auth/StaticKeyCollector.js';
3
+ import * as jose from 'jose';
4
+ import { KeyStore } from '../../src/auth/KeyStore.js';
5
+ import { KeySpec } from '../../src/auth/KeySpec.js';
6
+ import { RemoteJWKSCollector } from '../../src/auth/RemoteJWKSCollector.js';
7
+ import { KeyResult } from '../../src/auth/KeyCollector.js';
8
+ import { CachedKeyCollector } from '../../src/auth/CachedKeyCollector.js';
9
+
10
+ const publicKey: jose.JWK = {
11
+ use: 'sig',
12
+ kty: 'RSA',
13
+ e: 'AQAB',
14
+ kid: 'f2e82732b971a135cf1416e8b46dae04d80894e7',
15
+ alg: 'RS256',
16
+ n: 'v7wW9w5vzvACxbo2Ldqt0IHBy0LCloQvnfIr-nhEKmqgBJeBgF2cZSGz0Fe-grRaAvhhDrxaOft2JvZlbUM8vFFnxx-52dYViDBxv8vDxmV1HeEGV69DYrGxnsOLrHQWKkPSeyxtidiwGrNVYuyC21PG1heScTYppxVSHBUh_D9di56ql16Xytv97FJHeBtEYUmyzLQsWGhfzuLBwYSSuZxia4p3-azlztHisht4Ai1KYpX0HWLjh9NGIMzimk2cNdKZjIO1Mm4Tu5S1z9dCauZdocpE5csFHyeLHY3oeXFNgl9GanyM9IAg-0T5QLJA-C6M9lUO4WuVmOtLM_iGlw'
17
+ };
18
+
19
+ const sharedKey: jose.JWK = {
20
+ kid: 'k1',
21
+ alg: 'HS256',
22
+ kty: 'oct',
23
+ k: Buffer.from('mysecret1', 'utf-8').toString('base64url')
24
+ };
25
+
26
+ const sharedKey2: jose.JWK = {
27
+ alg: 'HS256',
28
+ kty: 'oct',
29
+ k: Buffer.from('mysecret2', 'utf-8').toString('base64url')
30
+ };
31
+
32
+ describe('JWT Auth', () => {
33
+ test('KeyStore basics', async () => {
34
+ const keys = await StaticKeyCollector.importKeys([sharedKey]);
35
+ const store = new KeyStore(keys);
36
+ const signKey = (await jose.importJWK(sharedKey)) as jose.KeyLike;
37
+ const signedJwt = await new jose.SignJWT({})
38
+ .setProtectedHeader({ alg: 'HS256', kid: 'k1' })
39
+ .setSubject('f1')
40
+ .setIssuedAt()
41
+ .setIssuer('tester')
42
+ .setAudience('tests')
43
+ .setExpirationTime('5m')
44
+ .sign(signKey);
45
+
46
+ const verified = await store.verifyJwt(signedJwt, {
47
+ defaultAudiences: ['tests'],
48
+ maxAge: '6m'
49
+ });
50
+ expect(verified.sub).toEqual('f1');
51
+ await expect(
52
+ store.verifyJwt(signedJwt, {
53
+ defaultAudiences: ['other'],
54
+ maxAge: '6m'
55
+ })
56
+ ).rejects.toThrow('unexpected "aud" claim value');
57
+
58
+ await expect(
59
+ store.verifyJwt(signedJwt, {
60
+ defaultAudiences: [],
61
+ maxAge: '6m'
62
+ })
63
+ ).rejects.toThrow('unexpected "aud" claim value');
64
+
65
+ await expect(
66
+ store.verifyJwt(signedJwt, {
67
+ defaultAudiences: ['tests'],
68
+ maxAge: '1m'
69
+ })
70
+ ).rejects.toThrow('Token must expire in a maximum of');
71
+
72
+ const signedJwt2 = await new jose.SignJWT({})
73
+ .setProtectedHeader({ alg: 'HS256', kid: 'k1' })
74
+ .setIssuedAt()
75
+ .setIssuer('tester')
76
+ .setAudience('tests')
77
+ .setExpirationTime('5m')
78
+ .sign(signKey);
79
+
80
+ await expect(
81
+ store.verifyJwt(signedJwt2, {
82
+ defaultAudiences: ['tests'],
83
+ maxAge: '5m'
84
+ })
85
+ ).rejects.toThrow('missing required "sub" claim');
86
+ });
87
+
88
+ test('Algorithm validation', async () => {
89
+ const keys = await StaticKeyCollector.importKeys([publicKey]);
90
+ const store = new KeyStore(keys);
91
+
92
+ // Bad attempt at signing token with rsa public key
93
+ const spoofedKey: jose.JWK = {
94
+ kty: 'oct',
95
+ kid: publicKey.kid!,
96
+ alg: 'HS256',
97
+ k: publicKey.n!
98
+ };
99
+ const signKey = (await jose.importJWK(spoofedKey)) as jose.KeyLike;
100
+
101
+ const signedJwt = await new jose.SignJWT({})
102
+ .setProtectedHeader({ alg: 'HS256', kid: publicKey.kid! })
103
+ .setSubject('f1')
104
+ .setIssuedAt()
105
+ .setIssuer('tester')
106
+ .setAudience('tests')
107
+ .setExpirationTime('5m')
108
+ .sign(signKey);
109
+
110
+ await expect(
111
+ store.verifyJwt(signedJwt, {
112
+ defaultAudiences: ['tests'],
113
+ maxAge: '6m'
114
+ })
115
+ ).rejects.toThrow('Unexpected token algorithm HS256');
116
+ });
117
+
118
+ test('key selection for key with kid', async () => {
119
+ const keys = await StaticKeyCollector.importKeys([publicKey, sharedKey, sharedKey2]);
120
+ const store = new KeyStore(keys);
121
+ const signKey = (await jose.importJWK(sharedKey)) as jose.KeyLike;
122
+ const signKey2 = (await jose.importJWK(sharedKey2)) as jose.KeyLike;
123
+
124
+ // No kid
125
+ const signedJwt = await new jose.SignJWT({})
126
+ .setProtectedHeader({ alg: 'HS256' })
127
+ .setSubject('f1')
128
+ .setIssuedAt()
129
+ .setIssuer('tester')
130
+ .setAudience('tests')
131
+ .setExpirationTime('5m')
132
+ .sign(signKey);
133
+
134
+ await expect(
135
+ store.verifyJwt(signedJwt, {
136
+ defaultAudiences: ['tests'],
137
+ maxAge: '6m'
138
+ })
139
+ ).rejects.toThrow(
140
+ 'Could not find an appropriate key in the keystore. The key is missing or no key matched the token KID'
141
+ );
142
+
143
+ // Wrong kid
144
+ const signedJwt2 = await new jose.SignJWT({})
145
+ .setProtectedHeader({ alg: 'HS256', kid: 'other' })
146
+ .setSubject('f1')
147
+ .setIssuedAt()
148
+ .setIssuer('tester')
149
+ .setAudience('tests')
150
+ .setExpirationTime('5m')
151
+ .sign(signKey);
152
+
153
+ await expect(
154
+ store.verifyJwt(signedJwt2, {
155
+ defaultAudiences: ['tests'],
156
+ maxAge: '6m'
157
+ })
158
+ ).rejects.toThrow(
159
+ 'Could not find an appropriate key in the keystore. The key is missing or no key matched the token KID'
160
+ );
161
+
162
+ // No kid, matches sharedKey2
163
+ const signedJwt3 = await new jose.SignJWT({})
164
+ .setProtectedHeader({ alg: 'HS256' })
165
+ .setSubject('f1')
166
+ .setIssuedAt()
167
+ .setIssuer('tester')
168
+ .setAudience('tests')
169
+ .setExpirationTime('5m')
170
+ .sign(signKey2);
171
+
172
+ await expect(
173
+ store.verifyJwt(signedJwt3, {
174
+ defaultAudiences: ['tests'],
175
+ maxAge: '6m'
176
+ })
177
+ ).resolves.toMatchObject({ sub: 'f1' });
178
+
179
+ // Random kid, matches sharedKey2
180
+ const signedJwt4 = await new jose.SignJWT({})
181
+ .setProtectedHeader({ alg: 'HS256', kid: 'other' })
182
+ .setSubject('f1')
183
+ .setIssuedAt()
184
+ .setIssuer('tester')
185
+ .setAudience('tests')
186
+ .setExpirationTime('5m')
187
+ .sign(signKey2);
188
+
189
+ await expect(
190
+ store.verifyJwt(signedJwt4, {
191
+ defaultAudiences: ['tests'],
192
+ maxAge: '6m'
193
+ })
194
+ ).resolves.toMatchObject({ sub: 'f1' });
195
+ });
196
+
197
+ test('KeyOptions', async () => {
198
+ const keys = new StaticKeyCollector([
199
+ await KeySpec.importKey(sharedKey, {
200
+ // This overrides the default validation options
201
+ requiresAudience: ['other'],
202
+ maxLifetimeSeconds: 3600
203
+ })
204
+ ]);
205
+ const store = new KeyStore(keys);
206
+ const signKey = (await jose.importJWK(sharedKey)) as jose.KeyLike;
207
+ const signedJwt = await new jose.SignJWT({})
208
+ .setProtectedHeader({ alg: 'HS256', kid: 'k1' })
209
+ .setSubject('f1')
210
+ .setIssuedAt()
211
+ .setIssuer('tester')
212
+ .setAudience('other')
213
+ .setExpirationTime('50m')
214
+ .sign(signKey);
215
+
216
+ const verified = await store.verifyJwt(signedJwt, {
217
+ defaultAudiences: ['tests'],
218
+ maxAge: '6m'
219
+ });
220
+ expect(verified.sub).toEqual('f1');
221
+
222
+ const signedJwt2 = await new jose.SignJWT({})
223
+ .setProtectedHeader({ alg: 'HS256', kid: 'k1' })
224
+ .setSubject('f1')
225
+ .setIssuedAt()
226
+ .setIssuer('tester')
227
+ .setAudience('tests') // Doesn't match KeyOptions audience
228
+ .setExpirationTime('50m')
229
+ .sign(signKey);
230
+
231
+ await expect(
232
+ store.verifyJwt(signedJwt2, {
233
+ defaultAudiences: ['tests'],
234
+ maxAge: '6m'
235
+ })
236
+ ).rejects.toThrow('unexpected "aud" claim value');
237
+
238
+ const signedJwt3 = await new jose.SignJWT({})
239
+ .setProtectedHeader({ alg: 'HS256', kid: 'k1' })
240
+ .setSubject('f1')
241
+ .setIssuedAt()
242
+ .setIssuer('tester')
243
+ .setAudience('other')
244
+ .setExpirationTime('70m') // longer than KeyOptions expiration
245
+ .sign(signKey);
246
+
247
+ await expect(
248
+ store.verifyJwt(signedJwt3, {
249
+ defaultAudiences: ['tests'],
250
+ maxAge: '6m'
251
+ })
252
+ ).rejects.toThrow('Token must expire in a maximum of');
253
+ });
254
+
255
+ test('http', async () => {
256
+ // Not ideal to rely on an external endpoint for tests, but it is good to test that this
257
+ // one actually works.
258
+ const remote = new RemoteJWKSCollector(
259
+ 'https://www.googleapis.com/service_accounts/v1/jwk/securetoken@system.gserviceaccount.com'
260
+ );
261
+ const { keys, errors } = await remote.getKeys();
262
+ expect(errors).toEqual([]);
263
+ expect(keys.length).toBeGreaterThanOrEqual(1);
264
+
265
+ const invalid = new RemoteJWKSCollector('https://localhost/.well-known/jwks.json', {
266
+ block_local_ip: true
267
+ });
268
+ expect(invalid.getKeys()).rejects.toThrow('IPs in this range are not supported');
269
+ });
270
+
271
+ test('http not blocking local IPs', async () => {
272
+ // Not ideal to rely on an external endpoint for tests, but it is good to test that this
273
+ // one actually works.
274
+ const remote = new RemoteJWKSCollector(
275
+ 'https://www.googleapis.com/service_accounts/v1/jwk/securetoken@system.gserviceaccount.com'
276
+ );
277
+ const { keys, errors } = await remote.getKeys();
278
+ expect(errors).toEqual([]);
279
+ expect(keys.length).toBeGreaterThanOrEqual(1);
280
+
281
+ const invalid = new RemoteJWKSCollector('https://localhost/.well-known/jwks.json');
282
+ // Should try and fetch
283
+ expect(invalid.getKeys()).rejects.toThrow('ECONNREFUSED');
284
+ });
285
+
286
+ test('caching', async () => {
287
+ let currentResponse: Promise<KeyResult>;
288
+
289
+ const cached = new CachedKeyCollector({
290
+ async getKeys() {
291
+ return currentResponse;
292
+ }
293
+ });
294
+
295
+ currentResponse = Promise.resolve({
296
+ errors: [],
297
+ keys: [await KeySpec.importKey(publicKey)]
298
+ });
299
+
300
+ let key = (await cached.getKeys()).keys[0];
301
+ expect(key.kid).toEqual(publicKey.kid!);
302
+
303
+ currentResponse = undefined as any;
304
+
305
+ key = (await cached.getKeys()).keys[0];
306
+ expect(key.kid).toEqual(publicKey.kid!);
307
+
308
+ cached.addTimeForTests(301_000);
309
+ currentResponse = Promise.reject('refresh failed');
310
+
311
+ // Uses the promise, refreshes in the background
312
+ let response = await cached.getKeys();
313
+ expect(response.keys[0].kid).toEqual(publicKey.kid!);
314
+ expect(response.errors).toEqual([]);
315
+
316
+ // Wait for refresh to finish
317
+ await cached.addTimeForTests(0);
318
+ response = await cached.getKeys();
319
+ // Still have the cached key, but also have the error
320
+ expect(response.keys[0].kid).toEqual(publicKey.kid!);
321
+ expect(response.errors[0].message).toMatch('Failed to fetch');
322
+
323
+ await cached.addTimeForTests(3601_000);
324
+ response = await cached.getKeys();
325
+
326
+ // Now the keys have expired, and the request still fails
327
+ expect(response.keys).toEqual([]);
328
+ expect(response.errors[0].message).toMatch('Failed to fetch');
329
+
330
+ currentResponse = Promise.resolve({
331
+ errors: [],
332
+ keys: [await KeySpec.importKey(publicKey)]
333
+ });
334
+
335
+ // After a delay, we can refresh again
336
+ await cached.addTimeForTests(30_000);
337
+ key = (await cached.getKeys()).keys[0];
338
+ expect(key.kid).toEqual(publicKey.kid!);
339
+ });
340
+ });
@@ -0,0 +1,156 @@
1
+ import { AsyncIterableX, interval } from 'ix/asynciterable/index.js';
2
+ import { delayEach } from 'ix/asynciterable/operators/delayeach.js';
3
+ import { take } from 'ix/asynciterable/operators/take.js';
4
+ import { wrapWithAbort } from 'ix/asynciterable/operators/withabort.js';
5
+ import { toArray } from 'ix/asynciterable/toarray.js';
6
+ import * as timers from 'timers/promises';
7
+ import { describe, expect, test } from 'vitest';
8
+ import { BroadcastIterable, IterableSource } from '../../src/sync/BroadcastIterable.js';
9
+
10
+ describe('BroadcastIterable', () => {
11
+ test('should iterate', async () => {
12
+ const range = AsyncIterableX.from([1, 2, 3]);
13
+ const broadcast = new BroadcastIterable(() => range);
14
+
15
+ const results = await toArray(broadcast);
16
+ expect(results).toEqual([1, 2, 3]);
17
+ expect(broadcast.active).toBe(false);
18
+ });
19
+
20
+ test('should skip values if sink is slow', async () => {
21
+ const range = AsyncIterableX.from([1, 2, 3]);
22
+ const broadcast = new BroadcastIterable(() => range);
23
+
24
+ // Delay reading each element
25
+ const delayed = delayEach(1)(broadcast);
26
+ const results = await toArray(delayed);
27
+
28
+ // We only get a single value, then done.
29
+ expect(results).toEqual([1]);
30
+ expect(broadcast.active).toBe(false);
31
+ });
32
+
33
+ test('should abort', async () => {
34
+ const range = AsyncIterableX.from([1, 2, 3]);
35
+ let recordedSignal: AbortSignal | undefined;
36
+ const broadcast = new BroadcastIterable((signal) => {
37
+ recordedSignal = signal;
38
+ return range;
39
+ });
40
+
41
+ const controller = new AbortController();
42
+ const iter = broadcast[Symbol.asyncIterator](controller.signal);
43
+ await iter.next();
44
+ controller.abort();
45
+ await expect(iter.next()).rejects.toThrow('The operation has been aborted');
46
+ expect(recordedSignal!.aborted).toEqual(true);
47
+ });
48
+
49
+ test('should handle indefinite sources', async () => {
50
+ const source: IterableSource<number> = (signal) => {
51
+ return wrapWithAbort(interval(1), signal);
52
+ };
53
+
54
+ const broadcast = new BroadcastIterable(source);
55
+
56
+ const delayed = delayEach(10)(broadcast);
57
+ expect(broadcast.active).toBe(false);
58
+ const results = await toArray(take(5)(delayed));
59
+
60
+ expect(results.length).toEqual(5);
61
+ expect(results[0]).toEqual(0);
62
+ expect(results[4]).toBeGreaterThan(10);
63
+ expect(results[4]).toBeLessThan(40);
64
+
65
+ expect(broadcast.active).toBe(false);
66
+ });
67
+
68
+ test('should handle multiple subscribers', async () => {
69
+ let sourceIndex = 0;
70
+ const source = async function* (signal: AbortSignal) {
71
+ // Test value out by 1000 means it may have used the wrong iteration of the source
72
+ const base = (sourceIndex += 1000);
73
+ const abortedPromise = new Promise((resolve) => {
74
+ signal.addEventListener('abort', resolve, { once: true });
75
+ });
76
+ for (let i = 0; !signal.aborted; i++) {
77
+ yield base + i;
78
+ await Promise.race([abortedPromise, timers.setTimeout(1)]);
79
+ }
80
+ // Test value out by 100 means this wasn't reached
81
+ sourceIndex += 100;
82
+ };
83
+
84
+ const broadcast = new BroadcastIterable(source);
85
+
86
+ const delayed1 = delayEach(9)(broadcast);
87
+ const delayed2 = delayEach(10)(broadcast);
88
+ expect(broadcast.active).toBe(false);
89
+ const results1Promise = toArray(take(5)(delayed1));
90
+ const results2Promise = toArray(take(5)(delayed2));
91
+ const [results1, results2] = [await results1Promise, await results2Promise];
92
+
93
+ expect(broadcast.active).toBe(false);
94
+
95
+ expect(results1.length).toEqual(5);
96
+ expect(results1[0]).toEqual(1000);
97
+ expect(results1[4]).toBeGreaterThan(1010);
98
+ expect(results1[4]).toBeLessThan(1045);
99
+
100
+ expect(results2.length).toEqual(5);
101
+ expect(results2[0]).toEqual(1000);
102
+ expect(results2[4]).toBeGreaterThan(1010);
103
+ expect(results2[4]).toBeLessThan(1045);
104
+
105
+ // This starts a new source
106
+ const delayed3 = delayEach(10)(broadcast);
107
+ const results3 = await toArray(take(5)(delayed3));
108
+ expect(results3.length).toEqual(5);
109
+ expect(results3[0]).toEqual(2100);
110
+ expect(results3[4]).toBeGreaterThan(2110);
111
+ expect(results3[4]).toBeLessThan(2145);
112
+ });
113
+
114
+ test('should handle errors on multiple subscribers', async () => {
115
+ let sourceIndex = 0;
116
+ const source = async function* (signal: AbortSignal) {
117
+ // Test value out by 1000 means it may have used the wrong iteration of the source
118
+ const base = (sourceIndex += 1000);
119
+ const abortedPromise = new Promise((resolve) => {
120
+ signal.addEventListener('abort', resolve, { once: true });
121
+ });
122
+ for (let i = 0; !signal.aborted; i++) {
123
+ if (base + i == 1005) {
124
+ throw new Error('simulated failure');
125
+ }
126
+ yield base + i;
127
+ await Promise.race([abortedPromise, timers.setTimeout(1)]);
128
+ }
129
+ // Test value out by 100 means this wasn't reached
130
+ sourceIndex += 100;
131
+ };
132
+
133
+ const broadcast = new BroadcastIterable(source);
134
+
135
+ const delayed1 = delayEach(9)(broadcast);
136
+ const delayed2 = delayEach(10)(broadcast);
137
+ expect(broadcast.active).toBe(false);
138
+ const results1Promise = toArray(take(5)(delayed1)) as Promise<number[]>;
139
+ const results2Promise = toArray(take(5)(delayed2)) as Promise<number[]>;
140
+
141
+ const [r1, r2] = await Promise.allSettled([results1Promise, results2Promise]);
142
+
143
+ expect(r1).toEqual({ status: 'rejected', reason: new Error('simulated failure') });
144
+ expect(r2).toEqual({ status: 'rejected', reason: new Error('simulated failure') });
145
+
146
+ expect(broadcast.active).toBe(false);
147
+
148
+ // This starts a new source
149
+ const delayed3 = delayEach(10)(broadcast);
150
+ const results3 = await toArray(take(5)(delayed3));
151
+ expect(results3.length).toEqual(5);
152
+ expect(results3[0]).toEqual(2000);
153
+ expect(results3[4]).toBeGreaterThan(2010);
154
+ expect(results3[4]).toBeLessThan(2045);
155
+ });
156
+ });