@powersync/service-core 0.0.0-dev-20240718134716 → 0.0.0-dev-20240918082156

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 (352) hide show
  1. package/CHANGELOG.md +89 -6
  2. package/dist/api/RouteAPI.d.ts +68 -0
  3. package/dist/api/RouteAPI.js +2 -0
  4. package/dist/api/RouteAPI.js.map +1 -0
  5. package/dist/api/api-index.d.ts +1 -0
  6. package/dist/api/api-index.js +1 -0
  7. package/dist/api/api-index.js.map +1 -1
  8. package/dist/api/diagnostics.d.ts +4 -4
  9. package/dist/api/diagnostics.js +11 -65
  10. package/dist/api/diagnostics.js.map +1 -1
  11. package/dist/api/schema.d.ts +3 -5
  12. package/dist/api/schema.js +9 -79
  13. package/dist/api/schema.js.map +1 -1
  14. package/dist/auth/KeyStore.d.ts +7 -4
  15. package/dist/auth/KeyStore.js +1 -1
  16. package/dist/auth/KeyStore.js.map +1 -1
  17. package/dist/auth/auth-index.d.ts +0 -1
  18. package/dist/auth/auth-index.js +0 -1
  19. package/dist/auth/auth-index.js.map +1 -1
  20. package/dist/entry/cli-entry.js +4 -2
  21. package/dist/entry/cli-entry.js.map +1 -1
  22. package/dist/entry/commands/compact-action.d.ts +2 -0
  23. package/dist/entry/commands/compact-action.js +52 -0
  24. package/dist/entry/commands/compact-action.js.map +1 -0
  25. package/dist/entry/commands/migrate-action.js +4 -5
  26. package/dist/entry/commands/migrate-action.js.map +1 -1
  27. package/dist/entry/commands/teardown-action.js +2 -2
  28. package/dist/entry/commands/teardown-action.js.map +1 -1
  29. package/dist/entry/entry-index.d.ts +1 -0
  30. package/dist/entry/entry-index.js +1 -0
  31. package/dist/entry/entry-index.js.map +1 -1
  32. package/dist/index.d.ts +4 -2
  33. package/dist/index.js +4 -2
  34. package/dist/index.js.map +1 -1
  35. package/dist/metrics/Metrics.d.ts +6 -5
  36. package/dist/metrics/Metrics.js +53 -10
  37. package/dist/metrics/Metrics.js.map +1 -1
  38. package/dist/migrations/db/migrations/1684951997326-init.d.ts +2 -2
  39. package/dist/migrations/db/migrations/1684951997326-init.js +4 -2
  40. package/dist/migrations/db/migrations/1684951997326-init.js.map +1 -1
  41. package/dist/migrations/db/migrations/1702295701188-sync-rule-state.d.ts +2 -2
  42. package/dist/migrations/db/migrations/1702295701188-sync-rule-state.js +4 -2
  43. package/dist/migrations/db/migrations/1702295701188-sync-rule-state.js.map +1 -1
  44. package/dist/migrations/db/migrations/1711543888062-write-checkpoint-index.d.ts +2 -2
  45. package/dist/migrations/db/migrations/1711543888062-write-checkpoint-index.js +4 -2
  46. package/dist/migrations/db/migrations/1711543888062-write-checkpoint-index.js.map +1 -1
  47. package/dist/migrations/migrations.d.ts +8 -0
  48. package/dist/migrations/migrations.js +19 -7
  49. package/dist/migrations/migrations.js.map +1 -1
  50. package/dist/modules/AbstractModule.d.ts +26 -0
  51. package/dist/modules/AbstractModule.js +11 -0
  52. package/dist/modules/AbstractModule.js.map +1 -0
  53. package/dist/modules/ModuleManager.d.ts +11 -0
  54. package/dist/modules/ModuleManager.js +32 -0
  55. package/dist/modules/ModuleManager.js.map +1 -0
  56. package/dist/modules/modules-index.d.ts +2 -0
  57. package/dist/modules/modules-index.js +3 -0
  58. package/dist/modules/modules-index.js.map +1 -0
  59. package/dist/replication/AbstractReplicationJob.d.ts +38 -0
  60. package/dist/replication/AbstractReplicationJob.js +51 -0
  61. package/dist/replication/AbstractReplicationJob.js.map +1 -0
  62. package/dist/replication/AbstractReplicator.d.ts +53 -0
  63. package/dist/replication/AbstractReplicator.js +187 -0
  64. package/dist/replication/AbstractReplicator.js.map +1 -0
  65. package/dist/replication/ErrorRateLimiter.d.ts +0 -9
  66. package/dist/replication/ErrorRateLimiter.js +1 -42
  67. package/dist/replication/ErrorRateLimiter.js.map +1 -1
  68. package/dist/replication/ReplicationEngine.d.ts +18 -0
  69. package/dist/replication/ReplicationEngine.js +41 -0
  70. package/dist/replication/ReplicationEngine.js.map +1 -0
  71. package/dist/replication/ReplicationModule.d.ts +39 -0
  72. package/dist/replication/ReplicationModule.js +65 -0
  73. package/dist/replication/ReplicationModule.js.map +1 -0
  74. package/dist/replication/replication-index.d.ts +4 -6
  75. package/dist/replication/replication-index.js +4 -6
  76. package/dist/replication/replication-index.js.map +1 -1
  77. package/dist/routes/RouterEngine.d.ts +42 -0
  78. package/dist/routes/RouterEngine.js +80 -0
  79. package/dist/routes/RouterEngine.js.map +1 -0
  80. package/dist/routes/auth.d.ts +2 -2
  81. package/dist/routes/auth.js +11 -11
  82. package/dist/routes/auth.js.map +1 -1
  83. package/dist/routes/configure-fastify.d.ts +737 -0
  84. package/dist/routes/configure-fastify.js +57 -0
  85. package/dist/routes/configure-fastify.js.map +1 -0
  86. package/dist/routes/configure-rsocket.d.ts +13 -0
  87. package/dist/routes/configure-rsocket.js +47 -0
  88. package/dist/routes/configure-rsocket.js.map +1 -0
  89. package/dist/routes/endpoints/admin.d.ts +0 -34
  90. package/dist/routes/endpoints/admin.js +48 -89
  91. package/dist/routes/endpoints/admin.js.map +1 -1
  92. package/dist/routes/endpoints/checkpointing.d.ts +56 -16
  93. package/dist/routes/endpoints/checkpointing.js +33 -12
  94. package/dist/routes/endpoints/checkpointing.js.map +1 -1
  95. package/dist/routes/endpoints/route-endpoints-index.d.ts +0 -1
  96. package/dist/routes/endpoints/route-endpoints-index.js +0 -1
  97. package/dist/routes/endpoints/route-endpoints-index.js.map +1 -1
  98. package/dist/routes/endpoints/socket-route.js +46 -39
  99. package/dist/routes/endpoints/socket-route.js.map +1 -1
  100. package/dist/routes/endpoints/sync-rules.d.ts +1 -1
  101. package/dist/routes/endpoints/sync-rules.js +32 -23
  102. package/dist/routes/endpoints/sync-rules.js.map +1 -1
  103. package/dist/routes/endpoints/sync-stream.d.ts +10 -0
  104. package/dist/routes/endpoints/sync-stream.js +17 -13
  105. package/dist/routes/endpoints/sync-stream.js.map +1 -1
  106. package/dist/routes/route-register.d.ts +1 -1
  107. package/dist/routes/route-register.js +1 -1
  108. package/dist/routes/route-register.js.map +1 -1
  109. package/dist/routes/router-socket.d.ts +5 -4
  110. package/dist/routes/router-socket.js +2 -1
  111. package/dist/routes/router-socket.js.map +1 -1
  112. package/dist/routes/router.d.ts +7 -2
  113. package/dist/routes/router.js.map +1 -1
  114. package/dist/routes/routes-index.d.ts +3 -0
  115. package/dist/routes/routes-index.js +3 -0
  116. package/dist/routes/routes-index.js.map +1 -1
  117. package/dist/runner/teardown.js +47 -76
  118. package/dist/runner/teardown.js.map +1 -1
  119. package/dist/storage/BucketStorage.d.ts +61 -20
  120. package/dist/storage/BucketStorage.js +0 -10
  121. package/dist/storage/BucketStorage.js.map +1 -1
  122. package/dist/storage/MongoBucketStorage.d.ts +4 -4
  123. package/dist/storage/MongoBucketStorage.js +19 -24
  124. package/dist/storage/MongoBucketStorage.js.map +1 -1
  125. package/dist/storage/SourceEntity.d.ts +20 -0
  126. package/dist/storage/SourceEntity.js +2 -0
  127. package/dist/storage/SourceEntity.js.map +1 -0
  128. package/dist/storage/SourceTable.d.ts +4 -5
  129. package/dist/storage/SourceTable.js +3 -4
  130. package/dist/storage/SourceTable.js.map +1 -1
  131. package/dist/storage/StorageEngine.d.ts +24 -0
  132. package/dist/storage/StorageEngine.js +43 -0
  133. package/dist/storage/StorageEngine.js.map +1 -0
  134. package/dist/storage/StorageProvider.d.ts +21 -0
  135. package/dist/storage/StorageProvider.js +2 -0
  136. package/dist/storage/StorageProvider.js.map +1 -0
  137. package/dist/storage/mongo/MongoBucketBatch.d.ts +1 -1
  138. package/dist/storage/mongo/MongoBucketBatch.js +6 -7
  139. package/dist/storage/mongo/MongoBucketBatch.js.map +1 -1
  140. package/dist/storage/mongo/MongoCompactor.d.ts +40 -0
  141. package/dist/storage/mongo/MongoCompactor.js +293 -0
  142. package/dist/storage/mongo/MongoCompactor.js.map +1 -0
  143. package/dist/storage/mongo/MongoPersistedSyncRulesContent.d.ts +2 -2
  144. package/dist/storage/mongo/MongoPersistedSyncRulesContent.js +2 -2
  145. package/dist/storage/mongo/MongoPersistedSyncRulesContent.js.map +1 -1
  146. package/dist/storage/mongo/MongoStorageProvider.d.ts +5 -0
  147. package/dist/storage/mongo/MongoStorageProvider.js +26 -0
  148. package/dist/storage/mongo/MongoStorageProvider.js.map +1 -0
  149. package/dist/storage/mongo/MongoSyncBucketStorage.d.ts +9 -7
  150. package/dist/storage/mongo/MongoSyncBucketStorage.js +43 -28
  151. package/dist/storage/mongo/MongoSyncBucketStorage.js.map +1 -1
  152. package/dist/storage/mongo/MongoSyncRulesLock.js +1 -1
  153. package/dist/storage/mongo/MongoSyncRulesLock.js.map +1 -1
  154. package/dist/storage/mongo/OperationBatch.d.ts +7 -3
  155. package/dist/storage/mongo/OperationBatch.js +16 -7
  156. package/dist/storage/mongo/OperationBatch.js.map +1 -1
  157. package/dist/storage/mongo/PersistedBatch.d.ts +3 -3
  158. package/dist/storage/mongo/PersistedBatch.js +2 -2
  159. package/dist/storage/mongo/PersistedBatch.js.map +1 -1
  160. package/dist/storage/mongo/models.d.ts +17 -7
  161. package/dist/storage/mongo/models.js.map +1 -1
  162. package/dist/storage/mongo/util.d.ts +14 -0
  163. package/dist/storage/mongo/util.js +70 -0
  164. package/dist/storage/mongo/util.js.map +1 -1
  165. package/dist/storage/storage-index.d.ts +5 -2
  166. package/dist/storage/storage-index.js +5 -2
  167. package/dist/storage/storage-index.js.map +1 -1
  168. package/dist/sync/RequestTracker.js +2 -3
  169. package/dist/sync/RequestTracker.js.map +1 -1
  170. package/dist/sync/sync-index.d.ts +1 -0
  171. package/dist/sync/sync-index.js +1 -0
  172. package/dist/sync/sync-index.js.map +1 -1
  173. package/dist/sync/sync.d.ts +2 -1
  174. package/dist/sync/sync.js +56 -17
  175. package/dist/sync/sync.js.map +1 -1
  176. package/dist/system/ServiceContext.d.ts +37 -0
  177. package/dist/system/ServiceContext.js +48 -0
  178. package/dist/system/ServiceContext.js.map +1 -0
  179. package/dist/system/system-index.d.ts +1 -1
  180. package/dist/system/system-index.js +1 -1
  181. package/dist/system/system-index.js.map +1 -1
  182. package/dist/util/config/collectors/config-collector.d.ts +12 -0
  183. package/dist/util/config/collectors/config-collector.js +43 -0
  184. package/dist/util/config/collectors/config-collector.js.map +1 -1
  185. package/dist/util/config/compound-config-collector.d.ts +10 -29
  186. package/dist/util/config/compound-config-collector.js +28 -84
  187. package/dist/util/config/compound-config-collector.js.map +1 -1
  188. package/dist/util/config/sync-rules/sync-rules-provider.d.ts +9 -0
  189. package/dist/util/config/sync-rules/sync-rules-provider.js +15 -0
  190. package/dist/util/config/sync-rules/sync-rules-provider.js.map +1 -0
  191. package/dist/util/config/types.d.ts +6 -4
  192. package/dist/util/config/types.js.map +1 -1
  193. package/dist/util/config.d.ts +3 -4
  194. package/dist/util/config.js +5 -20
  195. package/dist/util/config.js.map +1 -1
  196. package/dist/util/protocol-types.d.ts +4 -0
  197. package/dist/util/protocol-types.js +5 -1
  198. package/dist/util/protocol-types.js.map +1 -1
  199. package/dist/util/util-index.d.ts +3 -6
  200. package/dist/util/util-index.js +3 -6
  201. package/dist/util/util-index.js.map +1 -1
  202. package/dist/util/utils.d.ts +10 -6
  203. package/dist/util/utils.js +45 -25
  204. package/dist/util/utils.js.map +1 -1
  205. package/package.json +7 -7
  206. package/src/api/RouteAPI.ts +78 -0
  207. package/src/api/api-index.ts +1 -0
  208. package/src/api/diagnostics.ts +16 -71
  209. package/src/api/schema.ts +13 -89
  210. package/src/auth/KeyStore.ts +9 -6
  211. package/src/auth/auth-index.ts +0 -1
  212. package/src/entry/cli-entry.ts +4 -2
  213. package/src/entry/commands/compact-action.ts +57 -0
  214. package/src/entry/commands/migrate-action.ts +5 -8
  215. package/src/entry/commands/teardown-action.ts +2 -2
  216. package/src/entry/entry-index.ts +1 -0
  217. package/src/index.ts +5 -2
  218. package/src/metrics/Metrics.ts +70 -15
  219. package/src/migrations/db/migrations/1684951997326-init.ts +9 -4
  220. package/src/migrations/db/migrations/1702295701188-sync-rule-state.ts +7 -4
  221. package/src/migrations/db/migrations/1711543888062-write-checkpoint-index.ts +6 -4
  222. package/src/migrations/migrations.ts +24 -8
  223. package/src/modules/AbstractModule.ts +37 -0
  224. package/src/modules/ModuleManager.ts +34 -0
  225. package/src/modules/modules-index.ts +2 -0
  226. package/src/replication/AbstractReplicationJob.ts +79 -0
  227. package/src/replication/AbstractReplicator.ts +227 -0
  228. package/src/replication/ErrorRateLimiter.ts +0 -44
  229. package/src/replication/ReplicationEngine.ts +43 -0
  230. package/src/replication/ReplicationModule.ts +101 -0
  231. package/src/replication/replication-index.ts +4 -6
  232. package/src/routes/RouterEngine.ts +120 -0
  233. package/src/routes/auth.ts +21 -12
  234. package/src/routes/configure-fastify.ts +101 -0
  235. package/src/routes/configure-rsocket.ts +60 -0
  236. package/src/routes/endpoints/admin.ts +74 -100
  237. package/src/routes/endpoints/checkpointing.ts +46 -12
  238. package/src/routes/endpoints/route-endpoints-index.ts +0 -1
  239. package/src/routes/endpoints/socket-route.ts +50 -42
  240. package/src/routes/endpoints/sync-rules.ts +41 -25
  241. package/src/routes/endpoints/sync-stream.ts +17 -13
  242. package/src/routes/route-register.ts +2 -2
  243. package/src/routes/router-socket.ts +6 -5
  244. package/src/routes/router.ts +7 -2
  245. package/src/routes/routes-index.ts +3 -0
  246. package/src/runner/teardown.ts +50 -88
  247. package/src/storage/BucketStorage.ts +74 -26
  248. package/src/storage/MongoBucketStorage.ts +23 -26
  249. package/src/storage/SourceEntity.ts +22 -0
  250. package/src/storage/SourceTable.ts +4 -6
  251. package/src/storage/StorageEngine.ts +55 -0
  252. package/src/storage/StorageProvider.ts +27 -0
  253. package/src/storage/mongo/MongoBucketBatch.ts +8 -8
  254. package/src/storage/mongo/MongoCompactor.ts +372 -0
  255. package/src/storage/mongo/MongoPersistedSyncRulesContent.ts +3 -3
  256. package/src/storage/mongo/MongoStorageProvider.ts +31 -0
  257. package/src/storage/mongo/MongoSyncBucketStorage.ts +64 -34
  258. package/src/storage/mongo/MongoSyncRulesLock.ts +1 -1
  259. package/src/storage/mongo/OperationBatch.ts +18 -11
  260. package/src/storage/mongo/PersistedBatch.ts +6 -5
  261. package/src/storage/mongo/models.ts +17 -7
  262. package/src/storage/mongo/util.ts +71 -1
  263. package/src/storage/storage-index.ts +5 -2
  264. package/src/sync/RequestTracker.ts +3 -3
  265. package/src/sync/sync-index.ts +1 -0
  266. package/src/sync/sync.ts +66 -17
  267. package/src/system/ServiceContext.ts +68 -0
  268. package/src/system/system-index.ts +1 -1
  269. package/src/util/config/collectors/config-collector.ts +48 -0
  270. package/src/util/config/compound-config-collector.ts +45 -110
  271. package/src/util/config/sync-rules/sync-rules-provider.ts +18 -0
  272. package/src/util/config/types.ts +6 -5
  273. package/src/util/config.ts +6 -23
  274. package/src/util/protocol-types.ts +6 -1
  275. package/src/util/util-index.ts +3 -6
  276. package/src/util/utils.ts +55 -39
  277. package/test/src/__snapshots__/sync.test.ts.snap +90 -5
  278. package/test/src/auth.test.ts +7 -7
  279. package/test/src/broadcast_iterable.test.ts +1 -1
  280. package/test/src/bucket_validation.test.ts +142 -0
  281. package/test/src/bucket_validation.ts +116 -0
  282. package/test/src/checksum_cache.test.ts +3 -3
  283. package/test/src/compacting.test.ts +216 -0
  284. package/test/src/data_storage.test.ts +275 -204
  285. package/test/src/env.ts +1 -3
  286. package/test/src/merge_iterable.test.ts +1 -6
  287. package/test/src/setup.ts +1 -1
  288. package/test/src/stream_utils.ts +42 -0
  289. package/test/src/sync.test.ts +209 -48
  290. package/test/src/util.ts +110 -55
  291. package/test/tsconfig.json +1 -1
  292. package/tsconfig.tsbuildinfo +1 -1
  293. package/dist/auth/SupabaseKeyCollector.d.ts +0 -22
  294. package/dist/auth/SupabaseKeyCollector.js +0 -61
  295. package/dist/auth/SupabaseKeyCollector.js.map +0 -1
  296. package/dist/replication/PgRelation.d.ts +0 -16
  297. package/dist/replication/PgRelation.js +0 -26
  298. package/dist/replication/PgRelation.js.map +0 -1
  299. package/dist/replication/WalConnection.d.ts +0 -34
  300. package/dist/replication/WalConnection.js +0 -190
  301. package/dist/replication/WalConnection.js.map +0 -1
  302. package/dist/replication/WalStream.d.ts +0 -57
  303. package/dist/replication/WalStream.js +0 -517
  304. package/dist/replication/WalStream.js.map +0 -1
  305. package/dist/replication/WalStreamManager.d.ts +0 -30
  306. package/dist/replication/WalStreamManager.js +0 -198
  307. package/dist/replication/WalStreamManager.js.map +0 -1
  308. package/dist/replication/WalStreamRunner.d.ts +0 -38
  309. package/dist/replication/WalStreamRunner.js +0 -155
  310. package/dist/replication/WalStreamRunner.js.map +0 -1
  311. package/dist/replication/util.d.ts +0 -9
  312. package/dist/replication/util.js +0 -62
  313. package/dist/replication/util.js.map +0 -1
  314. package/dist/routes/endpoints/dev.d.ts +0 -312
  315. package/dist/routes/endpoints/dev.js +0 -172
  316. package/dist/routes/endpoints/dev.js.map +0 -1
  317. package/dist/system/CorePowerSyncSystem.d.ts +0 -23
  318. package/dist/system/CorePowerSyncSystem.js +0 -52
  319. package/dist/system/CorePowerSyncSystem.js.map +0 -1
  320. package/dist/util/PgManager.d.ts +0 -24
  321. package/dist/util/PgManager.js +0 -55
  322. package/dist/util/PgManager.js.map +0 -1
  323. package/dist/util/migration_lib.d.ts +0 -11
  324. package/dist/util/migration_lib.js +0 -64
  325. package/dist/util/migration_lib.js.map +0 -1
  326. package/dist/util/pgwire_utils.d.ts +0 -24
  327. package/dist/util/pgwire_utils.js +0 -117
  328. package/dist/util/pgwire_utils.js.map +0 -1
  329. package/dist/util/populate_test_data.d.ts +0 -8
  330. package/dist/util/populate_test_data.js +0 -65
  331. package/dist/util/populate_test_data.js.map +0 -1
  332. package/src/auth/SupabaseKeyCollector.ts +0 -67
  333. package/src/replication/PgRelation.ts +0 -42
  334. package/src/replication/WalConnection.ts +0 -227
  335. package/src/replication/WalStream.ts +0 -628
  336. package/src/replication/WalStreamManager.ts +0 -213
  337. package/src/replication/WalStreamRunner.ts +0 -180
  338. package/src/replication/util.ts +0 -76
  339. package/src/routes/endpoints/dev.ts +0 -199
  340. package/src/system/CorePowerSyncSystem.ts +0 -64
  341. package/src/util/PgManager.ts +0 -64
  342. package/src/util/migration_lib.ts +0 -79
  343. package/src/util/pgwire_utils.ts +0 -139
  344. package/src/util/populate_test_data.ts +0 -78
  345. package/test/src/__snapshots__/pg_test.test.ts.snap +0 -256
  346. package/test/src/large_batch.test.ts +0 -194
  347. package/test/src/pg_test.test.ts +0 -450
  348. package/test/src/schema_changes.test.ts +0 -545
  349. package/test/src/slow_tests.test.ts +0 -296
  350. package/test/src/validation.test.ts +0 -63
  351. package/test/src/wal_stream.test.ts +0 -314
  352. package/test/src/wal_stream_utils.ts +0 -147
@@ -1,9 +1,9 @@
1
1
  import * as jose from 'jose';
2
2
 
3
3
  import * as auth from '../auth/auth-index.js';
4
+ import { ServiceContext } from '../system/ServiceContext.js';
4
5
  import * as util from '../util/util-index.js';
5
6
  import { BasicRouterRequest, Context, RequestEndpointHandlerPayload } from './router.js';
6
- import { CorePowerSyncSystem } from '../system/CorePowerSyncSystem.js';
7
7
 
8
8
  export function endpoint(req: BasicRouterRequest) {
9
9
  const protocol = req.headers['x-forwarded-proto'] ?? req.protocol;
@@ -108,7 +108,7 @@ export async function authorizeUser(context: Context, authHeader: string = '') {
108
108
  };
109
109
  }
110
110
 
111
- const { context: tokenContext, errors } = await generateContext(context.system, token);
111
+ const { context: tokenContext, errors } = await generateContext(context.service_context, token);
112
112
 
113
113
  if (!tokenContext) {
114
114
  return {
@@ -121,14 +121,14 @@ export async function authorizeUser(context: Context, authHeader: string = '') {
121
121
  return { authorized: true };
122
122
  }
123
123
 
124
- export async function generateContext(system: CorePowerSyncSystem, token: string) {
125
- const config = system.config;
124
+ export async function generateContext(serviceContext: ServiceContext, token: string) {
125
+ const { configuration } = serviceContext;
126
126
 
127
127
  let tokenPayload: auth.JwtPayload;
128
128
  try {
129
- const maxAge = config.token_max_expiration;
130
- tokenPayload = await system.client_keystore.verifyJwt(token, {
131
- defaultAudiences: config.jwt_audiences,
129
+ const maxAge = configuration.token_max_expiration;
130
+ tokenPayload = await configuration.client_keystore.verifyJwt(token, {
131
+ defaultAudiences: configuration.jwt_audiences,
132
132
  maxAge: maxAge
133
133
  });
134
134
  return {
@@ -149,9 +149,14 @@ export async function generateContext(system: CorePowerSyncSystem, token: string
149
149
  * @deprecated
150
150
  */
151
151
  export const authDevUser = async (payload: RequestEndpointHandlerPayload) => {
152
- const context = payload.context;
152
+ const {
153
+ context: {
154
+ service_context: { configuration }
155
+ }
156
+ } = payload;
157
+
153
158
  const token = getTokenFromHeader(payload.request.headers.authorization as string);
154
- if (!context.system.config.dev.demo_auth) {
159
+ if (!configuration.dev.demo_auth) {
155
160
  return {
156
161
  authorized: false,
157
162
  errors: ['Authentication disabled']
@@ -170,7 +175,7 @@ export const authDevUser = async (payload: RequestEndpointHandlerPayload) => {
170
175
 
171
176
  let tokenPayload: auth.JwtPayload;
172
177
  try {
173
- tokenPayload = await context.system.dev_client_keystore.verifyJwt(token, {
178
+ tokenPayload = await configuration.dev_client_keystore.verifyJwt(token, {
174
179
  defaultAudiences: audience,
175
180
  maxAge: '31d'
176
181
  });
@@ -186,8 +191,12 @@ export const authDevUser = async (payload: RequestEndpointHandlerPayload) => {
186
191
  };
187
192
 
188
193
  export const authApi = (payload: RequestEndpointHandlerPayload) => {
189
- const context = payload.context;
190
- const api_keys = context.system.config.api_tokens;
194
+ const {
195
+ context: {
196
+ service_context: { configuration }
197
+ }
198
+ } = payload;
199
+ const api_keys = configuration.api_tokens;
191
200
  if (api_keys.length == 0) {
192
201
  return {
193
202
  authorized: false,
@@ -0,0 +1,101 @@
1
+ import type fastify from 'fastify';
2
+ import { registerFastifyRoutes } from './route-register.js';
3
+
4
+ import * as system from '../system/system-index.js';
5
+
6
+ import { ADMIN_ROUTES } from './endpoints/admin.js';
7
+ import { CHECKPOINT_ROUTES } from './endpoints/checkpointing.js';
8
+ import { SYNC_RULES_ROUTES } from './endpoints/sync-rules.js';
9
+ import { SYNC_STREAM_ROUTES } from './endpoints/sync-stream.js';
10
+ import { createRequestQueueHook, CreateRequestQueueParams } from './hooks.js';
11
+ import { RouteDefinition } from './router.js';
12
+
13
+ /**
14
+ * A list of route definitions to be registered as endpoints.
15
+ * Supplied concurrency limits will be applied to the grouped routes.
16
+ */
17
+ export type RouteRegistrationOptions = {
18
+ routes: RouteDefinition[];
19
+ queue_options: CreateRequestQueueParams;
20
+ };
21
+
22
+ /**
23
+ * HTTP routes separated by API and Sync stream categories.
24
+ * This allows for separate concurrency limits.
25
+ */
26
+ export type RouteDefinitions = {
27
+ api?: Partial<RouteRegistrationOptions>;
28
+ sync_stream?: Partial<RouteRegistrationOptions>;
29
+ };
30
+
31
+ export type FastifyServerConfig = {
32
+ service_context: system.ServiceContext;
33
+ routes?: RouteDefinitions;
34
+ };
35
+
36
+ export const DEFAULT_ROUTE_OPTIONS = {
37
+ api: {
38
+ routes: [...ADMIN_ROUTES, ...CHECKPOINT_ROUTES, ...SYNC_RULES_ROUTES],
39
+ queue_options: {
40
+ concurrency: 10,
41
+ max_queue_depth: 20
42
+ }
43
+ },
44
+ sync_stream: {
45
+ routes: [...SYNC_STREAM_ROUTES],
46
+ queue_options: {
47
+ concurrency: 200,
48
+ max_queue_depth: 0
49
+ }
50
+ }
51
+ };
52
+
53
+ /**
54
+ * Registers default routes on a Fastify server. Consumers can optionally configure
55
+ * concurrency queue limits or override routes.
56
+ */
57
+ export function configureFastifyServer(server: fastify.FastifyInstance, options: FastifyServerConfig) {
58
+ const { service_context, routes = DEFAULT_ROUTE_OPTIONS } = options;
59
+ /**
60
+ * Fastify creates an encapsulated context for each `.register` call.
61
+ * Creating a separate context here to separate the concurrency limits for Admin APIs
62
+ * and Sync Streaming routes.
63
+ * https://github.com/fastify/fastify/blob/main/docs/Reference/Encapsulation.md
64
+ */
65
+ server.register(async function (childContext) {
66
+ registerFastifyRoutes(
67
+ childContext,
68
+ async () => {
69
+ return {
70
+ user_id: undefined,
71
+ service_context
72
+ };
73
+ },
74
+ routes.api?.routes ?? DEFAULT_ROUTE_OPTIONS.api.routes
75
+ );
76
+ // Limit the active concurrent requests
77
+ childContext.addHook(
78
+ 'onRequest',
79
+ createRequestQueueHook(routes.api?.queue_options ?? DEFAULT_ROUTE_OPTIONS.api.queue_options)
80
+ );
81
+ });
82
+
83
+ // Create a separate context for concurrency queueing
84
+ server.register(async function (childContext) {
85
+ registerFastifyRoutes(
86
+ childContext,
87
+ async () => {
88
+ return {
89
+ user_id: undefined,
90
+ service_context
91
+ };
92
+ },
93
+ routes.sync_stream?.routes ?? DEFAULT_ROUTE_OPTIONS.sync_stream.routes
94
+ );
95
+ // Limit the active concurrent requests
96
+ childContext.addHook(
97
+ 'onRequest',
98
+ createRequestQueueHook(routes.sync_stream?.queue_options ?? DEFAULT_ROUTE_OPTIONS.sync_stream.queue_options)
99
+ );
100
+ });
101
+ }
@@ -0,0 +1,60 @@
1
+ import { deserialize } from 'bson';
2
+ import * as http from 'http';
3
+
4
+ import { errors, logger } from '@powersync/lib-services-framework';
5
+ import { ReactiveSocketRouter, RSocketRequestMeta } from '@powersync/service-rsocket-router';
6
+
7
+ import { ServiceContext } from '../system/ServiceContext.js';
8
+ import { generateContext, getTokenFromHeader } from './auth.js';
9
+ import { syncStreamReactive } from './endpoints/socket-route.js';
10
+ import { RSocketContextMeta, SocketRouteGenerator } from './router-socket.js';
11
+ import { Context } from './router.js';
12
+
13
+ export type RSockerRouterConfig = {
14
+ service_context: ServiceContext;
15
+ server: http.Server;
16
+ route_generators?: SocketRouteGenerator[];
17
+ };
18
+
19
+ export const DEFAULT_SOCKET_ROUTES = [syncStreamReactive];
20
+
21
+ export function configureRSocket(router: ReactiveSocketRouter<Context>, options: RSockerRouterConfig) {
22
+ const { route_generators = DEFAULT_SOCKET_ROUTES, server, service_context } = options;
23
+
24
+ router.applyWebSocketEndpoints(server, {
25
+ contextProvider: async (data: Buffer) => {
26
+ const { token, user_agent } = RSocketContextMeta.decode(deserialize(data) as any);
27
+
28
+ if (!token) {
29
+ throw new errors.AuthorizationError('No token provided');
30
+ }
31
+
32
+ try {
33
+ const extracted_token = getTokenFromHeader(token);
34
+ if (extracted_token != null) {
35
+ const { context, errors: token_errors } = await generateContext(options.service_context, extracted_token);
36
+ if (context?.token_payload == null) {
37
+ throw new errors.AuthorizationError(token_errors ?? 'Authentication required');
38
+ }
39
+ return {
40
+ token,
41
+ user_agent,
42
+ ...context,
43
+ token_errors: token_errors,
44
+ service_context
45
+ };
46
+ } else {
47
+ throw new errors.AuthorizationError('No token provided');
48
+ }
49
+ } catch (ex) {
50
+ logger.error(ex);
51
+ throw ex;
52
+ }
53
+ },
54
+ endpoints: route_generators.map((generator) => generator(router)),
55
+ metaDecoder: async (meta: Buffer) => {
56
+ return RSocketRequestMeta.decode(deserialize(meta) as any);
57
+ },
58
+ payloadDecoder: async (rawData?: Buffer) => rawData && deserialize(rawData)
59
+ });
60
+ }
@@ -1,35 +1,11 @@
1
1
  import { errors, router, schema } from '@powersync/lib-services-framework';
2
- import { SqlSyncRules, SqliteValue, StaticSchema, isJsonValue, toSyncRulesValue } from '@powersync/service-sync-rules';
2
+ import { SqlSyncRules, StaticSchema } from '@powersync/service-sync-rules';
3
3
  import { internal_routes } from '@powersync/service-types';
4
4
 
5
5
  import * as api from '../../api/api-index.js';
6
- import * as util from '../../util/util-index.js';
7
-
8
- import { routeDefinition } from '../router.js';
9
- import { PersistedSyncRulesContent } from '../../storage/BucketStorage.js';
6
+ import * as storage from '../../storage/storage-index.js';
10
7
  import { authApi } from '../auth.js';
11
-
12
- const demoCredentials = routeDefinition({
13
- path: '/api/admin/v1/demo-credentials',
14
- method: router.HTTPMethod.POST,
15
- authorize: authApi,
16
- validator: schema.createTsCodecValidator(internal_routes.DemoCredentialsRequest, {
17
- allowAdditional: true
18
- }),
19
- handler: async (payload) => {
20
- const connection = payload.context.system.config.connection;
21
- if (connection == null || !connection.demo_database) {
22
- return internal_routes.DemoCredentialsResponse.encode({});
23
- }
24
-
25
- const uri = util.buildDemoPgUri(connection);
26
- return internal_routes.DemoCredentialsResponse.encode({
27
- credentials: {
28
- postgres_uri: uri
29
- }
30
- });
31
- }
32
- });
8
+ import { routeDefinition } from '../router.js';
33
9
 
34
10
  export const executeSql = routeDefinition({
35
11
  path: '/api/admin/v1/execute-sql',
@@ -37,47 +13,27 @@ export const executeSql = routeDefinition({
37
13
  authorize: authApi,
38
14
  validator: schema.createTsCodecValidator(internal_routes.ExecuteSqlRequest, { allowAdditional: true }),
39
15
  handler: async (payload) => {
40
- const connection = payload.context.system.config.connection;
41
- if (connection == null || !connection.debug_api) {
42
- return internal_routes.ExecuteSqlResponse.encode({
43
- results: {
44
- columns: [],
45
- rows: []
46
- },
47
- success: false,
48
- error: 'SQL querying is not enabled'
49
- });
50
- }
51
-
52
- const pool = payload.context.system.requirePgPool();
53
-
54
- const { query, args } = payload.params.sql;
16
+ const {
17
+ params: {
18
+ sql: { query, args }
19
+ }
20
+ } = payload;
55
21
 
56
- try {
57
- const result = await pool.query({
58
- statement: query,
59
- params: args.map(util.autoParameter)
60
- });
22
+ const apiHandler = payload.context.service_context.routerEngine!.getAPI();
61
23
 
62
- return internal_routes.ExecuteSqlResponse.encode({
63
- success: true,
64
- results: {
65
- columns: result.columns.map((c) => c.name),
66
- rows: result.rows.map((row) => {
67
- return row.map((value) => mapColumnValue(toSyncRulesValue(value)));
68
- })
69
- }
70
- });
71
- } catch (e) {
24
+ const sourceConfig = await apiHandler.getSourceConfig();
25
+ if (!sourceConfig.debug_api) {
72
26
  return internal_routes.ExecuteSqlResponse.encode({
73
27
  results: {
74
28
  columns: [],
75
29
  rows: []
76
30
  },
77
31
  success: false,
78
- error: e.message
32
+ error: 'SQL querying is not enabled'
79
33
  });
80
34
  }
35
+
36
+ return internal_routes.ExecuteSqlResponse.encode(await apiHandler.executeQuery(query, args));
81
37
  }
82
38
  });
83
39
 
@@ -87,34 +43,45 @@ export const diagnostics = routeDefinition({
87
43
  authorize: authApi,
88
44
  validator: schema.createTsCodecValidator(internal_routes.DiagnosticsRequest, { allowAdditional: true }),
89
45
  handler: async (payload) => {
46
+ const { context } = payload;
47
+ const { service_context } = context;
90
48
  const include_content = payload.params.sync_rules_content ?? false;
91
- const system = payload.context.system;
92
49
 
93
- const status = await api.getConnectionStatus(system);
94
- if (status == null) {
50
+ const apiHandler = service_context.routerEngine!.getAPI();
51
+
52
+ const status = await apiHandler.getConnectionStatus();
53
+ if (!status) {
95
54
  return internal_routes.DiagnosticsResponse.encode({
96
55
  connections: []
97
56
  });
98
57
  }
99
58
 
100
- const { storage } = system;
101
- const active = await storage.getActiveSyncRulesContent();
102
- const next = await storage.getNextSyncRulesContent();
59
+ const {
60
+ storageEngine: { activeBucketStorage }
61
+ } = service_context;
62
+ const active = await activeBucketStorage.getActiveSyncRulesContent();
63
+ const next = await activeBucketStorage.getNextSyncRulesContent();
103
64
 
104
- const active_status = await api.getSyncRulesStatus(active, system, {
65
+ const active_status = await api.getSyncRulesStatus(activeBucketStorage, apiHandler, active, {
105
66
  include_content,
106
67
  check_connection: status.connected,
107
68
  live_status: true
108
69
  });
109
70
 
110
- const next_status = await api.getSyncRulesStatus(next, system, {
71
+ const next_status = await api.getSyncRulesStatus(activeBucketStorage, apiHandler, next, {
111
72
  include_content,
112
73
  check_connection: status.connected,
113
74
  live_status: true
114
75
  });
115
76
 
116
77
  return internal_routes.DiagnosticsResponse.encode({
117
- connections: [status],
78
+ connections: [
79
+ {
80
+ ...status,
81
+ // TODO update this in future
82
+ postgres_uri: status.uri
83
+ }
84
+ ],
118
85
  active_sync_rules: active_status,
119
86
  deploying_sync_rules: next_status
120
87
  });
@@ -127,9 +94,9 @@ export const getSchema = routeDefinition({
127
94
  authorize: authApi,
128
95
  validator: schema.createTsCodecValidator(internal_routes.GetSchemaRequest, { allowAdditional: true }),
129
96
  handler: async (payload) => {
130
- const system = payload.context.system;
97
+ const apiHandler = payload.context.service_context.routerEngine!.getAPI();
131
98
 
132
- return internal_routes.GetSchemaResponse.encode(await api.getConnectionsSchema(system));
99
+ return internal_routes.GetSchemaResponse.encode(await api.getConnectionsSchema(apiHandler));
133
100
  }
134
101
  });
135
102
 
@@ -139,15 +106,19 @@ export const reprocess = routeDefinition({
139
106
  authorize: authApi,
140
107
  validator: schema.createTsCodecValidator(internal_routes.ReprocessRequest, { allowAdditional: true }),
141
108
  handler: async (payload) => {
142
- const system = payload.context.system;
143
-
144
- const storage = system.storage;
145
- const next = await storage.getNextSyncRules();
109
+ const {
110
+ context: { service_context }
111
+ } = payload;
112
+ const {
113
+ storageEngine: { activeBucketStorage }
114
+ } = service_context;
115
+ const apiHandler = service_context.routerEngine!.getAPI();
116
+ const next = await activeBucketStorage.getNextSyncRules(apiHandler.getParseSyncRulesOptions());
146
117
  if (next != null) {
147
118
  throw new Error(`Busy processing sync rules - cannot reprocess`);
148
119
  }
149
120
 
150
- const active = await storage.getActiveSyncRules();
121
+ const active = await activeBucketStorage.getActiveSyncRules(apiHandler.getParseSyncRulesOptions());
151
122
  if (active == null) {
152
123
  throw new errors.JourneyError({
153
124
  status: 422,
@@ -156,15 +127,18 @@ export const reprocess = routeDefinition({
156
127
  });
157
128
  }
158
129
 
159
- const new_rules = await storage.updateSyncRules({
130
+ const new_rules = await activeBucketStorage.updateSyncRules({
160
131
  content: active.sync_rules.content
161
132
  });
162
133
 
134
+ const baseConfig = await apiHandler.getSourceConfig();
135
+
163
136
  return internal_routes.ReprocessResponse.encode({
164
137
  connections: [
165
138
  {
166
- tag: system.config.connection!.tag,
167
- id: system.config.connection!.id,
139
+ // Previously the connection was asserted with `!`
140
+ tag: baseConfig!.tag!,
141
+ id: baseConfig!.id,
168
142
  slot_name: new_rules.slot_name
169
143
  }
170
144
  ]
@@ -178,14 +152,16 @@ export const validate = routeDefinition({
178
152
  authorize: authApi,
179
153
  validator: schema.createTsCodecValidator(internal_routes.ValidateRequest, { allowAdditional: true }),
180
154
  handler: async (payload) => {
181
- const system = payload.context.system;
182
-
155
+ const {
156
+ context: { service_context }
157
+ } = payload;
183
158
  const content = payload.params.sync_rules;
159
+ const apiHandler = service_context.routerEngine!.getAPI();
184
160
 
185
- const schemaData = await api.getConnectionsSchema(system);
161
+ const schemaData = await api.getConnectionsSchema(apiHandler);
186
162
  const schema = new StaticSchema(schemaData.connections);
187
163
 
188
- const sync_rules: PersistedSyncRulesContent = {
164
+ const sync_rules: storage.PersistedSyncRulesContent = {
189
165
  // Dummy values
190
166
  id: 0,
191
167
  slot_name: '',
@@ -193,7 +169,10 @@ export const validate = routeDefinition({
193
169
  parsed() {
194
170
  return {
195
171
  ...this,
196
- sync_rules: SqlSyncRules.fromYaml(content, { throwOnError: false, schema })
172
+ sync_rules: SqlSyncRules.fromYaml(content, {
173
+ ...apiHandler.getParseSyncRulesOptions(),
174
+ schema
175
+ })
197
176
  };
198
177
  },
199
178
  sync_rules_content: content,
@@ -202,19 +181,24 @@ export const validate = routeDefinition({
202
181
  }
203
182
  };
204
183
 
205
- const connectionStatus = await api.getConnectionStatus(system);
206
- if (connectionStatus == null) {
184
+ const connectionStatus = await apiHandler.getConnectionStatus();
185
+ if (!connectionStatus) {
207
186
  return internal_routes.ValidateResponse.encode({
208
187
  errors: [{ level: 'fatal', message: 'No connection configured' }],
209
188
  connections: []
210
189
  });
211
190
  }
212
191
 
213
- const status = (await api.getSyncRulesStatus(sync_rules, system, {
214
- include_content: false,
215
- check_connection: connectionStatus?.connected,
216
- live_status: false
217
- }))!;
192
+ const status = (await api.getSyncRulesStatus(
193
+ service_context.storageEngine.activeBucketStorage,
194
+ apiHandler,
195
+ sync_rules,
196
+ {
197
+ include_content: false,
198
+ check_connection: connectionStatus.connected,
199
+ live_status: false
200
+ }
201
+ ))!;
218
202
 
219
203
  if (connectionStatus == null) {
220
204
  status.errors.push({ level: 'fatal', message: 'No connection configured' });
@@ -224,14 +208,4 @@ export const validate = routeDefinition({
224
208
  }
225
209
  });
226
210
 
227
- function mapColumnValue(value: SqliteValue) {
228
- if (typeof value == 'bigint') {
229
- return Number(value);
230
- } else if (isJsonValue(value)) {
231
- return value;
232
- } else {
233
- return null;
234
- }
235
- }
236
-
237
- export const ADMIN_ROUTES = [demoCredentials, executeSql, diagnostics, getSchema, reprocess, validate];
211
+ export const ADMIN_ROUTES = [executeSql, diagnostics, getSchema, reprocess, validate];
@@ -1,11 +1,13 @@
1
1
  import * as t from 'ts-codec';
2
- import { router, schema } from '@powersync/lib-services-framework';
2
+ import { logger, router, schema } from '@powersync/lib-services-framework';
3
3
 
4
4
  import * as util from '../../util/util-index.js';
5
5
  import { authUser } from '../auth.js';
6
6
  import { routeDefinition } from '../router.js';
7
7
 
8
- const WriteCheckpointRequest = t.object({});
8
+ const WriteCheckpointRequest = t.object({
9
+ client_id: t.string.optional()
10
+ });
9
11
 
10
12
  export const writeCheckpoint = routeDefinition({
11
13
  path: '/write-checkpoint.json',
@@ -13,13 +15,33 @@ export const writeCheckpoint = routeDefinition({
13
15
  authorize: authUser,
14
16
  validator: schema.createTsCodecValidator(WriteCheckpointRequest, { allowAdditional: true }),
15
17
  handler: async (payload) => {
16
- const system = payload.context.system;
17
- const storage = system.storage;
18
+ const {
19
+ context: { service_context }
20
+ } = payload;
21
+ const apiHandler = service_context.routerEngine!.getAPI();
18
22
 
19
- const checkpoint = await util.getClientCheckpoint(system.requirePgPool(), storage);
20
- return {
21
- checkpoint
22
- };
23
+ // This old API needs a persisted checkpoint id.
24
+ // Since we don't use LSNs anymore, the only way to get that is to wait.
25
+ const start = Date.now();
26
+
27
+ const head = await apiHandler.getReplicationHead();
28
+
29
+ const timeout = 50_000;
30
+
31
+ logger.info(`Waiting for LSN checkpoint: ${head}`);
32
+ while (Date.now() - start < timeout) {
33
+ const cp = await service_context.storageEngine.activeBucketStorage.getActiveCheckpoint();
34
+ if (!cp.hasSyncRules()) {
35
+ throw new Error('No sync rules available');
36
+ }
37
+ if (cp.lsn && cp.lsn >= head) {
38
+ logger.info(`Got write checkpoint: ${head} : ${cp.checkpoint}`);
39
+ return { checkpoint: cp.checkpoint };
40
+ }
41
+
42
+ await new Promise((resolve) => setTimeout(resolve, 30));
43
+ }
44
+ throw new Error('Timeout while waiting for checkpoint');
23
45
  }
24
46
  });
25
47
 
@@ -29,11 +51,23 @@ export const writeCheckpoint2 = routeDefinition({
29
51
  authorize: authUser,
30
52
  validator: schema.createTsCodecValidator(WriteCheckpointRequest, { allowAdditional: true }),
31
53
  handler: async (payload) => {
32
- const { user_id, system } = payload.context;
33
- const storage = system.storage;
34
- const write_checkpoint = await util.createWriteCheckpoint(system.requirePgPool(), storage, user_id!);
54
+ const { user_id, service_context } = payload.context;
55
+
56
+ const apiHandler = service_context.routerEngine!.getAPI();
57
+
58
+ const client_id = payload.params.client_id;
59
+ const full_user_id = util.checkpointUserId(user_id, client_id);
60
+
61
+ const currentCheckpoint = await apiHandler.getReplicationHead();
62
+ const {
63
+ storageEngine: { activeBucketStorage }
64
+ } = service_context;
65
+
66
+ const writeCheckpoint = await activeBucketStorage.createWriteCheckpoint(full_user_id, { '1': currentCheckpoint });
67
+ logger.info(`Write checkpoint 2: ${JSON.stringify({ currentCheckpoint, id: String(full_user_id) })}`);
68
+
35
69
  return {
36
- write_checkpoint: String(write_checkpoint)
70
+ write_checkpoint: String(writeCheckpoint)
37
71
  };
38
72
  }
39
73
  });
@@ -1,6 +1,5 @@
1
1
  export * from './admin.js';
2
2
  export * from './checkpointing.js';
3
- export * from './dev.js';
4
3
  export * from './socket-route.js';
5
4
  export * from './sync-rules.js';
6
5
  export * from './sync-stream.js';