@powersync/service-core 0.0.0-dev-20240725112650 → 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 (331) hide show
  1. package/CHANGELOG.md +80 -2
  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 +3 -2
  21. package/dist/entry/cli-entry.js.map +1 -1
  22. package/dist/entry/commands/compact-action.js +12 -8
  23. package/dist/entry/commands/compact-action.js.map +1 -1
  24. package/dist/entry/commands/migrate-action.js +4 -5
  25. package/dist/entry/commands/migrate-action.js.map +1 -1
  26. package/dist/entry/commands/teardown-action.js +2 -2
  27. package/dist/entry/commands/teardown-action.js.map +1 -1
  28. package/dist/index.d.ts +4 -2
  29. package/dist/index.js +4 -2
  30. package/dist/index.js.map +1 -1
  31. package/dist/metrics/Metrics.d.ts +2 -2
  32. package/dist/metrics/Metrics.js +5 -13
  33. package/dist/metrics/Metrics.js.map +1 -1
  34. package/dist/migrations/db/migrations/1684951997326-init.d.ts +2 -2
  35. package/dist/migrations/db/migrations/1684951997326-init.js +4 -2
  36. package/dist/migrations/db/migrations/1684951997326-init.js.map +1 -1
  37. package/dist/migrations/db/migrations/1702295701188-sync-rule-state.d.ts +2 -2
  38. package/dist/migrations/db/migrations/1702295701188-sync-rule-state.js +4 -2
  39. package/dist/migrations/db/migrations/1702295701188-sync-rule-state.js.map +1 -1
  40. package/dist/migrations/db/migrations/1711543888062-write-checkpoint-index.d.ts +2 -2
  41. package/dist/migrations/db/migrations/1711543888062-write-checkpoint-index.js +4 -2
  42. package/dist/migrations/db/migrations/1711543888062-write-checkpoint-index.js.map +1 -1
  43. package/dist/migrations/migrations.d.ts +8 -0
  44. package/dist/migrations/migrations.js +19 -7
  45. package/dist/migrations/migrations.js.map +1 -1
  46. package/dist/modules/AbstractModule.d.ts +26 -0
  47. package/dist/modules/AbstractModule.js +11 -0
  48. package/dist/modules/AbstractModule.js.map +1 -0
  49. package/dist/modules/ModuleManager.d.ts +11 -0
  50. package/dist/modules/ModuleManager.js +32 -0
  51. package/dist/modules/ModuleManager.js.map +1 -0
  52. package/dist/modules/modules-index.d.ts +2 -0
  53. package/dist/modules/modules-index.js +3 -0
  54. package/dist/modules/modules-index.js.map +1 -0
  55. package/dist/replication/AbstractReplicationJob.d.ts +38 -0
  56. package/dist/replication/AbstractReplicationJob.js +51 -0
  57. package/dist/replication/AbstractReplicationJob.js.map +1 -0
  58. package/dist/replication/AbstractReplicator.d.ts +53 -0
  59. package/dist/replication/AbstractReplicator.js +187 -0
  60. package/dist/replication/AbstractReplicator.js.map +1 -0
  61. package/dist/replication/ErrorRateLimiter.d.ts +0 -9
  62. package/dist/replication/ErrorRateLimiter.js +1 -42
  63. package/dist/replication/ErrorRateLimiter.js.map +1 -1
  64. package/dist/replication/ReplicationEngine.d.ts +18 -0
  65. package/dist/replication/ReplicationEngine.js +41 -0
  66. package/dist/replication/ReplicationEngine.js.map +1 -0
  67. package/dist/replication/ReplicationModule.d.ts +39 -0
  68. package/dist/replication/ReplicationModule.js +65 -0
  69. package/dist/replication/ReplicationModule.js.map +1 -0
  70. package/dist/replication/replication-index.d.ts +4 -6
  71. package/dist/replication/replication-index.js +4 -6
  72. package/dist/replication/replication-index.js.map +1 -1
  73. package/dist/routes/RouterEngine.d.ts +42 -0
  74. package/dist/routes/RouterEngine.js +80 -0
  75. package/dist/routes/RouterEngine.js.map +1 -0
  76. package/dist/routes/auth.d.ts +2 -2
  77. package/dist/routes/auth.js +11 -11
  78. package/dist/routes/auth.js.map +1 -1
  79. package/dist/routes/configure-fastify.d.ts +30 -176
  80. package/dist/routes/configure-fastify.js +10 -11
  81. package/dist/routes/configure-fastify.js.map +1 -1
  82. package/dist/routes/configure-rsocket.d.ts +3 -3
  83. package/dist/routes/configure-rsocket.js +6 -5
  84. package/dist/routes/configure-rsocket.js.map +1 -1
  85. package/dist/routes/endpoints/admin.d.ts +0 -34
  86. package/dist/routes/endpoints/admin.js +48 -89
  87. package/dist/routes/endpoints/admin.js.map +1 -1
  88. package/dist/routes/endpoints/checkpointing.d.ts +56 -16
  89. package/dist/routes/endpoints/checkpointing.js +33 -12
  90. package/dist/routes/endpoints/checkpointing.js.map +1 -1
  91. package/dist/routes/endpoints/route-endpoints-index.d.ts +0 -1
  92. package/dist/routes/endpoints/route-endpoints-index.js +0 -1
  93. package/dist/routes/endpoints/route-endpoints-index.js.map +1 -1
  94. package/dist/routes/endpoints/socket-route.js +40 -25
  95. package/dist/routes/endpoints/socket-route.js.map +1 -1
  96. package/dist/routes/endpoints/sync-rules.d.ts +1 -1
  97. package/dist/routes/endpoints/sync-rules.js +32 -23
  98. package/dist/routes/endpoints/sync-rules.js.map +1 -1
  99. package/dist/routes/endpoints/sync-stream.d.ts +10 -0
  100. package/dist/routes/endpoints/sync-stream.js +13 -8
  101. package/dist/routes/endpoints/sync-stream.js.map +1 -1
  102. package/dist/routes/router-socket.d.ts +1 -0
  103. package/dist/routes/router-socket.js +2 -1
  104. package/dist/routes/router-socket.js.map +1 -1
  105. package/dist/routes/router.d.ts +6 -2
  106. package/dist/routes/router.js.map +1 -1
  107. package/dist/routes/routes-index.d.ts +1 -0
  108. package/dist/routes/routes-index.js +1 -0
  109. package/dist/routes/routes-index.js.map +1 -1
  110. package/dist/runner/teardown.js +47 -76
  111. package/dist/runner/teardown.js.map +1 -1
  112. package/dist/storage/BucketStorage.d.ts +30 -19
  113. package/dist/storage/BucketStorage.js +0 -10
  114. package/dist/storage/BucketStorage.js.map +1 -1
  115. package/dist/storage/MongoBucketStorage.d.ts +4 -4
  116. package/dist/storage/MongoBucketStorage.js +19 -24
  117. package/dist/storage/MongoBucketStorage.js.map +1 -1
  118. package/dist/storage/SourceEntity.d.ts +20 -0
  119. package/dist/storage/SourceEntity.js +2 -0
  120. package/dist/storage/SourceEntity.js.map +1 -0
  121. package/dist/storage/SourceTable.d.ts +4 -5
  122. package/dist/storage/SourceTable.js +3 -4
  123. package/dist/storage/SourceTable.js.map +1 -1
  124. package/dist/storage/StorageEngine.d.ts +24 -0
  125. package/dist/storage/StorageEngine.js +43 -0
  126. package/dist/storage/StorageEngine.js.map +1 -0
  127. package/dist/storage/StorageProvider.d.ts +21 -0
  128. package/dist/storage/StorageProvider.js +2 -0
  129. package/dist/storage/StorageProvider.js.map +1 -0
  130. package/dist/storage/mongo/MongoBucketBatch.d.ts +1 -1
  131. package/dist/storage/mongo/MongoBucketBatch.js +6 -7
  132. package/dist/storage/mongo/MongoBucketBatch.js.map +1 -1
  133. package/dist/storage/mongo/MongoCompactor.js +2 -1
  134. package/dist/storage/mongo/MongoCompactor.js.map +1 -1
  135. package/dist/storage/mongo/MongoPersistedSyncRulesContent.d.ts +2 -2
  136. package/dist/storage/mongo/MongoPersistedSyncRulesContent.js +2 -2
  137. package/dist/storage/mongo/MongoPersistedSyncRulesContent.js.map +1 -1
  138. package/dist/storage/mongo/MongoStorageProvider.d.ts +5 -0
  139. package/dist/storage/mongo/MongoStorageProvider.js +26 -0
  140. package/dist/storage/mongo/MongoStorageProvider.js.map +1 -0
  141. package/dist/storage/mongo/MongoSyncBucketStorage.d.ts +7 -6
  142. package/dist/storage/mongo/MongoSyncBucketStorage.js +24 -15
  143. package/dist/storage/mongo/MongoSyncBucketStorage.js.map +1 -1
  144. package/dist/storage/mongo/MongoSyncRulesLock.js +1 -1
  145. package/dist/storage/mongo/MongoSyncRulesLock.js.map +1 -1
  146. package/dist/storage/mongo/OperationBatch.d.ts +7 -3
  147. package/dist/storage/mongo/OperationBatch.js +16 -7
  148. package/dist/storage/mongo/OperationBatch.js.map +1 -1
  149. package/dist/storage/mongo/PersistedBatch.d.ts +3 -3
  150. package/dist/storage/mongo/PersistedBatch.js +2 -2
  151. package/dist/storage/mongo/PersistedBatch.js.map +1 -1
  152. package/dist/storage/mongo/models.d.ts +13 -4
  153. package/dist/storage/mongo/models.js.map +1 -1
  154. package/dist/storage/mongo/util.d.ts +12 -1
  155. package/dist/storage/mongo/util.js +50 -2
  156. package/dist/storage/mongo/util.js.map +1 -1
  157. package/dist/storage/storage-index.d.ts +5 -2
  158. package/dist/storage/storage-index.js +5 -2
  159. package/dist/storage/storage-index.js.map +1 -1
  160. package/dist/sync/sync.d.ts +2 -1
  161. package/dist/sync/sync.js +36 -10
  162. package/dist/sync/sync.js.map +1 -1
  163. package/dist/sync/util.js.map +1 -1
  164. package/dist/system/ServiceContext.d.ts +37 -0
  165. package/dist/system/ServiceContext.js +48 -0
  166. package/dist/system/ServiceContext.js.map +1 -0
  167. package/dist/system/system-index.d.ts +1 -1
  168. package/dist/system/system-index.js +1 -1
  169. package/dist/system/system-index.js.map +1 -1
  170. package/dist/util/config/compound-config-collector.d.ts +9 -2
  171. package/dist/util/config/compound-config-collector.js +14 -23
  172. package/dist/util/config/compound-config-collector.js.map +1 -1
  173. package/dist/util/config/sync-rules/sync-rules-provider.d.ts +9 -0
  174. package/dist/util/config/sync-rules/sync-rules-provider.js +15 -0
  175. package/dist/util/config/sync-rules/sync-rules-provider.js.map +1 -0
  176. package/dist/util/config/types.d.ts +6 -4
  177. package/dist/util/config/types.js.map +1 -1
  178. package/dist/util/config.d.ts +3 -4
  179. package/dist/util/config.js +5 -20
  180. package/dist/util/config.js.map +1 -1
  181. package/dist/util/protocol-types.d.ts +4 -0
  182. package/dist/util/protocol-types.js +5 -1
  183. package/dist/util/protocol-types.js.map +1 -1
  184. package/dist/util/util-index.d.ts +3 -6
  185. package/dist/util/util-index.js +3 -6
  186. package/dist/util/util-index.js.map +1 -1
  187. package/dist/util/utils.d.ts +10 -6
  188. package/dist/util/utils.js +45 -25
  189. package/dist/util/utils.js.map +1 -1
  190. package/package.json +5 -7
  191. package/src/api/RouteAPI.ts +78 -0
  192. package/src/api/api-index.ts +1 -0
  193. package/src/api/diagnostics.ts +16 -71
  194. package/src/api/schema.ts +13 -89
  195. package/src/auth/KeyStore.ts +9 -6
  196. package/src/auth/auth-index.ts +0 -1
  197. package/src/entry/cli-entry.ts +3 -2
  198. package/src/entry/commands/compact-action.ts +12 -9
  199. package/src/entry/commands/migrate-action.ts +5 -8
  200. package/src/entry/commands/teardown-action.ts +2 -2
  201. package/src/index.ts +5 -2
  202. package/src/metrics/Metrics.ts +6 -16
  203. package/src/migrations/db/migrations/1684951997326-init.ts +9 -4
  204. package/src/migrations/db/migrations/1702295701188-sync-rule-state.ts +7 -4
  205. package/src/migrations/db/migrations/1711543888062-write-checkpoint-index.ts +6 -4
  206. package/src/migrations/migrations.ts +24 -8
  207. package/src/modules/AbstractModule.ts +37 -0
  208. package/src/modules/ModuleManager.ts +34 -0
  209. package/src/modules/modules-index.ts +2 -0
  210. package/src/replication/AbstractReplicationJob.ts +79 -0
  211. package/src/replication/AbstractReplicator.ts +227 -0
  212. package/src/replication/ErrorRateLimiter.ts +0 -44
  213. package/src/replication/ReplicationEngine.ts +43 -0
  214. package/src/replication/ReplicationModule.ts +101 -0
  215. package/src/replication/replication-index.ts +4 -6
  216. package/src/routes/RouterEngine.ts +120 -0
  217. package/src/routes/auth.ts +21 -12
  218. package/src/routes/configure-fastify.ts +13 -14
  219. package/src/routes/configure-rsocket.ts +9 -8
  220. package/src/routes/endpoints/admin.ts +74 -100
  221. package/src/routes/endpoints/checkpointing.ts +46 -12
  222. package/src/routes/endpoints/route-endpoints-index.ts +0 -1
  223. package/src/routes/endpoints/socket-route.ts +44 -27
  224. package/src/routes/endpoints/sync-rules.ts +41 -25
  225. package/src/routes/endpoints/sync-stream.ts +13 -8
  226. package/src/routes/router-socket.ts +2 -1
  227. package/src/routes/router.ts +6 -3
  228. package/src/routes/routes-index.ts +1 -0
  229. package/src/runner/teardown.ts +50 -88
  230. package/src/storage/BucketStorage.ts +38 -25
  231. package/src/storage/MongoBucketStorage.ts +23 -26
  232. package/src/storage/SourceEntity.ts +22 -0
  233. package/src/storage/SourceTable.ts +4 -6
  234. package/src/storage/StorageEngine.ts +55 -0
  235. package/src/storage/StorageProvider.ts +27 -0
  236. package/src/storage/mongo/MongoBucketBatch.ts +8 -8
  237. package/src/storage/mongo/MongoCompactor.ts +2 -1
  238. package/src/storage/mongo/MongoPersistedSyncRulesContent.ts +3 -3
  239. package/src/storage/mongo/MongoStorageProvider.ts +31 -0
  240. package/src/storage/mongo/MongoSyncBucketStorage.ts +39 -20
  241. package/src/storage/mongo/MongoSyncRulesLock.ts +1 -1
  242. package/src/storage/mongo/OperationBatch.ts +18 -11
  243. package/src/storage/mongo/PersistedBatch.ts +6 -5
  244. package/src/storage/mongo/models.ts +13 -4
  245. package/src/storage/mongo/util.ts +49 -4
  246. package/src/storage/storage-index.ts +5 -2
  247. package/src/sync/sync.ts +46 -11
  248. package/src/sync/util.ts +0 -1
  249. package/src/system/ServiceContext.ts +68 -0
  250. package/src/system/system-index.ts +1 -1
  251. package/src/util/config/compound-config-collector.ts +30 -31
  252. package/src/util/config/sync-rules/sync-rules-provider.ts +18 -0
  253. package/src/util/config/types.ts +6 -5
  254. package/src/util/config.ts +6 -23
  255. package/src/util/protocol-types.ts +6 -1
  256. package/src/util/util-index.ts +3 -6
  257. package/src/util/utils.ts +55 -39
  258. package/test/src/__snapshots__/sync.test.ts.snap +7 -7
  259. package/test/src/auth.test.ts +7 -7
  260. package/test/src/broadcast_iterable.test.ts +1 -1
  261. package/test/src/checksum_cache.test.ts +3 -3
  262. package/test/src/compacting.test.ts +26 -17
  263. package/test/src/data_storage.test.ts +258 -146
  264. package/test/src/env.ts +1 -3
  265. package/test/src/merge_iterable.test.ts +1 -6
  266. package/test/src/setup.ts +1 -1
  267. package/test/src/stream_utils.ts +42 -0
  268. package/test/src/sync.test.ts +52 -31
  269. package/test/src/util.ts +48 -51
  270. package/test/tsconfig.json +1 -1
  271. package/tsconfig.tsbuildinfo +1 -1
  272. package/dist/auth/SupabaseKeyCollector.d.ts +0 -22
  273. package/dist/auth/SupabaseKeyCollector.js +0 -61
  274. package/dist/auth/SupabaseKeyCollector.js.map +0 -1
  275. package/dist/replication/PgRelation.d.ts +0 -16
  276. package/dist/replication/PgRelation.js +0 -26
  277. package/dist/replication/PgRelation.js.map +0 -1
  278. package/dist/replication/WalConnection.d.ts +0 -34
  279. package/dist/replication/WalConnection.js +0 -190
  280. package/dist/replication/WalConnection.js.map +0 -1
  281. package/dist/replication/WalStream.d.ts +0 -57
  282. package/dist/replication/WalStream.js +0 -515
  283. package/dist/replication/WalStream.js.map +0 -1
  284. package/dist/replication/WalStreamManager.d.ts +0 -30
  285. package/dist/replication/WalStreamManager.js +0 -198
  286. package/dist/replication/WalStreamManager.js.map +0 -1
  287. package/dist/replication/WalStreamRunner.d.ts +0 -38
  288. package/dist/replication/WalStreamRunner.js +0 -155
  289. package/dist/replication/WalStreamRunner.js.map +0 -1
  290. package/dist/replication/util.d.ts +0 -9
  291. package/dist/replication/util.js +0 -62
  292. package/dist/replication/util.js.map +0 -1
  293. package/dist/routes/endpoints/dev.d.ts +0 -312
  294. package/dist/routes/endpoints/dev.js +0 -172
  295. package/dist/routes/endpoints/dev.js.map +0 -1
  296. package/dist/system/CorePowerSyncSystem.d.ts +0 -23
  297. package/dist/system/CorePowerSyncSystem.js +0 -52
  298. package/dist/system/CorePowerSyncSystem.js.map +0 -1
  299. package/dist/util/PgManager.d.ts +0 -24
  300. package/dist/util/PgManager.js +0 -55
  301. package/dist/util/PgManager.js.map +0 -1
  302. package/dist/util/migration_lib.d.ts +0 -11
  303. package/dist/util/migration_lib.js +0 -64
  304. package/dist/util/migration_lib.js.map +0 -1
  305. package/dist/util/pgwire_utils.d.ts +0 -24
  306. package/dist/util/pgwire_utils.js +0 -117
  307. package/dist/util/pgwire_utils.js.map +0 -1
  308. package/dist/util/populate_test_data.d.ts +0 -8
  309. package/dist/util/populate_test_data.js +0 -65
  310. package/dist/util/populate_test_data.js.map +0 -1
  311. package/src/auth/SupabaseKeyCollector.ts +0 -67
  312. package/src/replication/PgRelation.ts +0 -42
  313. package/src/replication/WalConnection.ts +0 -227
  314. package/src/replication/WalStream.ts +0 -624
  315. package/src/replication/WalStreamManager.ts +0 -213
  316. package/src/replication/WalStreamRunner.ts +0 -180
  317. package/src/replication/util.ts +0 -76
  318. package/src/routes/endpoints/dev.ts +0 -199
  319. package/src/system/CorePowerSyncSystem.ts +0 -64
  320. package/src/util/PgManager.ts +0 -64
  321. package/src/util/migration_lib.ts +0 -79
  322. package/src/util/pgwire_utils.ts +0 -139
  323. package/src/util/populate_test_data.ts +0 -78
  324. package/test/src/__snapshots__/pg_test.test.ts.snap +0 -256
  325. package/test/src/large_batch.test.ts +0 -194
  326. package/test/src/pg_test.test.ts +0 -450
  327. package/test/src/schema_changes.test.ts +0 -545
  328. package/test/src/slow_tests.test.ts +0 -338
  329. package/test/src/validation.test.ts +0 -63
  330. package/test/src/wal_stream.test.ts +0 -319
  331. package/test/src/wal_stream_utils.ts +0 -156
@@ -1,12 +1,11 @@
1
- import * as t from 'ts-codec';
2
- import type { FastifyPluginAsync } from 'fastify';
3
- import * as pgwire from '@powersync/service-jpgwire';
4
1
  import { errors, router, schema } from '@powersync/lib-services-framework';
5
2
  import { SqlSyncRules, SyncRulesErrors } from '@powersync/service-sync-rules';
3
+ import type { FastifyPluginAsync } from 'fastify';
4
+ import * as t from 'ts-codec';
6
5
 
7
- import * as replication from '../../replication/replication-index.js';
8
6
  import { authApi } from '../auth.js';
9
7
  import { routeDefinition } from '../router.js';
8
+ import { RouteAPI } from '../../api/RouteAPI.js';
10
9
 
11
10
  const DeploySyncRulesRequest = t.object({
12
11
  content: t.string
@@ -39,7 +38,10 @@ export const deploySyncRules = routeDefinition({
39
38
  plugins: [yamlPlugin],
40
39
  validator: schema.createTsCodecValidator(DeploySyncRulesRequest, { allowAdditional: true }),
41
40
  handler: async (payload) => {
42
- if (payload.context.system.config.sync_rules.present) {
41
+ const { service_context } = payload.context;
42
+ const { storageEngine } = service_context;
43
+
44
+ if (service_context.configuration.sync_rules.present) {
43
45
  // If sync rules are configured via the config, disable deploy via the API.
44
46
  throw new errors.JourneyError({
45
47
  status: 422,
@@ -51,7 +53,12 @@ export const deploySyncRules = routeDefinition({
51
53
  const content = payload.params.content;
52
54
 
53
55
  try {
54
- SqlSyncRules.fromYaml(payload.params.content);
56
+ const apiHandler = service_context.routerEngine!.getAPI();
57
+ SqlSyncRules.fromYaml(payload.params.content, {
58
+ ...apiHandler.getParseSyncRulesOptions(),
59
+ // We don't do any schema-level validation at this point
60
+ schema: undefined
61
+ });
55
62
  } catch (e) {
56
63
  throw new errors.JourneyError({
57
64
  status: 422,
@@ -61,7 +68,7 @@ export const deploySyncRules = routeDefinition({
61
68
  });
62
69
  }
63
70
 
64
- const sync_rules = await payload.context.system.storage.updateSyncRules({
71
+ const sync_rules = await storageEngine.activeBucketStorage.updateSyncRules({
65
72
  content: content
66
73
  });
67
74
 
@@ -84,8 +91,10 @@ export const validateSyncRules = routeDefinition({
84
91
  validator: schema.createTsCodecValidator(ValidateSyncRulesRequest, { allowAdditional: true }),
85
92
  handler: async (payload) => {
86
93
  const content = payload.params.content;
94
+ const { service_context } = payload.context;
95
+ const apiHandler = service_context.routerEngine!.getAPI();
87
96
 
88
- const info = await debugSyncRules(payload.context.system.requirePgPool(), content);
97
+ const info = await debugSyncRules(apiHandler, content);
89
98
 
90
99
  return replyPrettyJson(info);
91
100
  }
@@ -96,8 +105,12 @@ export const currentSyncRules = routeDefinition({
96
105
  method: router.HTTPMethod.GET,
97
106
  authorize: authApi,
98
107
  handler: async (payload) => {
99
- const storage = payload.context.system.storage;
100
- const sync_rules = await storage.getActiveSyncRulesContent();
108
+ const { service_context } = payload.context;
109
+ const {
110
+ storageEngine: { activeBucketStorage }
111
+ } = service_context;
112
+
113
+ const sync_rules = await activeBucketStorage.getActiveSyncRulesContent();
101
114
  if (!sync_rules) {
102
115
  throw new errors.JourneyError({
103
116
  status: 422,
@@ -105,12 +118,12 @@ export const currentSyncRules = routeDefinition({
105
118
  description: 'No active sync rules'
106
119
  });
107
120
  }
108
- const info = await debugSyncRules(payload.context.system.requirePgPool(), sync_rules.sync_rules_content);
109
- const next = await storage.getNextSyncRulesContent();
110
121
 
111
- const next_info = next
112
- ? await debugSyncRules(payload.context.system.requirePgPool(), next.sync_rules_content)
113
- : null;
122
+ const apiHandler = service_context.routerEngine!.getAPI();
123
+ const info = await debugSyncRules(apiHandler, sync_rules.sync_rules_content);
124
+ const next = await activeBucketStorage.getNextSyncRulesContent();
125
+
126
+ const next_info = next ? await debugSyncRules(apiHandler, next.sync_rules_content) : null;
114
127
 
115
128
  const response = {
116
129
  current: {
@@ -140,8 +153,11 @@ export const reprocessSyncRules = routeDefinition({
140
153
  authorize: authApi,
141
154
  validator: schema.createTsCodecValidator(ReprocessSyncRulesRequest),
142
155
  handler: async (payload) => {
143
- const storage = payload.context.system.storage;
144
- const sync_rules = await storage.getActiveSyncRules();
156
+ const {
157
+ storageEngine: { activeBucketStorage }
158
+ } = payload.context.service_context;
159
+ const apiHandler = payload.context.service_context.routerEngine!.getAPI();
160
+ const sync_rules = await activeBucketStorage.getActiveSyncRules(apiHandler.getParseSyncRulesOptions());
145
161
  if (sync_rules == null) {
146
162
  throw new errors.JourneyError({
147
163
  status: 422,
@@ -150,7 +166,7 @@ export const reprocessSyncRules = routeDefinition({
150
166
  });
151
167
  }
152
168
 
153
- const new_rules = await storage.updateSyncRules({
169
+ const new_rules = await activeBucketStorage.updateSyncRules({
154
170
  content: sync_rules.sync_rules.content
155
171
  });
156
172
  return {
@@ -169,15 +185,15 @@ function replyPrettyJson(payload: any) {
169
185
  });
170
186
  }
171
187
 
172
- async function debugSyncRules(db: pgwire.PgClient, sync_rules: string) {
188
+ async function debugSyncRules(apiHandler: RouteAPI, sync_rules: string) {
173
189
  try {
174
- const rules = SqlSyncRules.fromYaml(sync_rules);
175
- const source_table_patterns = rules.getSourceTables();
176
- const wc = new replication.WalConnection({
177
- db: db,
178
- sync_rules: rules
190
+ const rules = SqlSyncRules.fromYaml(sync_rules, {
191
+ ...apiHandler.getParseSyncRulesOptions(),
192
+ // No schema-based validation at this point
193
+ schema: undefined
179
194
  });
180
- const resolved_tables = await wc.getDebugTablesInfo(source_table_patterns);
195
+ const source_table_patterns = rules.getSourceTables();
196
+ const resolved_tables = await apiHandler.getDebugTablesInfo(source_table_patterns, rules);
181
197
 
182
198
  return {
183
199
  valid: true,
@@ -8,7 +8,6 @@ import * as util from '../../util/util-index.js';
8
8
  import { Metrics } from '../../metrics/Metrics.js';
9
9
  import { authUser } from '../auth.js';
10
10
  import { routeDefinition } from '../router.js';
11
- import { RequestTracker } from '../../sync/RequestTracker.js';
12
11
 
13
12
  export enum SyncRoutes {
14
13
  STREAM = '/sync/stream'
@@ -20,9 +19,13 @@ export const syncStreamed = routeDefinition({
20
19
  authorize: authUser,
21
20
  validator: schema.createTsCodecValidator(util.StreamingSyncRequest, { allowAdditional: true }),
22
21
  handler: async (payload) => {
23
- const system = payload.context.system;
22
+ const { service_context } = payload.context;
23
+ const { routerEngine, storageEngine } = service_context;
24
+ const headers = payload.request.headers;
25
+ const userAgent = headers['x-user-agent'] ?? headers['user-agent'];
26
+ const clientId = payload.params.client_id;
24
27
 
25
- if (system.closed) {
28
+ if (routerEngine!.closed) {
26
29
  throw new errors.JourneyError({
27
30
  status: 503,
28
31
  code: 'SERVICE_UNAVAILABLE',
@@ -33,9 +36,8 @@ export const syncStreamed = routeDefinition({
33
36
  const params: util.StreamingSyncRequest = payload.params;
34
37
  const syncParams = new RequestParameters(payload.context.token_payload!, payload.params.parameters ?? {});
35
38
 
36
- const storage = system.storage;
37
39
  // Sanity check before we start the stream
38
- const cp = await storage.getActiveCheckpoint();
40
+ const cp = await storageEngine.activeBucketStorage.getActiveCheckpoint();
39
41
  if (!cp.hasSyncRules()) {
40
42
  throw new errors.JourneyError({
41
43
  status: 500,
@@ -44,14 +46,15 @@ export const syncStreamed = routeDefinition({
44
46
  });
45
47
  }
46
48
  const controller = new AbortController();
47
- const tracker = new RequestTracker();
49
+ const tracker = new sync.RequestTracker();
48
50
  try {
49
51
  Metrics.getInstance().concurrent_connections.add(1);
50
52
  const stream = Readable.from(
51
53
  sync.transformToBytesTracked(
52
54
  sync.ndjson(
53
55
  sync.streamResponse({
54
- storage,
56
+ storage: storageEngine.activeBucketStorage,
57
+ parseOptions: routerEngine!.getAPI().getParseSyncRulesOptions(),
55
58
  params,
56
59
  syncParams,
57
60
  token: payload.context.token_payload!,
@@ -64,7 +67,7 @@ export const syncStreamed = routeDefinition({
64
67
  { objectMode: false, highWaterMark: 16 * 1024 }
65
68
  );
66
69
 
67
- const deregister = system.addStopHandler(() => {
70
+ const deregister = routerEngine!.addStopHandler(() => {
68
71
  // This error is not currently propagated to the client
69
72
  controller.abort();
70
73
  stream.destroy(new Error('Shutting down system'));
@@ -92,6 +95,8 @@ export const syncStreamed = routeDefinition({
92
95
  Metrics.getInstance().concurrent_connections.add(-1);
93
96
  logger.info(`Sync stream complete`, {
94
97
  user_id: syncParams.user_id,
98
+ client_id: clientId,
99
+ user_agent: userAgent,
95
100
  operations_synced: tracker.operationsSynced,
96
101
  data_synced_bytes: tracker.dataSyncedBytes
97
102
  });
@@ -9,5 +9,6 @@ import { Context } from './router.js';
9
9
  export type SocketRouteGenerator = (router: ReactiveSocketRouter<Context>) => IReactiveStream;
10
10
 
11
11
  export const RSocketContextMeta = t.object({
12
- token: t.string
12
+ token: t.string,
13
+ user_agent: t.string.optional()
13
14
  });
@@ -1,16 +1,20 @@
1
1
  import { router } from '@powersync/lib-services-framework';
2
2
  import * as auth from '../auth/auth-index.js';
3
- import { CorePowerSyncSystem } from '../system/CorePowerSyncSystem.js';
3
+ import { ServiceContext } from '../system/ServiceContext.js';
4
4
 
5
5
  /**
6
6
  * Common context for routes
7
7
  */
8
8
  export type Context = {
9
9
  user_id?: string;
10
- system: CorePowerSyncSystem;
10
+ service_context: ServiceContext;
11
11
 
12
12
  token_payload?: auth.JwtPayload;
13
13
  token_errors?: string[];
14
+ /**
15
+ * Only on websocket endpoints.
16
+ */
17
+ user_agent?: string;
14
18
  };
15
19
 
16
20
  export type BasicRouterRequest = {
@@ -37,7 +41,6 @@ export type RequestEndpointHandlerPayload<
37
41
  };
38
42
 
39
43
  export type RouteDefinition<I = any, O = any> = RequestEndpoint<I, O>;
40
-
41
44
  /**
42
45
  * Helper function for making generics work well when defining routes
43
46
  */
@@ -6,3 +6,4 @@ export * as hooks from './hooks.js';
6
6
  export * from './route-register.js';
7
7
  export * from './router-socket.js';
8
8
  export * from './router.js';
9
+ export * from './RouterEngine.js';
@@ -1,108 +1,70 @@
1
1
  // Script to tear down the data when deleting an instance.
2
- // This deletes:
3
- // 1. The replication slots on the source postgres instance (if available).
4
- // 2. The mongo database.
2
+ // This should:
3
+ // 1. Attempt to clean up any remote configuration of data sources that was set up.
4
+ // 2. Delete the storage
5
5
 
6
- import * as timers from 'timers/promises';
7
-
8
- import * as db from '../db/db-index.js';
6
+ import { container, logger } from '@powersync/lib-services-framework';
7
+ import * as modules from '../modules/modules-index.js';
8
+ import * as system from '../system/system-index.js';
9
9
  import * as storage from '../storage/storage-index.js';
10
10
  import * as utils from '../util/util-index.js';
11
- import * as replication from '../replication/replication-index.js';
12
- import { logger } from '@powersync/lib-services-framework';
11
+ import timers from 'timers/promises';
13
12
 
14
- /**
15
- * Attempt to terminate a single sync rules instance.
16
- *
17
- * This may fail with a lock error.
18
- */
19
- async function terminateReplicator(
20
- storageFactory: storage.BucketStorageFactory,
21
- connection: utils.ResolvedConnection,
22
- syncRules: storage.PersistedSyncRulesContent
23
- ) {
24
- // The lock may still be active if the current replication instance
25
- // hasn't stopped yet.
26
- const lock = await syncRules.lock();
13
+ export async function teardown(runnerConfig: utils.RunnerConfig) {
27
14
  try {
28
- const parsed = syncRules.parsed();
29
- const storage = storageFactory.getInstance(parsed);
30
- const stream = new replication.WalStreamRunner({
31
- factory: storageFactory,
32
- storage: storage,
33
- source_db: connection,
34
- lock
35
- });
15
+ logger.info(`Tearing down PowerSync instance...`);
16
+ const config = await utils.loadConfig(runnerConfig);
17
+ const serviceContext = new system.ServiceContextContainer(config);
18
+ const moduleManager = container.getImplementation(modules.ModuleManager);
19
+ await moduleManager.initialize(serviceContext);
20
+ // This is mostly done to ensure that the storage is ready
21
+ await serviceContext.lifeCycleEngine.start();
36
22
 
37
- logger.info(`Terminating replication slot ${stream.slot_name}`);
38
- await stream.terminate();
39
- logger.info(`Terminated replication slot ${stream.slot_name}`);
40
- } finally {
41
- await lock.release();
23
+ await terminateSyncRules(serviceContext.storageEngine.activeBucketStorage, moduleManager);
24
+ await serviceContext.storageEngine.activeStorage.tearDown();
25
+ logger.info(`Teardown complete.`);
26
+ process.exit(0);
27
+ } catch (e) {
28
+ logger.error(`Teardown failure`, e);
29
+ process.exit(1);
42
30
  }
43
31
  }
44
32
 
45
- /**
46
- * Terminate all replicating sync rules, deleting the replication slots.
47
- *
48
- * Retries lock and other errors for up to two minutes.
49
- *
50
- * This is a best-effot attempt. In some cases it may not be possible to delete the replication
51
- * slot, such as when the postgres instance is unreachable.
52
- */
53
- async function terminateReplicators(
54
- storageFactory: storage.BucketStorageFactory,
55
- connection: utils.ResolvedConnection
56
- ) {
33
+ async function terminateSyncRules(storageFactory: storage.BucketStorageFactory, moduleManager: modules.ModuleManager) {
34
+ logger.info(`Terminating sync rules...`);
57
35
  const start = Date.now();
58
- while (Date.now() - start < 12_000) {
36
+ const locks: storage.ReplicationLock[] = [];
37
+ while (Date.now() - start < 120_000) {
59
38
  let retry = false;
60
- const replicationRules = await storageFactory.getReplicatingSyncRules();
61
- for (let syncRules of replicationRules) {
62
- try {
63
- await terminateReplicator(storageFactory, connection, syncRules);
64
- } catch (e) {
65
- retry = true;
66
- console.error(e);
67
- logger.warn(`Failed to terminate ${syncRules.slot_name}`, e);
39
+ const replicatingSyncRules = await storageFactory.getReplicatingSyncRules();
40
+ // Lock all the replicating sync rules
41
+ for (const replicatingSyncRule of replicatingSyncRules) {
42
+ const lock = await replicatingSyncRule.lock();
43
+ locks.push(lock);
44
+ }
45
+
46
+ const stoppedSyncRules = await storageFactory.getStoppedSyncRules();
47
+ const combinedSyncRules = [...replicatingSyncRules, ...stoppedSyncRules];
48
+ try {
49
+ // Clean up any module specific configuration for the sync rules
50
+ await moduleManager.tearDown({ syncRules: combinedSyncRules });
51
+
52
+ // Mark the sync rules as terminated
53
+ for (let syncRules of combinedSyncRules) {
54
+ const syncRulesStorage = storageFactory.getInstance(syncRules);
55
+ // The storage will be dropped at the end of the teardown, so we don't need to clear it here
56
+ await syncRulesStorage.terminate({ clearStorage: false });
57
+ }
58
+ } catch (e) {
59
+ retry = true;
60
+ for (const lock of locks) {
61
+ await lock.release();
68
62
  }
69
63
  }
64
+
70
65
  if (!retry) {
71
66
  break;
72
67
  }
73
68
  await timers.setTimeout(5_000);
74
69
  }
75
70
  }
76
-
77
- export async function teardown(runnerConfig: utils.RunnerConfig) {
78
- const config = await utils.loadConfig(runnerConfig);
79
- const mongoDB = storage.createPowerSyncMongo(config.storage);
80
- try {
81
- logger.info(`Waiting for auth`);
82
- await db.mongo.waitForAuth(mongoDB.db);
83
-
84
- const bucketStorage = new storage.MongoBucketStorage(mongoDB, { slot_name_prefix: config.slot_name_prefix });
85
- const connection = config.connection;
86
-
87
- logger.info(`Terminating replication slots`);
88
-
89
- if (connection) {
90
- await terminateReplicators(bucketStorage, connection);
91
- }
92
-
93
- const database = mongoDB.db;
94
- logger.info(`Dropping database ${database.namespace}`);
95
- await database.dropDatabase();
96
- logger.info(`Done`);
97
- await mongoDB.client.close();
98
-
99
- // If there was an error connecting to postgress, the process may stay open indefinitely.
100
- // This forces an exit.
101
- // We do not consider those errors a teardown failure.
102
- process.exit(0);
103
- } catch (e) {
104
- logger.error(`Teardown failure`, e);
105
- await mongoDB.client.close();
106
- process.exit(1);
107
- }
108
- }
@@ -7,10 +7,10 @@ import {
7
7
  SqliteRow,
8
8
  ToastableSqliteRow
9
9
  } from '@powersync/service-sync-rules';
10
-
11
- import * as replication from '../replication/replication-index.js';
12
10
  import * as util from '../util/util-index.js';
13
11
  import { SourceTable } from './SourceTable.js';
12
+ import { SourceEntityDescriptor } from './SourceEntity.js';
13
+ import { ReplicaId } from './storage-index.js';
14
14
 
15
15
  export interface BucketStorageFactory {
16
16
  /**
@@ -24,7 +24,7 @@ export interface BucketStorageFactory {
24
24
  /**
25
25
  * Get a storage instance to query sync data for specific sync rules.
26
26
  */
27
- getInstance(options: PersistedSyncRules): SyncRulesBucketStorage;
27
+ getInstance(options: PersistedSyncRulesContent): SyncRulesBucketStorage;
28
28
 
29
29
  /**
30
30
  * Deploy new sync rules.
@@ -48,7 +48,7 @@ export interface BucketStorageFactory {
48
48
  /**
49
49
  * Get the sync rules used for querying.
50
50
  */
51
- getActiveSyncRules(): Promise<PersistedSyncRules | null>;
51
+ getActiveSyncRules(options: ParseSyncRulesOptions): Promise<PersistedSyncRules | null>;
52
52
 
53
53
  /**
54
54
  * Get the sync rules used for querying.
@@ -58,7 +58,7 @@ export interface BucketStorageFactory {
58
58
  /**
59
59
  * Get the sync rules that will be active next once done with initial replicatino.
60
60
  */
61
- getNextSyncRules(): Promise<PersistedSyncRules | null>;
61
+ getNextSyncRules(options: ParseSyncRulesOptions): Promise<PersistedSyncRules | null>;
62
62
 
63
63
  /**
64
64
  * Get the sync rules that will be active next once done with initial replicatino.
@@ -105,7 +105,7 @@ export interface WriteCheckpoint {
105
105
 
106
106
  export interface ActiveCheckpoint {
107
107
  readonly checkpoint: util.OpId;
108
- readonly lsn: string;
108
+ readonly lsn: string | null;
109
109
 
110
110
  hasSyncRules(): boolean;
111
111
 
@@ -131,6 +131,10 @@ export interface StorageMetrics {
131
131
  replication_size_bytes: number;
132
132
  }
133
133
 
134
+ export interface ParseSyncRulesOptions {
135
+ defaultSchema: string;
136
+ }
137
+
134
138
  export interface PersistedSyncRulesContent {
135
139
  readonly id: number;
136
140
  readonly sync_rules_content: string;
@@ -140,7 +144,7 @@ export interface PersistedSyncRulesContent {
140
144
  readonly last_keepalive_ts?: Date | null;
141
145
  readonly last_checkpoint_ts?: Date | null;
142
146
 
143
- parsed(): PersistedSyncRules;
147
+ parsed(options: ParseSyncRulesOptions): PersistedSyncRules;
144
148
 
145
149
  lock(): Promise<ReplicationLock>;
146
150
  }
@@ -157,18 +161,6 @@ export interface PersistedSyncRules {
157
161
  readonly slot_name: string;
158
162
  }
159
163
 
160
- export class DefaultPersistedSyncRules implements PersistedSyncRules {
161
- public readonly checkpoint_lsn: string | null;
162
-
163
- constructor(public readonly id: number, public readonly sync_rules: SqlSyncRules, checkpoint_lsn: string | null) {
164
- this.checkpoint_lsn = checkpoint_lsn;
165
- }
166
-
167
- get slot_name(): string {
168
- return `powersync_${this.id}`;
169
- }
170
- }
171
-
172
164
  export interface UpdateSyncRulesOptions {
173
165
  content: string;
174
166
  lock?: boolean;
@@ -198,8 +190,11 @@ export interface BucketDataBatchOptions {
198
190
  chunkLimitBytes?: number;
199
191
  }
200
192
 
193
+ export interface StartBatchOptions extends ParseSyncRulesOptions {
194
+ zeroLSN: string;
195
+ }
196
+
201
197
  export interface SyncRulesBucketStorage {
202
- readonly sync_rules: SqlSyncRules;
203
198
  readonly group_id: number;
204
199
  readonly slot_name: string;
205
200
 
@@ -207,9 +202,14 @@ export interface SyncRulesBucketStorage {
207
202
 
208
203
  resolveTable(options: ResolveTableOptions): Promise<ResolveTableResult>;
209
204
 
210
- startBatch(options: {}, callback: (batch: BucketStorageBatch) => Promise<void>): Promise<FlushedResult | null>;
205
+ startBatch(
206
+ options: StartBatchOptions,
207
+ callback: (batch: BucketStorageBatch) => Promise<void>
208
+ ): Promise<FlushedResult | null>;
211
209
 
212
- getCheckpoint(): Promise<{ checkpoint: util.OpId; lsn: string }>;
210
+ getCheckpoint(): Promise<{ checkpoint: util.OpId }>;
211
+
212
+ getParsedSyncRules(options: ParseSyncRulesOptions): SqlSyncRules;
213
213
 
214
214
  getParameterSets(checkpoint: util.OpId, lookups: SqliteJsonValue[][]): Promise<SqliteJsonRow[]>;
215
215
 
@@ -244,7 +244,7 @@ export interface SyncRulesBucketStorage {
244
244
  *
245
245
  * Must only be called on stopped sync rules.
246
246
  */
247
- terminate(): Promise<void>;
247
+ terminate(options?: TerminateOptions): Promise<void>;
248
248
 
249
249
  getStatus(): Promise<SyncRuleStatus>;
250
250
 
@@ -279,7 +279,7 @@ export interface ResolveTableOptions {
279
279
  group_id: number;
280
280
  connection_id: number;
281
281
  connection_tag: string;
282
- relation: replication.PgRelation;
282
+ entity_descriptor: SourceEntityDescriptor;
283
283
 
284
284
  sync_rules: SqlSyncRules;
285
285
  }
@@ -363,7 +363,9 @@ export interface SaveInsert {
363
363
  tag: 'insert';
364
364
  sourceTable: SourceTable;
365
365
  before?: undefined;
366
+ beforeReplicaId?: undefined;
366
367
  after: SqliteRow;
368
+ afterReplicaId: ReplicaId;
367
369
  }
368
370
 
369
371
  export interface SaveUpdate {
@@ -374,6 +376,7 @@ export interface SaveUpdate {
374
376
  * This is only present when the id has changed, and will only contain replica identity columns.
375
377
  */
376
378
  before?: SqliteRow;
379
+ beforeReplicaId?: ReplicaId;
377
380
 
378
381
  /**
379
382
  * A null value means null column.
@@ -381,13 +384,16 @@ export interface SaveUpdate {
381
384
  * An undefined value means it's a TOAST value - must be copied from another record.
382
385
  */
383
386
  after: ToastableSqliteRow;
387
+ afterReplicaId: ReplicaId;
384
388
  }
385
389
 
386
390
  export interface SaveDelete {
387
391
  tag: 'delete';
388
392
  sourceTable: SourceTable;
389
- before: SqliteRow;
393
+ before?: SqliteRow;
394
+ beforeReplicaId: ReplicaId;
390
395
  after?: undefined;
396
+ afterReplicaId?: undefined;
391
397
  }
392
398
 
393
399
  export interface SyncBucketDataBatch {
@@ -434,3 +440,10 @@ export interface CompactOptions {
434
440
  */
435
441
  compactBuckets?: string[];
436
442
  }
443
+
444
+ export interface TerminateOptions {
445
+ /**
446
+ * If true, also clear the storage before terminating.
447
+ */
448
+ clearStorage: boolean;
449
+ }