@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,141 @@
1
+ import * as t from 'ts-codec';
2
+ import { configFile } from '@powersync/service-types';
3
+ import * as micro from '@journeyapps-platform/micro';
4
+ import { RunnerConfig } from '../types.js';
5
+ import * as yaml from 'yaml';
6
+
7
+ export enum ConfigFileFormat {
8
+ YAML = 'yaml',
9
+ JSON = 'json'
10
+ }
11
+
12
+ /**
13
+ * Environment variables can be substituted into the YAML config
14
+ * when parsing if the environment variable name starts with this prefix.
15
+ * Attempting to substitute any other environment variable will throw an exception.
16
+ *
17
+ * Example of substitution:
18
+ * storage:
19
+ * type: mongodb
20
+ * uri: !env PS_MONGO_URI
21
+ */
22
+ const YAML_ENV_PREFIX = 'PS_';
23
+
24
+ // ts-codec itself doesn't give great validation errors, so we use json schema for that
25
+ const configSchemaValidator = micro.schema
26
+ .parseJSONSchema(
27
+ t.generateJSONSchema(configFile.powerSyncConfig, { allowAdditional: true, parsers: [configFile.portParser] })
28
+ )
29
+ .validator();
30
+
31
+ export abstract class ConfigCollector {
32
+ abstract get name(): string;
33
+
34
+ /**
35
+ * Collects the serialized base PowerSyncConfig.
36
+ * @returns null if this collector cannot provide a config
37
+ */
38
+ abstract collectSerialized(runnerConfig: RunnerConfig): Promise<configFile.SerializedPowerSyncConfig | null>;
39
+
40
+ /**
41
+ * Collects the PowerSyncConfig settings.
42
+ * Validates and decodes the config.
43
+ * @returns null if this collector cannot provide a config
44
+ */
45
+ async collect(runner_config: RunnerConfig): Promise<configFile.PowerSyncConfig | null> {
46
+ const serialized = await this.collectSerialized(runner_config);
47
+ if (!serialized) {
48
+ return null;
49
+ }
50
+
51
+ /**
52
+ * After this point a serialized config has been found. Any failures to decode or validate
53
+ * will result in a hard stop.
54
+ */
55
+ const decoded = this.decode(serialized);
56
+ this.validate(decoded);
57
+ return decoded;
58
+ }
59
+
60
+ /**
61
+ * Validates input config
62
+ * ts-codec itself doesn't give great validation errors, so we use json schema for that
63
+ */
64
+ validate(config: configFile.PowerSyncConfig) {
65
+ const valid = configSchemaValidator.validate(config);
66
+ if (!valid.valid) {
67
+ throw new Error(`Failed to validate PowerSync config: ${valid.errors.join(', ')}`);
68
+ }
69
+ }
70
+
71
+ decode(encoded: configFile.SerializedPowerSyncConfig): configFile.PowerSyncConfig {
72
+ try {
73
+ return configFile.powerSyncConfig.decode(encoded);
74
+ } catch (ex) {
75
+ throw new Error(`Failed to decode PowerSync config: ${ex}`);
76
+ }
77
+ }
78
+
79
+ protected parseContent(content: string, contentType?: ConfigFileFormat) {
80
+ switch (contentType) {
81
+ case ConfigFileFormat.YAML:
82
+ return this.parseYaml(content);
83
+ case ConfigFileFormat.JSON:
84
+ return this.parseJSON(content);
85
+ default: {
86
+ // No content type provided, need to try both
87
+ try {
88
+ return this.parseYaml(content);
89
+ } catch (ex) {}
90
+ try {
91
+ return this.parseJSON(content);
92
+ } catch (ex) {
93
+ throw new Error(`Could not parse PowerSync config file content as JSON or YAML: ${ex}`);
94
+ }
95
+ }
96
+ }
97
+ }
98
+
99
+ protected parseYaml(content: string) {
100
+ const lineCounter = new yaml.LineCounter();
101
+
102
+ const parsed = yaml.parseDocument(content, {
103
+ schema: 'core',
104
+ keepSourceTokens: true,
105
+ lineCounter,
106
+ customTags: [
107
+ {
108
+ tag: '!env',
109
+ resolve(envName: string, onError: (error: string) => void) {
110
+ if (!envName.startsWith(YAML_ENV_PREFIX)) {
111
+ onError(
112
+ `Attempting to substitute environment variable ${envName} is not allowed. Variables must start with "${YAML_ENV_PREFIX}"`
113
+ );
114
+ return envName;
115
+ }
116
+ const value = process.env[envName];
117
+ if (typeof value == 'undefined') {
118
+ onError(
119
+ `Attempted to substitute environment variable "${envName}" which is undefined. Set this variable on the environment.`
120
+ );
121
+ return envName;
122
+ }
123
+ return value;
124
+ }
125
+ }
126
+ ]
127
+ });
128
+
129
+ if (parsed.errors.length) {
130
+ throw new Error(
131
+ `Could not parse YAML configuration file. Received errors: \n ${parsed.errors.map((e) => e.message).join('\n')}`
132
+ );
133
+ }
134
+
135
+ return parsed.toJS();
136
+ }
137
+
138
+ protected parseJSON(content: string) {
139
+ return JSON.parse(content);
140
+ }
141
+ }
@@ -0,0 +1,18 @@
1
+ import { ConfigCollector } from '../config-collector.js';
2
+ import { RunnerConfig } from '../../types.js';
3
+
4
+ export class Base64ConfigCollector extends ConfigCollector {
5
+ get name(): string {
6
+ return 'Base64';
7
+ }
8
+
9
+ async collectSerialized(runnerConfig: RunnerConfig) {
10
+ const { config_base64 } = runnerConfig;
11
+ if (!config_base64) {
12
+ return null;
13
+ }
14
+
15
+ // Could be JSON or YAML at this point
16
+ return this.parseContent(Buffer.from(config_base64, 'base64').toString());
17
+ }
18
+ }
@@ -0,0 +1,22 @@
1
+ import { RunnerConfig } from '../../types.js';
2
+ import { FileSystemConfigCollector } from './filesystem-config-collector.js';
3
+
4
+ export const DEFAULT_CONFIG_LOCATION = 'powersync.yaml';
5
+
6
+ /**
7
+ * Falls back to reading the PowerSync config file from the previous
8
+ * default location of `powersync.yaml`
9
+ */
10
+ export class FallbackConfigCollector extends FileSystemConfigCollector {
11
+ get name(): string {
12
+ return 'Fallback powersync.yaml';
13
+ }
14
+
15
+ async collectSerialized(runnerConfig: RunnerConfig) {
16
+ return super.collectSerialized({
17
+ ...runnerConfig,
18
+ // Use the fallback config location
19
+ config_path: DEFAULT_CONFIG_LOCATION
20
+ });
21
+ }
22
+ }
@@ -0,0 +1,41 @@
1
+ import * as fs from 'fs/promises';
2
+ import * as micro from '@journeyapps-platform/micro';
3
+
4
+ import { ConfigCollector, ConfigFileFormat } from '../config-collector.js';
5
+ import { RunnerConfig } from '../../types.js';
6
+
7
+ export class FileSystemConfigCollector extends ConfigCollector {
8
+ get name(): string {
9
+ return 'FileSystem';
10
+ }
11
+
12
+ async collectSerialized(runnerConfig: RunnerConfig) {
13
+ const { config_path } = runnerConfig;
14
+ if (!config_path) {
15
+ return null;
16
+ }
17
+
18
+ // Check if file exists
19
+ try {
20
+ await fs.access(config_path, fs.constants.F_OK);
21
+ } catch (ex) {
22
+ throw new Error(`Config file path ${config_path} was specified, but the file does not exist.`);
23
+ }
24
+
25
+ micro.logger.info(`Collecting PowerSync configuration from File: ${config_path}`);
26
+
27
+ const content = await fs.readFile(config_path, 'utf-8');
28
+
29
+ let contentType: ConfigFileFormat | undefined;
30
+ switch (true) {
31
+ case config_path.endsWith('.yaml'):
32
+ case config_path.endsWith('.yml'):
33
+ contentType = ConfigFileFormat.YAML;
34
+ break;
35
+ case config_path.endsWith('.json'):
36
+ contentType = ConfigFileFormat.JSON;
37
+ break;
38
+ }
39
+ return this.parseContent(content, contentType);
40
+ }
41
+ }
@@ -0,0 +1,171 @@
1
+ import * as micro from '@journeyapps-platform/micro';
2
+ import { configFile, normalizeConnection } from '@powersync/service-types';
3
+ import { ConfigCollector } from './collectors/config-collector.js';
4
+ import { ResolvedConnection, ResolvedPowerSyncConfig, RunnerConfig, SyncRulesConfig } from './types.js';
5
+ import * as auth from '@/auth/auth-index.js';
6
+ import { SyncRulesCollector } from './sync-rules/sync-collector.js';
7
+ import { Base64ConfigCollector } from './collectors/impl/base64-config-collector.js';
8
+ import { FileSystemConfigCollector } from './collectors/impl/filesystem-config-collector.js';
9
+ import { Base64SyncRulesCollector } from './sync-rules/impl/base64-sync-rules-collector.js';
10
+ import { InlineSyncRulesCollector } from './sync-rules/impl/inline-sync-rules-collector.js';
11
+ import { FileSystemSyncRulesCollector } from './sync-rules/impl/filesystem-sync-rules-collector.js';
12
+ import { FallbackConfigCollector } from './collectors/impl/fallback-config-collector.js';
13
+
14
+ const POWERSYNC_DEV_KID = 'powersync-dev';
15
+
16
+ export type CompoundConfigCollectorOptions = {
17
+ /**
18
+ * Collectors for PowerSync configuration content.
19
+ * The configuration from first collector to provide a configuration
20
+ * is used. The order of the collectors specifies precedence
21
+ */
22
+ configCollectors: ConfigCollector[];
23
+ /**
24
+ * Collectors for PowerSync sync rules content.
25
+ * The configuration from first collector to provide a configuration
26
+ * is used. The order of the collectors specifies precedence
27
+ */
28
+ syncRulesCollectors: SyncRulesCollector[];
29
+ };
30
+
31
+ const DEFAULT_COLLECTOR_OPTIONS: CompoundConfigCollectorOptions = {
32
+ configCollectors: [new Base64ConfigCollector(), new FileSystemConfigCollector(), new FallbackConfigCollector()],
33
+ syncRulesCollectors: [
34
+ new Base64SyncRulesCollector(),
35
+ new FileSystemSyncRulesCollector(),
36
+ new InlineSyncRulesCollector()
37
+ ]
38
+ };
39
+
40
+ export class CompoundConfigCollector {
41
+ constructor(protected options: CompoundConfigCollectorOptions = DEFAULT_COLLECTOR_OPTIONS) {}
42
+
43
+ /**
44
+ * Collects and resolves base config
45
+ */
46
+ async collectConfig(runner_config: RunnerConfig = {}): Promise<ResolvedPowerSyncConfig> {
47
+ const baseConfig = await this.collectBaseConfig(runner_config);
48
+
49
+ const connections = baseConfig.replication?.connections ?? [];
50
+ if (connections.length > 1) {
51
+ throw new Error('Only a single replication connection is supported currently');
52
+ }
53
+
54
+ const mapped = connections.map((c) => {
55
+ const conf: ResolvedConnection = {
56
+ type: 'postgresql' as const,
57
+ ...normalizeConnection(c),
58
+ debug_api: c.debug_api ?? false
59
+ };
60
+
61
+ return conf;
62
+ });
63
+
64
+ const collectors = new auth.CompoundKeyCollector();
65
+ const keyStore = new auth.KeyStore(collectors);
66
+
67
+ const inputKeys = baseConfig.client_auth?.jwks?.keys ?? [];
68
+ const staticCollector = await auth.StaticKeyCollector.importKeys(inputKeys);
69
+
70
+ collectors.add(staticCollector);
71
+
72
+ if (baseConfig.client_auth?.supabase && mapped.length > 0) {
73
+ collectors.add(new auth.CachedKeyCollector(new auth.SupabaseKeyCollector(mapped[0])));
74
+ }
75
+
76
+ let jwks_uris = baseConfig.client_auth?.jwks_uri ?? [];
77
+ if (typeof jwks_uris == 'string') {
78
+ jwks_uris = [jwks_uris];
79
+ }
80
+
81
+ for (let uri of jwks_uris) {
82
+ collectors.add(
83
+ new auth.CachedKeyCollector(
84
+ new auth.RemoteJWKSCollector(uri, { block_local_ip: !!baseConfig.client_auth?.block_local_jwks })
85
+ )
86
+ );
87
+ }
88
+
89
+ const baseDevKey = (baseConfig.client_auth?.jwks?.keys ?? []).find((key) => key.kid == POWERSYNC_DEV_KID);
90
+
91
+ let devKey: auth.KeySpec | undefined;
92
+ if (baseConfig.dev?.demo_auth && baseDevKey != null && baseDevKey.kty == 'oct') {
93
+ devKey = await auth.KeySpec.importKey(baseDevKey);
94
+ }
95
+
96
+ const sync_rules = await this.collectSyncRules(baseConfig, runner_config);
97
+
98
+ let jwt_audiences: string[] = baseConfig.client_auth?.audience ?? [];
99
+
100
+ let config: ResolvedPowerSyncConfig = {
101
+ connection: mapped[0],
102
+ storage: baseConfig.storage,
103
+ client_keystore: keyStore,
104
+ // Dev tokens only use the static keys, no external key sources
105
+ // We may restrict this even further to only the powersync-dev key.
106
+ dev_client_keystore: new auth.KeyStore(staticCollector),
107
+ api_tokens: baseConfig.api?.tokens ?? [],
108
+ dev: {
109
+ demo_auth: baseConfig.dev?.demo_auth ?? false,
110
+ demo_client: baseConfig.dev?.demo_client ?? false,
111
+ demo_password: baseConfig.dev?.demo_password,
112
+ crud_api: baseConfig.dev?.crud_api ?? false,
113
+ dev_key: devKey
114
+ },
115
+ port: baseConfig.port ?? 8080,
116
+ sync_rules,
117
+ jwt_audiences,
118
+
119
+ token_max_expiration: '1d', // 1 day
120
+ metadata: baseConfig.metadata ?? {},
121
+ migrations: baseConfig.migrations,
122
+ slot_name_prefix: connections[0]?.slot_name_prefix ?? 'powersync_'
123
+ };
124
+ return config;
125
+ }
126
+
127
+ /**
128
+ * Collects the base PowerSyncConfig from various registered collectors.
129
+ * @throws if no collector could return a configuration.
130
+ */
131
+ protected async collectBaseConfig(runner_config: RunnerConfig): Promise<configFile.PowerSyncConfig> {
132
+ for (const collector of this.options.configCollectors) {
133
+ try {
134
+ const baseConfig = await collector.collect(runner_config);
135
+ if (baseConfig) {
136
+ return baseConfig;
137
+ }
138
+ micro.logger.debug(
139
+ `Could not collect PowerSync config with ${collector.name} method. Moving on to next method if available.`
140
+ );
141
+ } catch (ex) {
142
+ // An error in a collector is a hard stop
143
+ throw new Error(`Could not collect config using ${collector.name} method. Caught exception: ${ex}`);
144
+ }
145
+ }
146
+ throw new Error('PowerSyncConfig could not be collected using any of the registered config collectors.');
147
+ }
148
+
149
+ protected async collectSyncRules(
150
+ baseConfig: configFile.PowerSyncConfig,
151
+ runnerConfig: RunnerConfig
152
+ ): Promise<SyncRulesConfig> {
153
+ for (const collector of this.options.syncRulesCollectors) {
154
+ try {
155
+ const config = await collector.collect(baseConfig, runnerConfig);
156
+ if (config) {
157
+ return config;
158
+ }
159
+ micro.logger.debug(
160
+ `Could not collect sync rules with ${collector.name} method. Moving on to next method if available.`
161
+ );
162
+ } catch (ex) {
163
+ // An error in a collector is a hard stop
164
+ throw new Error(`Could not collect sync rules using ${collector.name} method. Caught exception: ${ex}`);
165
+ }
166
+ }
167
+ return {
168
+ present: false
169
+ };
170
+ }
171
+ }
@@ -0,0 +1,21 @@
1
+ import { RunnerConfig, SyncRulesConfig } from '../../types.js';
2
+ import { SyncRulesCollector } from '../sync-collector.js';
3
+ import { configFile } from '@powersync/service-types';
4
+
5
+ export class Base64SyncRulesCollector extends SyncRulesCollector {
6
+ get name(): string {
7
+ return 'Base64';
8
+ }
9
+
10
+ async collect(baseConfig: configFile.PowerSyncConfig, runnerConfig: RunnerConfig): Promise<SyncRulesConfig | null> {
11
+ const { sync_rules_base64 } = runnerConfig;
12
+ if (!sync_rules_base64) {
13
+ return null;
14
+ }
15
+
16
+ return {
17
+ present: true,
18
+ content: Buffer.from(sync_rules_base64, 'base64').toString()
19
+ };
20
+ }
21
+ }
@@ -0,0 +1,26 @@
1
+ import * as path from 'path';
2
+ import { RunnerConfig, SyncRulesConfig } from '../../types.js';
3
+ import { SyncRulesCollector } from '../sync-collector.js';
4
+ import { configFile } from '@powersync/service-types';
5
+
6
+ export class FileSystemSyncRulesCollector extends SyncRulesCollector {
7
+ get name(): string {
8
+ return 'FileSystem';
9
+ }
10
+
11
+ async collect(baseConfig: configFile.PowerSyncConfig, runnerConfig: RunnerConfig): Promise<SyncRulesConfig | null> {
12
+ const sync_path = baseConfig.sync_rules?.path;
13
+ if (!sync_path) {
14
+ return null;
15
+ }
16
+
17
+ const { config_path } = runnerConfig;
18
+
19
+ // Depending on the container, the sync rules may not actually be present.
20
+ // Only persist the path here, and load on demand using `loadSyncRules()`.
21
+ return {
22
+ present: true,
23
+ path: config_path ? path.resolve(path.dirname(config_path), sync_path) : sync_path
24
+ };
25
+ }
26
+ }
@@ -0,0 +1,21 @@
1
+ import { SyncRulesConfig } from '../../types.js';
2
+ import { SyncRulesCollector } from '../sync-collector.js';
3
+ import { configFile } from '@powersync/service-types';
4
+
5
+ export class InlineSyncRulesCollector extends SyncRulesCollector {
6
+ get name(): string {
7
+ return 'Inline';
8
+ }
9
+
10
+ async collect(baseConfig: configFile.PowerSyncConfig): Promise<SyncRulesConfig | null> {
11
+ const content = baseConfig.sync_rules?.content;
12
+ if (!content) {
13
+ return null;
14
+ }
15
+
16
+ return {
17
+ present: true,
18
+ ...baseConfig.sync_rules
19
+ };
20
+ }
21
+ }
@@ -0,0 +1,8 @@
1
+ import { configFile } from '@powersync/service-types';
2
+ import { RunnerConfig, SyncRulesConfig } from '../types.js';
3
+
4
+ export abstract class SyncRulesCollector {
5
+ abstract get name(): string;
6
+
7
+ abstract collect(baseConfig: configFile.PowerSyncConfig, runnerConfig: RunnerConfig): Promise<SyncRulesConfig | null>;
8
+ }
@@ -0,0 +1,60 @@
1
+ import { NormalizedPostgresConnection, configFile } from '@powersync/service-types';
2
+ import { KeySpec } from '../../auth/KeySpec.js';
3
+ import { KeyStore } from '../../auth/KeyStore.js';
4
+
5
+ export enum ServiceRunner {
6
+ UNIFIED = 'unified',
7
+ API = 'api',
8
+ SYNC = 'sync'
9
+ }
10
+
11
+ export type RunnerConfig = {
12
+ config_path?: string;
13
+ config_base64?: string;
14
+ sync_rules_base64?: string;
15
+ };
16
+
17
+ export type MigrationContext = {
18
+ runner_config: RunnerConfig;
19
+ };
20
+
21
+ export type Runner = (config: RunnerConfig) => Promise<void>;
22
+
23
+ export type ResolvedConnection = configFile.PostgresConnection & NormalizedPostgresConnection;
24
+
25
+ export type SyncRulesConfig = {
26
+ present: boolean;
27
+ content?: string;
28
+ path?: string;
29
+ };
30
+
31
+ export type ResolvedPowerSyncConfig = {
32
+ connection?: ResolvedConnection;
33
+ storage: configFile.StorageConfig;
34
+ dev: {
35
+ demo_auth: boolean;
36
+ demo_password?: string;
37
+ crud_api: boolean;
38
+ demo_client: boolean;
39
+ /**
40
+ * Only present when demo_auth == true
41
+ */
42
+ dev_key?: KeySpec;
43
+ };
44
+ client_keystore: KeyStore;
45
+ /**
46
+ * Keystore for development tokens.
47
+ */
48
+ dev_client_keystore: KeyStore;
49
+ port: number;
50
+ sync_rules: SyncRulesConfig;
51
+ api_tokens: string[];
52
+ jwt_audiences: string[];
53
+ token_max_expiration: string;
54
+ metadata: Record<string, string>;
55
+ migrations?: {
56
+ disable_auto_migration?: boolean;
57
+ };
58
+ /** Prefix for postgres replication slot names. May eventually be connection-specific. */
59
+ slot_name_prefix: string;
60
+ };
@@ -0,0 +1,39 @@
1
+ import * as fs from 'fs/promises';
2
+ import { baseUri } from '@powersync/service-types';
3
+
4
+ import { ResolvedConnection, ResolvedPowerSyncConfig, RunnerConfig } from './config/types.js';
5
+ import { CompoundConfigCollector } from './config/compound-config-collector.js';
6
+
7
+ /**
8
+ * Build a single URI from full postgres credentials.
9
+ */
10
+ export function buildDemoPgUri(options: ResolvedConnection): string {
11
+ if (!options.debug_api) {
12
+ throw new Error('Not supported');
13
+ }
14
+
15
+ const uri = new URL(baseUri(options));
16
+ uri.username = options.username;
17
+ uri.password = options.password;
18
+ if (options.sslmode != 'disable') {
19
+ // verify-full is tricky to actually use on a client, since they won't have the cert
20
+ // Just use "require" by default
21
+ // uri.searchParams.set('sslmode', options.sslmode);
22
+ uri.searchParams.set('sslmode', 'require');
23
+ }
24
+ return uri.toString();
25
+ }
26
+
27
+ export function loadConfig(runnerConfig: RunnerConfig = {}) {
28
+ const collector = new CompoundConfigCollector();
29
+ return collector.collectConfig(runnerConfig);
30
+ }
31
+
32
+ export async function loadSyncRules(config: ResolvedPowerSyncConfig): Promise<string | undefined> {
33
+ const sync_rules = config.sync_rules;
34
+ if (sync_rules.content) {
35
+ return sync_rules.content;
36
+ } else if (sync_rules.path) {
37
+ return await fs.readFile(sync_rules.path, 'utf-8');
38
+ }
39
+ }
@@ -0,0 +1,28 @@
1
+ import { utils } from '@journeyapps-platform/micro';
2
+
3
+ import { ServiceRunner } from './config/types.js';
4
+
5
+ export const env = utils.collectEnvironmentVariables({
6
+ /**
7
+ * Path to configuration file in filesystem
8
+ */
9
+ POWERSYNC_CONFIG_PATH: utils.type.string.optional(),
10
+ /**
11
+ * Base64 encoded contents of configuration file
12
+ */
13
+ POWERSYNC_CONFIG_B64: utils.type.string.optional(),
14
+ /**
15
+ * Base64 encoded contents of sync rules YAML
16
+ */
17
+ POWERSYNC_SYNC_RULES_B64: utils.type.string.optional(),
18
+ /**
19
+ * Runner to be started in this process
20
+ */
21
+ PS_RUNNER_TYPE: utils.type.string.default(ServiceRunner.UNIFIED),
22
+ /**
23
+ * Port for metrics
24
+ */
25
+ METRICS_PORT: utils.type.number.optional()
26
+ });
27
+
28
+ export type Env = typeof env;
@@ -0,0 +1,67 @@
1
+ import * as micro from '@journeyapps-platform/micro';
2
+
3
+ /**
4
+ * Track and log memory usage.
5
+ *
6
+ * Only for debugging purposes. This could add significant overhead and/or side-effects,
7
+ * and should not be used in production.
8
+ */
9
+ export function trackMemoryUsage() {
10
+ let lastMem = process.memoryUsage();
11
+
12
+ let bufferMemory = {
13
+ alloc: 0,
14
+ allocUnsafe: 0,
15
+ allocUnsafeSlow: 0,
16
+ from: 0,
17
+ concat: 0
18
+ };
19
+
20
+ const bufferRegistry = new FinalizationRegistry<[keyof typeof bufferMemory, number]>((v) => {
21
+ const [key, value] = v;
22
+ bufferMemory[key] -= value;
23
+ });
24
+
25
+ for (let key of Object.keys(bufferMemory)) {
26
+ const typedKey = key as keyof typeof bufferMemory;
27
+ const originalFunction = Buffer[typedKey] as (...args: any[]) => Buffer;
28
+ Buffer[typedKey] = function (...args: any[]) {
29
+ const buffer = originalFunction.apply(this, args);
30
+ bufferMemory[typedKey] += buffer.byteLength;
31
+ bufferRegistry.register(buffer, [typedKey, buffer.byteLength]);
32
+ return buffer;
33
+ };
34
+ }
35
+
36
+ setInterval(() => {
37
+ const mem = process.memoryUsage();
38
+
39
+ let isDifferent = false;
40
+ for (const key in mem) {
41
+ if (Math.abs((mem as any)[key] - (lastMem as any)[key]) > 5_000_000) {
42
+ isDifferent = true;
43
+ }
44
+ }
45
+
46
+ if (isDifferent) {
47
+ lastMem = mem;
48
+
49
+ const output = `RSS ${mb(mem.rss)} (
50
+ HAT ${mb(mem.heapTotal)} (
51
+ HU ${mb(mem.heapUsed)}
52
+ ),
53
+ buffers ${mb(mem.arrayBuffers)} (
54
+ alloc ${mb(bufferMemory.alloc + bufferMemory.allocUnsafe + bufferMemory.allocUnsafeSlow)},
55
+ from ${mb(bufferMemory.from)}
56
+ concat ${mb(bufferMemory.concat)}
57
+ )
58
+ )`.replaceAll(/\s+/g, ' ');
59
+
60
+ micro.logger.info(output);
61
+ }
62
+ }, 50);
63
+ }
64
+
65
+ function mb(n: number) {
66
+ return Math.round(n / 1024 / 1024) + 'mb';
67
+ }