@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.
- package/.probes/.gitkeep +0 -0
- package/CHANGELOG.md +13 -0
- package/LICENSE +67 -0
- package/README.md +3 -0
- package/dist/api/api-index.d.ts +2 -0
- package/dist/api/api-index.js +3 -0
- package/dist/api/api-index.js.map +1 -0
- package/dist/api/diagnostics.d.ts +21 -0
- package/dist/api/diagnostics.js +183 -0
- package/dist/api/diagnostics.js.map +1 -0
- package/dist/api/schema.d.ts +5 -0
- package/dist/api/schema.js +88 -0
- package/dist/api/schema.js.map +1 -0
- package/dist/auth/CachedKeyCollector.d.ts +46 -0
- package/dist/auth/CachedKeyCollector.js +116 -0
- package/dist/auth/CachedKeyCollector.js.map +1 -0
- package/dist/auth/CompoundKeyCollector.d.ts +8 -0
- package/dist/auth/CompoundKeyCollector.js +23 -0
- package/dist/auth/CompoundKeyCollector.js.map +1 -0
- package/dist/auth/JwtPayload.d.ts +10 -0
- package/dist/auth/JwtPayload.js +2 -0
- package/dist/auth/JwtPayload.js.map +1 -0
- package/dist/auth/KeyCollector.d.ts +24 -0
- package/dist/auth/KeyCollector.js +2 -0
- package/dist/auth/KeyCollector.js.map +1 -0
- package/dist/auth/KeySpec.d.ts +26 -0
- package/dist/auth/KeySpec.js +49 -0
- package/dist/auth/KeySpec.js.map +1 -0
- package/dist/auth/KeyStore.d.ts +39 -0
- package/dist/auth/KeyStore.js +131 -0
- package/dist/auth/KeyStore.js.map +1 -0
- package/dist/auth/LeakyBucket.d.ts +39 -0
- package/dist/auth/LeakyBucket.js +57 -0
- package/dist/auth/LeakyBucket.js.map +1 -0
- package/dist/auth/RemoteJWKSCollector.d.ts +24 -0
- package/dist/auth/RemoteJWKSCollector.js +106 -0
- package/dist/auth/RemoteJWKSCollector.js.map +1 -0
- package/dist/auth/StaticKeyCollector.d.ts +14 -0
- package/dist/auth/StaticKeyCollector.js +19 -0
- package/dist/auth/StaticKeyCollector.js.map +1 -0
- package/dist/auth/SupabaseKeyCollector.d.ts +22 -0
- package/dist/auth/SupabaseKeyCollector.js +61 -0
- package/dist/auth/SupabaseKeyCollector.js.map +1 -0
- package/dist/auth/auth-index.d.ts +10 -0
- package/dist/auth/auth-index.js +11 -0
- package/dist/auth/auth-index.js.map +1 -0
- package/dist/db/db-index.d.ts +1 -0
- package/dist/db/db-index.js +2 -0
- package/dist/db/db-index.js.map +1 -0
- package/dist/db/mongo.d.ts +29 -0
- package/dist/db/mongo.js +65 -0
- package/dist/db/mongo.js.map +1 -0
- package/dist/entry/cli-entry.d.ts +15 -0
- package/dist/entry/cli-entry.js +36 -0
- package/dist/entry/cli-entry.js.map +1 -0
- package/dist/entry/commands/config-command.d.ts +10 -0
- package/dist/entry/commands/config-command.js +21 -0
- package/dist/entry/commands/config-command.js.map +1 -0
- package/dist/entry/commands/migrate-action.d.ts +2 -0
- package/dist/entry/commands/migrate-action.js +18 -0
- package/dist/entry/commands/migrate-action.js.map +1 -0
- package/dist/entry/commands/start-action.d.ts +3 -0
- package/dist/entry/commands/start-action.js +15 -0
- package/dist/entry/commands/start-action.js.map +1 -0
- package/dist/entry/commands/teardown-action.d.ts +2 -0
- package/dist/entry/commands/teardown-action.js +17 -0
- package/dist/entry/commands/teardown-action.js.map +1 -0
- package/dist/entry/entry-index.d.ts +5 -0
- package/dist/entry/entry-index.js +6 -0
- package/dist/entry/entry-index.js.map +1 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.js +26 -0
- package/dist/index.js.map +1 -0
- package/dist/metrics/metrics.d.ts +16 -0
- package/dist/metrics/metrics.js +139 -0
- package/dist/metrics/metrics.js.map +1 -0
- package/dist/migrations/db/migrations/1684951997326-init.d.ts +3 -0
- package/dist/migrations/db/migrations/1684951997326-init.js +31 -0
- package/dist/migrations/db/migrations/1684951997326-init.js.map +1 -0
- package/dist/migrations/db/migrations/1688556755264-initial-sync-rules.d.ts +2 -0
- package/dist/migrations/db/migrations/1688556755264-initial-sync-rules.js +5 -0
- package/dist/migrations/db/migrations/1688556755264-initial-sync-rules.js.map +1 -0
- package/dist/migrations/db/migrations/1702295701188-sync-rule-state.d.ts +3 -0
- package/dist/migrations/db/migrations/1702295701188-sync-rule-state.js +54 -0
- package/dist/migrations/db/migrations/1702295701188-sync-rule-state.js.map +1 -0
- package/dist/migrations/db/migrations/1711543888062-write-checkpoint-index.d.ts +3 -0
- package/dist/migrations/db/migrations/1711543888062-write-checkpoint-index.js +27 -0
- package/dist/migrations/db/migrations/1711543888062-write-checkpoint-index.js.map +1 -0
- package/dist/migrations/db/store.d.ts +3 -0
- package/dist/migrations/db/store.js +10 -0
- package/dist/migrations/db/store.js.map +1 -0
- package/dist/migrations/migrations.d.ts +10 -0
- package/dist/migrations/migrations.js +94 -0
- package/dist/migrations/migrations.js.map +1 -0
- package/dist/replication/ErrorRateLimiter.d.ts +17 -0
- package/dist/replication/ErrorRateLimiter.js +42 -0
- package/dist/replication/ErrorRateLimiter.js.map +1 -0
- package/dist/replication/PgRelation.d.ts +16 -0
- package/dist/replication/PgRelation.js +26 -0
- package/dist/replication/PgRelation.js.map +1 -0
- package/dist/replication/WalConnection.d.ts +34 -0
- package/dist/replication/WalConnection.js +190 -0
- package/dist/replication/WalConnection.js.map +1 -0
- package/dist/replication/WalStream.d.ts +58 -0
- package/dist/replication/WalStream.js +517 -0
- package/dist/replication/WalStream.js.map +1 -0
- package/dist/replication/WalStreamManager.d.ts +30 -0
- package/dist/replication/WalStreamManager.js +199 -0
- package/dist/replication/WalStreamManager.js.map +1 -0
- package/dist/replication/WalStreamRunner.d.ts +38 -0
- package/dist/replication/WalStreamRunner.js +155 -0
- package/dist/replication/WalStreamRunner.js.map +1 -0
- package/dist/replication/replication-index.d.ts +7 -0
- package/dist/replication/replication-index.js +8 -0
- package/dist/replication/replication-index.js.map +1 -0
- package/dist/replication/util.d.ts +9 -0
- package/dist/replication/util.js +62 -0
- package/dist/replication/util.js.map +1 -0
- package/dist/routes/admin.d.ts +7 -0
- package/dist/routes/admin.js +192 -0
- package/dist/routes/admin.js.map +1 -0
- package/dist/routes/auth.d.ts +58 -0
- package/dist/routes/auth.js +182 -0
- package/dist/routes/auth.js.map +1 -0
- package/dist/routes/checkpointing.d.ts +3 -0
- package/dist/routes/checkpointing.js +30 -0
- package/dist/routes/checkpointing.js.map +1 -0
- package/dist/routes/dev.d.ts +6 -0
- package/dist/routes/dev.js +163 -0
- package/dist/routes/dev.js.map +1 -0
- package/dist/routes/route-generators.d.ts +15 -0
- package/dist/routes/route-generators.js +32 -0
- package/dist/routes/route-generators.js.map +1 -0
- package/dist/routes/router-socket.d.ts +10 -0
- package/dist/routes/router-socket.js +5 -0
- package/dist/routes/router-socket.js.map +1 -0
- package/dist/routes/router.d.ts +13 -0
- package/dist/routes/router.js +2 -0
- package/dist/routes/router.js.map +1 -0
- package/dist/routes/routes-index.d.ts +4 -0
- package/dist/routes/routes-index.js +5 -0
- package/dist/routes/routes-index.js.map +1 -0
- package/dist/routes/socket-route.d.ts +2 -0
- package/dist/routes/socket-route.js +119 -0
- package/dist/routes/socket-route.js.map +1 -0
- package/dist/routes/sync-rules.d.ts +6 -0
- package/dist/routes/sync-rules.js +182 -0
- package/dist/routes/sync-rules.js.map +1 -0
- package/dist/routes/sync-stream.d.ts +5 -0
- package/dist/routes/sync-stream.js +74 -0
- package/dist/routes/sync-stream.js.map +1 -0
- package/dist/runner/teardown.d.ts +2 -0
- package/dist/runner/teardown.js +79 -0
- package/dist/runner/teardown.js.map +1 -0
- package/dist/storage/BucketStorage.d.ts +298 -0
- package/dist/storage/BucketStorage.js +25 -0
- package/dist/storage/BucketStorage.js.map +1 -0
- package/dist/storage/MongoBucketStorage.d.ts +51 -0
- package/dist/storage/MongoBucketStorage.js +388 -0
- package/dist/storage/MongoBucketStorage.js.map +1 -0
- package/dist/storage/SourceTable.d.ts +39 -0
- package/dist/storage/SourceTable.js +50 -0
- package/dist/storage/SourceTable.js.map +1 -0
- package/dist/storage/mongo/MongoBucketBatch.d.ts +48 -0
- package/dist/storage/mongo/MongoBucketBatch.js +584 -0
- package/dist/storage/mongo/MongoBucketBatch.js.map +1 -0
- package/dist/storage/mongo/MongoIdSequence.d.ts +12 -0
- package/dist/storage/mongo/MongoIdSequence.js +21 -0
- package/dist/storage/mongo/MongoIdSequence.js.map +1 -0
- package/dist/storage/mongo/MongoPersistedSyncRules.d.ts +9 -0
- package/dist/storage/mongo/MongoPersistedSyncRules.js +9 -0
- package/dist/storage/mongo/MongoPersistedSyncRules.js.map +1 -0
- package/dist/storage/mongo/MongoPersistedSyncRulesContent.d.ts +20 -0
- package/dist/storage/mongo/MongoPersistedSyncRulesContent.js +26 -0
- package/dist/storage/mongo/MongoPersistedSyncRulesContent.js.map +1 -0
- package/dist/storage/mongo/MongoSyncBucketStorage.d.ts +27 -0
- package/dist/storage/mongo/MongoSyncBucketStorage.js +379 -0
- package/dist/storage/mongo/MongoSyncBucketStorage.js.map +1 -0
- package/dist/storage/mongo/MongoSyncRulesLock.d.ts +16 -0
- package/dist/storage/mongo/MongoSyncRulesLock.js +65 -0
- package/dist/storage/mongo/MongoSyncRulesLock.js.map +1 -0
- package/dist/storage/mongo/OperationBatch.d.ts +26 -0
- package/dist/storage/mongo/OperationBatch.js +101 -0
- package/dist/storage/mongo/OperationBatch.js.map +1 -0
- package/dist/storage/mongo/PersistedBatch.d.ts +42 -0
- package/dist/storage/mongo/PersistedBatch.js +200 -0
- package/dist/storage/mongo/PersistedBatch.js.map +1 -0
- package/dist/storage/mongo/db.d.ts +23 -0
- package/dist/storage/mongo/db.js +34 -0
- package/dist/storage/mongo/db.js.map +1 -0
- package/dist/storage/mongo/models.d.ts +137 -0
- package/dist/storage/mongo/models.js +27 -0
- package/dist/storage/mongo/models.js.map +1 -0
- package/dist/storage/mongo/util.d.ts +26 -0
- package/dist/storage/mongo/util.js +81 -0
- package/dist/storage/mongo/util.js.map +1 -0
- package/dist/storage/storage-index.d.ts +14 -0
- package/dist/storage/storage-index.js +15 -0
- package/dist/storage/storage-index.js.map +1 -0
- package/dist/sync/BroadcastIterable.d.ts +38 -0
- package/dist/sync/BroadcastIterable.js +153 -0
- package/dist/sync/BroadcastIterable.js.map +1 -0
- package/dist/sync/LastValueSink.d.ts +25 -0
- package/dist/sync/LastValueSink.js +84 -0
- package/dist/sync/LastValueSink.js.map +1 -0
- package/dist/sync/merge.d.ts +39 -0
- package/dist/sync/merge.js +175 -0
- package/dist/sync/merge.js.map +1 -0
- package/dist/sync/safeRace.d.ts +1 -0
- package/dist/sync/safeRace.js +91 -0
- package/dist/sync/safeRace.js.map +1 -0
- package/dist/sync/sync-index.d.ts +6 -0
- package/dist/sync/sync-index.js +7 -0
- package/dist/sync/sync-index.js.map +1 -0
- package/dist/sync/sync.d.ts +18 -0
- package/dist/sync/sync.js +248 -0
- package/dist/sync/sync.js.map +1 -0
- package/dist/sync/util.d.ts +26 -0
- package/dist/sync/util.js +73 -0
- package/dist/sync/util.js.map +1 -0
- package/dist/system/CorePowerSyncSystem.d.ts +18 -0
- package/dist/system/CorePowerSyncSystem.js +28 -0
- package/dist/system/CorePowerSyncSystem.js.map +1 -0
- package/dist/util/Mutex.d.ts +47 -0
- package/dist/util/Mutex.js +132 -0
- package/dist/util/Mutex.js.map +1 -0
- package/dist/util/PgManager.d.ts +24 -0
- package/dist/util/PgManager.js +55 -0
- package/dist/util/PgManager.js.map +1 -0
- package/dist/util/alerting.d.ts +4 -0
- package/dist/util/alerting.js +14 -0
- package/dist/util/alerting.js.map +1 -0
- package/dist/util/config/collectors/config-collector.d.ts +29 -0
- package/dist/util/config/collectors/config-collector.js +116 -0
- package/dist/util/config/collectors/config-collector.js.map +1 -0
- package/dist/util/config/collectors/impl/base64-config-collector.d.ts +6 -0
- package/dist/util/config/collectors/impl/base64-config-collector.js +15 -0
- package/dist/util/config/collectors/impl/base64-config-collector.js.map +1 -0
- package/dist/util/config/collectors/impl/fallback-config-collector.d.ts +11 -0
- package/dist/util/config/collectors/impl/fallback-config-collector.js +19 -0
- package/dist/util/config/collectors/impl/fallback-config-collector.js.map +1 -0
- package/dist/util/config/collectors/impl/filesystem-config-collector.d.ts +6 -0
- package/dist/util/config/collectors/impl/filesystem-config-collector.js +35 -0
- package/dist/util/config/collectors/impl/filesystem-config-collector.js.map +1 -0
- package/dist/util/config/compound-config-collector.d.ts +32 -0
- package/dist/util/config/compound-config-collector.js +126 -0
- package/dist/util/config/compound-config-collector.js.map +1 -0
- package/dist/util/config/sync-rules/impl/base64-sync-rules-collector.d.ts +7 -0
- package/dist/util/config/sync-rules/impl/base64-sync-rules-collector.js +17 -0
- package/dist/util/config/sync-rules/impl/base64-sync-rules-collector.js.map +1 -0
- package/dist/util/config/sync-rules/impl/filesystem-sync-rules-collector.d.ts +7 -0
- package/dist/util/config/sync-rules/impl/filesystem-sync-rules-collector.js +21 -0
- package/dist/util/config/sync-rules/impl/filesystem-sync-rules-collector.js.map +1 -0
- package/dist/util/config/sync-rules/impl/inline-sync-rules-collector.d.ts +7 -0
- package/dist/util/config/sync-rules/impl/inline-sync-rules-collector.js +17 -0
- package/dist/util/config/sync-rules/impl/inline-sync-rules-collector.js.map +1 -0
- package/dist/util/config/sync-rules/sync-collector.d.ts +6 -0
- package/dist/util/config/sync-rules/sync-collector.js +3 -0
- package/dist/util/config/sync-rules/sync-collector.js.map +1 -0
- package/dist/util/config/types.d.ts +53 -0
- package/dist/util/config/types.js +7 -0
- package/dist/util/config/types.js.map +1 -0
- package/dist/util/config.d.ts +7 -0
- package/dist/util/config.js +35 -0
- package/dist/util/config.js.map +1 -0
- package/dist/util/env.d.ts +10 -0
- package/dist/util/env.js +25 -0
- package/dist/util/env.js.map +1 -0
- package/dist/util/memory-tracking.d.ts +7 -0
- package/dist/util/memory-tracking.js +58 -0
- package/dist/util/memory-tracking.js.map +1 -0
- package/dist/util/migration_lib.d.ts +11 -0
- package/dist/util/migration_lib.js +64 -0
- package/dist/util/migration_lib.js.map +1 -0
- package/dist/util/pgwire_utils.d.ts +24 -0
- package/dist/util/pgwire_utils.js +117 -0
- package/dist/util/pgwire_utils.js.map +1 -0
- package/dist/util/populate_test_data.d.ts +8 -0
- package/dist/util/populate_test_data.js +65 -0
- package/dist/util/populate_test_data.js.map +1 -0
- package/dist/util/protocol-types.d.ts +178 -0
- package/dist/util/protocol-types.js +38 -0
- package/dist/util/protocol-types.js.map +1 -0
- package/dist/util/secs.d.ts +2 -0
- package/dist/util/secs.js +49 -0
- package/dist/util/secs.js.map +1 -0
- package/dist/util/util-index.d.ts +22 -0
- package/dist/util/util-index.js +23 -0
- package/dist/util/util-index.js.map +1 -0
- package/dist/util/utils.d.ts +14 -0
- package/dist/util/utils.js +75 -0
- package/dist/util/utils.js.map +1 -0
- package/package.json +55 -0
- package/src/api/api-index.ts +2 -0
- package/src/api/diagnostics.ts +221 -0
- package/src/api/schema.ts +99 -0
- package/src/auth/CachedKeyCollector.ts +132 -0
- package/src/auth/CompoundKeyCollector.ts +33 -0
- package/src/auth/JwtPayload.ts +11 -0
- package/src/auth/KeyCollector.ts +27 -0
- package/src/auth/KeySpec.ts +67 -0
- package/src/auth/KeyStore.ts +156 -0
- package/src/auth/LeakyBucket.ts +66 -0
- package/src/auth/RemoteJWKSCollector.ts +130 -0
- package/src/auth/StaticKeyCollector.ts +21 -0
- package/src/auth/SupabaseKeyCollector.ts +67 -0
- package/src/auth/auth-index.ts +10 -0
- package/src/db/db-index.ts +1 -0
- package/src/db/mongo.ts +72 -0
- package/src/entry/cli-entry.ts +41 -0
- package/src/entry/commands/config-command.ts +36 -0
- package/src/entry/commands/migrate-action.ts +25 -0
- package/src/entry/commands/start-action.ts +24 -0
- package/src/entry/commands/teardown-action.ts +23 -0
- package/src/entry/entry-index.ts +5 -0
- package/src/index.ts +37 -0
- package/src/metrics/metrics.ts +169 -0
- package/src/migrations/db/migrations/1684951997326-init.ts +33 -0
- package/src/migrations/db/migrations/1688556755264-initial-sync-rules.ts +5 -0
- package/src/migrations/db/migrations/1702295701188-sync-rule-state.ts +99 -0
- package/src/migrations/db/migrations/1711543888062-write-checkpoint-index.ts +32 -0
- package/src/migrations/db/store.ts +11 -0
- package/src/migrations/migrations.ts +122 -0
- package/src/replication/ErrorRateLimiter.ts +49 -0
- package/src/replication/PgRelation.ts +42 -0
- package/src/replication/WalConnection.ts +227 -0
- package/src/replication/WalStream.ts +626 -0
- package/src/replication/WalStreamManager.ts +214 -0
- package/src/replication/WalStreamRunner.ts +180 -0
- package/src/replication/replication-index.ts +7 -0
- package/src/replication/util.ts +76 -0
- package/src/routes/admin.ts +229 -0
- package/src/routes/auth.ts +209 -0
- package/src/routes/checkpointing.ts +38 -0
- package/src/routes/dev.ts +194 -0
- package/src/routes/route-generators.ts +39 -0
- package/src/routes/router-socket.ts +13 -0
- package/src/routes/router.ts +17 -0
- package/src/routes/routes-index.ts +5 -0
- package/src/routes/socket-route.ts +131 -0
- package/src/routes/sync-rules.ts +210 -0
- package/src/routes/sync-stream.ts +92 -0
- package/src/runner/teardown.ts +91 -0
- package/src/storage/BucketStorage.ts +386 -0
- package/src/storage/MongoBucketStorage.ts +493 -0
- package/src/storage/SourceTable.ts +60 -0
- package/src/storage/mongo/MongoBucketBatch.ts +756 -0
- package/src/storage/mongo/MongoIdSequence.ts +24 -0
- package/src/storage/mongo/MongoPersistedSyncRules.ts +16 -0
- package/src/storage/mongo/MongoPersistedSyncRulesContent.ts +47 -0
- package/src/storage/mongo/MongoSyncBucketStorage.ts +517 -0
- package/src/storage/mongo/MongoSyncRulesLock.ts +81 -0
- package/src/storage/mongo/OperationBatch.ts +115 -0
- package/src/storage/mongo/PersistedBatch.ts +245 -0
- package/src/storage/mongo/db.ts +69 -0
- package/src/storage/mongo/models.ts +157 -0
- package/src/storage/mongo/util.ts +88 -0
- package/src/storage/storage-index.ts +15 -0
- package/src/sync/BroadcastIterable.ts +161 -0
- package/src/sync/LastValueSink.ts +100 -0
- package/src/sync/merge.ts +200 -0
- package/src/sync/safeRace.ts +99 -0
- package/src/sync/sync-index.ts +6 -0
- package/src/sync/sync.ts +312 -0
- package/src/sync/util.ts +98 -0
- package/src/system/CorePowerSyncSystem.ts +43 -0
- package/src/util/Mutex.ts +159 -0
- package/src/util/PgManager.ts +64 -0
- package/src/util/alerting.ts +17 -0
- package/src/util/config/collectors/config-collector.ts +141 -0
- package/src/util/config/collectors/impl/base64-config-collector.ts +18 -0
- package/src/util/config/collectors/impl/fallback-config-collector.ts +22 -0
- package/src/util/config/collectors/impl/filesystem-config-collector.ts +41 -0
- package/src/util/config/compound-config-collector.ts +171 -0
- package/src/util/config/sync-rules/impl/base64-sync-rules-collector.ts +21 -0
- package/src/util/config/sync-rules/impl/filesystem-sync-rules-collector.ts +26 -0
- package/src/util/config/sync-rules/impl/inline-sync-rules-collector.ts +21 -0
- package/src/util/config/sync-rules/sync-collector.ts +8 -0
- package/src/util/config/types.ts +60 -0
- package/src/util/config.ts +39 -0
- package/src/util/env.ts +28 -0
- package/src/util/memory-tracking.ts +67 -0
- package/src/util/migration_lib.ts +79 -0
- package/src/util/pgwire_utils.ts +139 -0
- package/src/util/populate_test_data.ts +78 -0
- package/src/util/protocol-types.ts +223 -0
- package/src/util/secs.ts +54 -0
- package/src/util/util-index.ts +25 -0
- package/src/util/utils.ts +102 -0
- package/test/src/__snapshots__/pg_test.test.ts.snap +256 -0
- package/test/src/__snapshots__/sync.test.ts.snap +235 -0
- package/test/src/auth.test.ts +340 -0
- package/test/src/broadcast_iterable.test.ts +156 -0
- package/test/src/data_storage.test.ts +1176 -0
- package/test/src/env.ts +8 -0
- package/test/src/large_batch.test.ts +194 -0
- package/test/src/merge_iterable.test.ts +355 -0
- package/test/src/pg_test.test.ts +432 -0
- package/test/src/schema_changes.test.ts +545 -0
- package/test/src/slow_tests.test.ts +257 -0
- package/test/src/sql_functions.test.ts +254 -0
- package/test/src/sql_operators.test.ts +132 -0
- package/test/src/sync.test.ts +293 -0
- package/test/src/sync_rules.test.ts +1051 -0
- package/test/src/util.ts +67 -0
- package/test/src/validation.test.ts +63 -0
- package/test/src/wal_stream.test.ts +310 -0
- package/test/src/wal_stream_utils.ts +147 -0
- package/test/tsconfig.json +20 -0
- package/tsconfig.json +20 -0
- package/tsconfig.tsbuildinfo +1 -0
- package/vitest.config.ts +11 -0
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import * as t from 'ts-codec';
|
|
2
|
+
import { ReactiveSocketRouter, IReactiveStream } from '@powersync/service-rsocket-router';
|
|
3
|
+
|
|
4
|
+
import { Context } from './router.js';
|
|
5
|
+
|
|
6
|
+
export const RSocketContextMeta = t.object({
|
|
7
|
+
token: t.string
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Creates a socket route handler given a router instance
|
|
12
|
+
*/
|
|
13
|
+
export type SocketRouteGenerator = (router: ReactiveSocketRouter<Context>) => IReactiveStream;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import * as micro from '@journeyapps-platform/micro';
|
|
2
|
+
|
|
3
|
+
import * as auth from '@/auth/auth-index.js';
|
|
4
|
+
import { CorePowerSyncSystem } from '../system/CorePowerSyncSystem.js';
|
|
5
|
+
|
|
6
|
+
export type Context = {
|
|
7
|
+
user_id?: string;
|
|
8
|
+
system: CorePowerSyncSystem;
|
|
9
|
+
|
|
10
|
+
token_payload?: auth.JwtPayload;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Creates a route handler given a router instance
|
|
15
|
+
* TODO move away from Fastify specific types
|
|
16
|
+
*/
|
|
17
|
+
export type RouteGenerator = (router: micro.fastify.FastifyRouter<Context>) => micro.router.Route;
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { serialize } from 'bson';
|
|
2
|
+
import { SyncParameters, normalizeTokenParameters } from '@powersync/service-sync-rules';
|
|
3
|
+
import * as micro from '@journeyapps-platform/micro';
|
|
4
|
+
|
|
5
|
+
import * as util from '@/util/util-index.js';
|
|
6
|
+
import { concurrent_connections, data_synced_bytes } from '../metrics/metrics.js';
|
|
7
|
+
import { streamResponse } from '../sync/sync.js';
|
|
8
|
+
import { SyncRoutes } from './sync-stream.js';
|
|
9
|
+
import { SocketRouteGenerator } from './router-socket.js';
|
|
10
|
+
|
|
11
|
+
export const sync_stream_reactive: SocketRouteGenerator = (router) =>
|
|
12
|
+
router.reactiveStream<util.StreamingSyncRequest, any>(SyncRoutes.STREAM, {
|
|
13
|
+
authorize: ({ context }) => {
|
|
14
|
+
return {
|
|
15
|
+
authorized: !!context.token_payload,
|
|
16
|
+
errors: ['Authentication required']
|
|
17
|
+
};
|
|
18
|
+
},
|
|
19
|
+
validator: micro.schema.createTsCodecValidator(util.StreamingSyncRequest, { allowAdditional: true }),
|
|
20
|
+
handler: async ({ context, params, responder, observer, initialN }) => {
|
|
21
|
+
const { system } = context;
|
|
22
|
+
|
|
23
|
+
if (system.closed) {
|
|
24
|
+
responder.onError(
|
|
25
|
+
new micro.errors.JourneyError({
|
|
26
|
+
status: 503,
|
|
27
|
+
code: 'SERVICE_UNAVAILABLE',
|
|
28
|
+
description: 'Service temporarily unavailable'
|
|
29
|
+
})
|
|
30
|
+
);
|
|
31
|
+
responder.onComplete();
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const controller = new AbortController();
|
|
36
|
+
|
|
37
|
+
const syncParams: SyncParameters = normalizeTokenParameters(context.token_payload?.parameters ?? {});
|
|
38
|
+
const storage = system.storage;
|
|
39
|
+
// Sanity check before we start the stream
|
|
40
|
+
const cp = await storage.getActiveCheckpoint();
|
|
41
|
+
if (!cp.hasSyncRules()) {
|
|
42
|
+
responder.onError(
|
|
43
|
+
new micro.errors.JourneyError({
|
|
44
|
+
status: 500,
|
|
45
|
+
code: 'NO_SYNC_RULES',
|
|
46
|
+
description: 'No sync rules available'
|
|
47
|
+
})
|
|
48
|
+
);
|
|
49
|
+
responder.onComplete();
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
let requestedN = initialN;
|
|
54
|
+
const disposer = observer.registerListener({
|
|
55
|
+
request(n) {
|
|
56
|
+
requestedN += n;
|
|
57
|
+
},
|
|
58
|
+
cancel: () => {
|
|
59
|
+
controller.abort();
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
const removeStopHandler = system.addStopHandler(() => {
|
|
64
|
+
observer.triggerCancel();
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
concurrent_connections.add(1);
|
|
68
|
+
try {
|
|
69
|
+
for await (const data of streamResponse({
|
|
70
|
+
storage,
|
|
71
|
+
params: {
|
|
72
|
+
...params,
|
|
73
|
+
binary_data: true // always true for web sockets
|
|
74
|
+
},
|
|
75
|
+
syncParams,
|
|
76
|
+
token: context!.token_payload!,
|
|
77
|
+
tokenStreamOptions: {
|
|
78
|
+
// RSocket handles keepalive events by default
|
|
79
|
+
keep_alive: false
|
|
80
|
+
},
|
|
81
|
+
signal: controller.signal
|
|
82
|
+
})) {
|
|
83
|
+
if (data == null) {
|
|
84
|
+
// Empty value just to flush iterator memory
|
|
85
|
+
continue;
|
|
86
|
+
} else if (typeof data == 'string') {
|
|
87
|
+
// Should not happen with binary_data: true
|
|
88
|
+
throw new Error(`Unexpected string data: ${data}`);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
{
|
|
92
|
+
// On NodeJS, serialize always returns a Buffer
|
|
93
|
+
const serialized = serialize(data) as Buffer;
|
|
94
|
+
responder.onNext({ data: serialized }, false);
|
|
95
|
+
requestedN--;
|
|
96
|
+
data_synced_bytes.add(serialized.length);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (requestedN <= 0) {
|
|
100
|
+
await new Promise<void>((resolve) => {
|
|
101
|
+
const l = observer.registerListener({
|
|
102
|
+
request() {
|
|
103
|
+
if (requestedN > 0) {
|
|
104
|
+
// Management of updating the total requested items is done above
|
|
105
|
+
resolve();
|
|
106
|
+
l();
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
cancel: () => {
|
|
110
|
+
// Don't wait here if the request is cancelled
|
|
111
|
+
resolve();
|
|
112
|
+
l();
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
} catch (ex) {
|
|
119
|
+
// Convert to our standard form before responding.
|
|
120
|
+
// This ensures the error can be serialized.
|
|
121
|
+
const error = new micro.errors.InternalServerError(ex);
|
|
122
|
+
micro.logger.error('Sync stream error', error);
|
|
123
|
+
responder.onError(error);
|
|
124
|
+
} finally {
|
|
125
|
+
responder.onComplete();
|
|
126
|
+
removeStopHandler();
|
|
127
|
+
disposer();
|
|
128
|
+
concurrent_connections.add(-1);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
});
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import * as t from 'ts-codec';
|
|
2
|
+
import { FastifyPluginAsync, FastifyReply } from 'fastify';
|
|
3
|
+
import * as micro from '@journeyapps-platform/micro';
|
|
4
|
+
import * as pgwire from '@powersync/service-jpgwire';
|
|
5
|
+
import { SqlSyncRules, SyncRulesErrors } from '@powersync/service-sync-rules';
|
|
6
|
+
|
|
7
|
+
import * as replication from '@/replication/replication-index.js';
|
|
8
|
+
import { authApi } from './auth.js';
|
|
9
|
+
import { RouteGenerator } from './router.js';
|
|
10
|
+
|
|
11
|
+
const DeploySyncRulesRequest = t.object({
|
|
12
|
+
content: t.string
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
const yamlPlugin: FastifyPluginAsync = async (fastify) => {
|
|
16
|
+
fastify.addContentTypeParser('application/yaml', async (request, payload, _d) => {
|
|
17
|
+
const data = await micro.streaming.drain(payload);
|
|
18
|
+
|
|
19
|
+
request.params = { content: Buffer.concat(data).toString('utf8') };
|
|
20
|
+
});
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export const deploySyncRules: RouteGenerator = (router) =>
|
|
24
|
+
router.post('/api/sync-rules/v1/deploy', {
|
|
25
|
+
authorize: authApi,
|
|
26
|
+
parse: true,
|
|
27
|
+
plugins: [yamlPlugin],
|
|
28
|
+
validator: micro.schema.createTsCodecValidator(DeploySyncRulesRequest, { allowAdditional: true }),
|
|
29
|
+
handler: async (payload) => {
|
|
30
|
+
if (payload.context.system.config.sync_rules.present) {
|
|
31
|
+
// If sync rules are configured via the config, disable deploy via the API.
|
|
32
|
+
throw new micro.errors.JourneyError({
|
|
33
|
+
status: 422,
|
|
34
|
+
code: 'API_DISABLED',
|
|
35
|
+
description: 'Sync rules API disabled',
|
|
36
|
+
details: 'Use the management API to deploy sync rules'
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
const content = payload.params.content;
|
|
40
|
+
|
|
41
|
+
try {
|
|
42
|
+
SqlSyncRules.fromYaml(payload.params.content);
|
|
43
|
+
} catch (e) {
|
|
44
|
+
throw new micro.errors.JourneyError({
|
|
45
|
+
status: 422,
|
|
46
|
+
code: 'INVALID_SYNC_RULES',
|
|
47
|
+
description: 'Sync rules parsing failed',
|
|
48
|
+
details: e.message
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const sync_rules = await payload.context.system.storage.updateSyncRules({
|
|
53
|
+
content: content
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
return {
|
|
57
|
+
slot_name: sync_rules.slot_name
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
const ValidateSyncRulesRequest = t.object({
|
|
63
|
+
content: t.string
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
export const validateSyncRules: RouteGenerator = (router) =>
|
|
67
|
+
router.post('/api/sync-rules/v1/validate', {
|
|
68
|
+
authorize: authApi,
|
|
69
|
+
parse: true,
|
|
70
|
+
plugins: [yamlPlugin],
|
|
71
|
+
validator: micro.schema.createTsCodecValidator(ValidateSyncRulesRequest, { allowAdditional: true }),
|
|
72
|
+
handler: async (payload) => {
|
|
73
|
+
const content = payload.params.content;
|
|
74
|
+
|
|
75
|
+
const info = await debugSyncRules(payload.context.system.requirePgPool(), content);
|
|
76
|
+
|
|
77
|
+
replyPrettyJson(payload.reply, info);
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
export const currentSyncRules: RouteGenerator = (router) =>
|
|
82
|
+
router.get('/api/sync-rules/v1/current', {
|
|
83
|
+
authorize: authApi,
|
|
84
|
+
handler: async (payload) => {
|
|
85
|
+
const storage = payload.context.system.storage;
|
|
86
|
+
const sync_rules = await storage.getActiveSyncRulesContent();
|
|
87
|
+
if (!sync_rules) {
|
|
88
|
+
throw new micro.errors.JourneyError({
|
|
89
|
+
status: 422,
|
|
90
|
+
code: 'NO_SYNC_RULES',
|
|
91
|
+
description: 'No active sync rules'
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
const info = await debugSyncRules(payload.context.system.requirePgPool(), sync_rules.sync_rules_content);
|
|
95
|
+
const next = await storage.getNextSyncRulesContent();
|
|
96
|
+
|
|
97
|
+
const next_info = next
|
|
98
|
+
? await debugSyncRules(payload.context.system.requirePgPool(), next.sync_rules_content)
|
|
99
|
+
: null;
|
|
100
|
+
|
|
101
|
+
const response = {
|
|
102
|
+
current: {
|
|
103
|
+
slot_name: sync_rules.slot_name,
|
|
104
|
+
content: sync_rules.sync_rules_content,
|
|
105
|
+
...info
|
|
106
|
+
},
|
|
107
|
+
next:
|
|
108
|
+
next == null
|
|
109
|
+
? null
|
|
110
|
+
: {
|
|
111
|
+
slot_name: next.slot_name,
|
|
112
|
+
content: next.sync_rules_content,
|
|
113
|
+
...next_info
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
replyPrettyJson(payload.reply, { data: response });
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
const ReprocessSyncRulesRequest = t.object({});
|
|
121
|
+
|
|
122
|
+
export const reprocessSyncRules: RouteGenerator = (router) =>
|
|
123
|
+
router.post('/api/sync-rules/v1/reprocess', {
|
|
124
|
+
authorize: authApi,
|
|
125
|
+
validator: micro.schema.createTsCodecValidator(ReprocessSyncRulesRequest),
|
|
126
|
+
handler: async (payload) => {
|
|
127
|
+
const storage = payload.context.system.storage;
|
|
128
|
+
const sync_rules = await storage.getActiveSyncRules();
|
|
129
|
+
if (sync_rules == null) {
|
|
130
|
+
throw new micro.errors.JourneyError({
|
|
131
|
+
status: 422,
|
|
132
|
+
code: 'NO_SYNC_RULES',
|
|
133
|
+
description: 'No active sync rules'
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const new_rules = await storage.updateSyncRules({
|
|
138
|
+
content: sync_rules.sync_rules.content
|
|
139
|
+
});
|
|
140
|
+
return {
|
|
141
|
+
slot_name: new_rules.slot_name
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
export const syncRulesRoutes = [validateSyncRules, deploySyncRules, reprocessSyncRules, currentSyncRules];
|
|
147
|
+
|
|
148
|
+
function replyPrettyJson(reply: FastifyReply, payload: any) {
|
|
149
|
+
reply
|
|
150
|
+
.status(200)
|
|
151
|
+
.header('Content-Type', 'application/json')
|
|
152
|
+
.send(JSON.stringify(payload, null, 2) + '\n');
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
async function debugSyncRules(db: pgwire.PgClient, sync_rules: string) {
|
|
156
|
+
try {
|
|
157
|
+
const rules = SqlSyncRules.fromYaml(sync_rules);
|
|
158
|
+
const source_table_patterns = rules.getSourceTables();
|
|
159
|
+
const wc = new replication.WalConnection({
|
|
160
|
+
db: db,
|
|
161
|
+
sync_rules: rules
|
|
162
|
+
});
|
|
163
|
+
const resolved_tables = await wc.getDebugTablesInfo(source_table_patterns);
|
|
164
|
+
|
|
165
|
+
return {
|
|
166
|
+
valid: true,
|
|
167
|
+
bucket_definitions: rules.bucket_descriptors.map((d) => {
|
|
168
|
+
let all_parameter_queries = [...d.parameter_queries.values()].flat();
|
|
169
|
+
let all_data_queries = [...d.data_queries.values()].flat();
|
|
170
|
+
return {
|
|
171
|
+
name: d.name,
|
|
172
|
+
bucket_parameters: d.bucket_parameters,
|
|
173
|
+
global_parameter_queries: d.global_parameter_queries.map((q) => {
|
|
174
|
+
return {
|
|
175
|
+
sql: q.sql
|
|
176
|
+
};
|
|
177
|
+
}),
|
|
178
|
+
parameter_queries: all_parameter_queries.map((q) => {
|
|
179
|
+
return {
|
|
180
|
+
sql: q.sql,
|
|
181
|
+
table: q.sourceTable,
|
|
182
|
+
input_parameters: q.input_parameters
|
|
183
|
+
};
|
|
184
|
+
}),
|
|
185
|
+
|
|
186
|
+
data_queries: all_data_queries.map((q) => {
|
|
187
|
+
return {
|
|
188
|
+
sql: q.sql,
|
|
189
|
+
table: q.sourceTable,
|
|
190
|
+
columns: q.columnOutputNames()
|
|
191
|
+
};
|
|
192
|
+
})
|
|
193
|
+
};
|
|
194
|
+
}),
|
|
195
|
+
source_tables: resolved_tables,
|
|
196
|
+
data_tables: rules.debugGetOutputTables()
|
|
197
|
+
};
|
|
198
|
+
} catch (e) {
|
|
199
|
+
if (e instanceof SyncRulesErrors) {
|
|
200
|
+
return {
|
|
201
|
+
valid: false,
|
|
202
|
+
errors: e.errors.map((e) => e.message)
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
return {
|
|
206
|
+
valid: false,
|
|
207
|
+
errors: [e.message]
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { Readable } from 'stream';
|
|
2
|
+
import * as micro from '@journeyapps-platform/micro';
|
|
3
|
+
import { SyncParameters, normalizeTokenParameters } from '@powersync/service-sync-rules';
|
|
4
|
+
|
|
5
|
+
import * as sync from '@/sync/sync-index.js';
|
|
6
|
+
import * as util from '@/util/util-index.js';
|
|
7
|
+
import { concurrent_connections } from '../metrics/metrics.js';
|
|
8
|
+
|
|
9
|
+
import { authUser } from './auth.js';
|
|
10
|
+
import { RouteGenerator } from './router.js';
|
|
11
|
+
|
|
12
|
+
export enum SyncRoutes {
|
|
13
|
+
STREAM = '/sync/stream'
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export const syncStreamed: RouteGenerator = (router) =>
|
|
17
|
+
router.post(SyncRoutes.STREAM, {
|
|
18
|
+
authorize: authUser,
|
|
19
|
+
validator: micro.schema.createTsCodecValidator(util.StreamingSyncRequest, { allowAdditional: true }),
|
|
20
|
+
handler: async (payload) => {
|
|
21
|
+
const userId = payload.context.user_id!;
|
|
22
|
+
const system = payload.context.system;
|
|
23
|
+
|
|
24
|
+
if (system.closed) {
|
|
25
|
+
throw new micro.errors.JourneyError({
|
|
26
|
+
status: 503,
|
|
27
|
+
code: 'SERVICE_UNAVAILABLE',
|
|
28
|
+
description: 'Service temporarily unavailable'
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const params: util.StreamingSyncRequest = payload.params;
|
|
33
|
+
const syncParams: SyncParameters = normalizeTokenParameters(payload.context.token_payload!.parameters ?? {});
|
|
34
|
+
|
|
35
|
+
const storage = system.storage;
|
|
36
|
+
// Sanity check before we start the stream
|
|
37
|
+
const cp = await storage.getActiveCheckpoint();
|
|
38
|
+
if (!cp.hasSyncRules()) {
|
|
39
|
+
throw new micro.errors.JourneyError({
|
|
40
|
+
status: 500,
|
|
41
|
+
code: 'NO_SYNC_RULES',
|
|
42
|
+
description: 'No sync rules available'
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const res = payload.reply;
|
|
47
|
+
|
|
48
|
+
res.status(200).header('Content-Type', 'application/x-ndjson');
|
|
49
|
+
|
|
50
|
+
const controller = new AbortController();
|
|
51
|
+
try {
|
|
52
|
+
concurrent_connections.add(1);
|
|
53
|
+
const stream = Readable.from(
|
|
54
|
+
sync.transformToBytesTracked(
|
|
55
|
+
sync.ndjson(
|
|
56
|
+
sync.streamResponse({
|
|
57
|
+
storage,
|
|
58
|
+
params,
|
|
59
|
+
syncParams,
|
|
60
|
+
token: payload.context.token_payload!,
|
|
61
|
+
signal: controller.signal
|
|
62
|
+
})
|
|
63
|
+
)
|
|
64
|
+
),
|
|
65
|
+
{ objectMode: false, highWaterMark: 16 * 1024 }
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
const deregister = system.addStopHandler(() => {
|
|
69
|
+
// This error is not currently propagated to the client
|
|
70
|
+
controller.abort();
|
|
71
|
+
stream.destroy(new Error('Shutting down system'));
|
|
72
|
+
});
|
|
73
|
+
stream.on('close', () => {
|
|
74
|
+
deregister();
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
stream.on('error', (error) => {
|
|
78
|
+
controller.abort();
|
|
79
|
+
// Note: This appears as a 200 response in the logs.
|
|
80
|
+
if (error.message != 'Shutting down system') {
|
|
81
|
+
micro.logger.error('Streaming sync request failed', error);
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
await res.send(stream);
|
|
85
|
+
} finally {
|
|
86
|
+
controller.abort();
|
|
87
|
+
concurrent_connections.add(-1);
|
|
88
|
+
// Prevent double-send
|
|
89
|
+
res.hijack();
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
});
|
|
@@ -0,0 +1,91 @@
|
|
|
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.
|
|
5
|
+
|
|
6
|
+
import * as micro from '@journeyapps-platform/micro';
|
|
7
|
+
import * as timers from 'timers/promises';
|
|
8
|
+
|
|
9
|
+
import * as db from '../db/db-index.js';
|
|
10
|
+
import * as storage from '../storage/storage-index.js';
|
|
11
|
+
import * as utils from '../util/util-index.js';
|
|
12
|
+
import * as replication from '../replication/replication-index.js';
|
|
13
|
+
|
|
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();
|
|
27
|
+
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
|
+
});
|
|
36
|
+
console.log('terminating', stream.slot_name);
|
|
37
|
+
await stream.terminate();
|
|
38
|
+
console.log('terminated', stream.slot_name);
|
|
39
|
+
} finally {
|
|
40
|
+
await lock.release();
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Terminate all replicating sync rules, deleting the replication slots.
|
|
46
|
+
*
|
|
47
|
+
* Retries lock and other errors for up to two minutes.
|
|
48
|
+
*
|
|
49
|
+
* This is a best-effot attempt. In some cases it may not be possible to delete the replication
|
|
50
|
+
* slot, such as when the postgres instance is unreachable.
|
|
51
|
+
*/
|
|
52
|
+
async function terminateReplicators(
|
|
53
|
+
storageFactory: storage.BucketStorageFactory,
|
|
54
|
+
connection: utils.ResolvedConnection
|
|
55
|
+
) {
|
|
56
|
+
const start = Date.now();
|
|
57
|
+
while (Date.now() - start < 12_000) {
|
|
58
|
+
let retry = false;
|
|
59
|
+
const replicationRules = await storageFactory.getReplicatingSyncRules();
|
|
60
|
+
for (let syncRules of replicationRules) {
|
|
61
|
+
try {
|
|
62
|
+
await terminateReplicator(storageFactory, connection, syncRules);
|
|
63
|
+
} catch (e) {
|
|
64
|
+
retry = true;
|
|
65
|
+
console.error(e);
|
|
66
|
+
micro.logger.warn(`Failed to terminate ${syncRules.slot_name}`, e);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
if (!retry) {
|
|
70
|
+
break;
|
|
71
|
+
}
|
|
72
|
+
await timers.setTimeout(5_000);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export async function teardown(runnerConfig: utils.RunnerConfig) {
|
|
77
|
+
const config = await utils.loadConfig(runnerConfig);
|
|
78
|
+
const mongoDB = storage.createPowerSyncMongo(config.storage);
|
|
79
|
+
await db.mongo.waitForAuth(mongoDB.db);
|
|
80
|
+
|
|
81
|
+
const bucketStorage = new storage.MongoBucketStorage(mongoDB, { slot_name_prefix: config.slot_name_prefix });
|
|
82
|
+
const connection = config.connection;
|
|
83
|
+
|
|
84
|
+
if (connection) {
|
|
85
|
+
await terminateReplicators(bucketStorage, connection);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const database = mongoDB.db;
|
|
89
|
+
await database.dropDatabase();
|
|
90
|
+
await mongoDB.client.close();
|
|
91
|
+
}
|