@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
package/src/index.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// Provides global and namespaced exports
|
|
2
|
+
|
|
3
|
+
export * from './api/api-index.js';
|
|
4
|
+
export * as api from './api/api-index.js';
|
|
5
|
+
|
|
6
|
+
export * from './auth/auth-index.js';
|
|
7
|
+
export * as auth from './auth/auth-index.js';
|
|
8
|
+
|
|
9
|
+
export * from './db/db-index.js';
|
|
10
|
+
export * as db from './db/db-index.js';
|
|
11
|
+
|
|
12
|
+
export * from './entry/entry-index.js';
|
|
13
|
+
export * as entry from './entry/entry-index.js';
|
|
14
|
+
|
|
15
|
+
export * from './metrics/metrics.js';
|
|
16
|
+
export * as metrics from './metrics/metrics.js';
|
|
17
|
+
|
|
18
|
+
export * from './migrations/migrations.js';
|
|
19
|
+
export * as migrations from './migrations/migrations.js';
|
|
20
|
+
|
|
21
|
+
export * from './replication/replication-index.js';
|
|
22
|
+
export * as replication from './replication/replication-index.js';
|
|
23
|
+
|
|
24
|
+
export * from './routes/routes-index.js';
|
|
25
|
+
export * as routes from './routes/routes-index.js';
|
|
26
|
+
|
|
27
|
+
export * from './storage/storage-index.js';
|
|
28
|
+
export * as storage from './storage/storage-index.js';
|
|
29
|
+
|
|
30
|
+
export * from './sync/sync-index.js';
|
|
31
|
+
export * as sync from './sync/sync-index.js';
|
|
32
|
+
|
|
33
|
+
export * from './system/CorePowerSyncSystem.js';
|
|
34
|
+
export * as system from './system/CorePowerSyncSystem.js';
|
|
35
|
+
|
|
36
|
+
export * from './util/util-index.js';
|
|
37
|
+
export * as utils from './util/util-index.js';
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import * as micro from '@journeyapps-platform/micro';
|
|
2
|
+
import { ValueType } from '@opentelemetry/api';
|
|
3
|
+
import { PrometheusExporter } from '@opentelemetry/exporter-prometheus';
|
|
4
|
+
import { MeterProvider } from '@opentelemetry/sdk-metrics';
|
|
5
|
+
import * as jpgwire from '@powersync/service-jpgwire';
|
|
6
|
+
|
|
7
|
+
import * as util from '@/util/util-index.js';
|
|
8
|
+
import * as storage from '@/storage/storage-index.js';
|
|
9
|
+
import { CorePowerSyncSystem } from '../system/CorePowerSyncSystem.js';
|
|
10
|
+
|
|
11
|
+
const meterProvider = new MeterProvider();
|
|
12
|
+
|
|
13
|
+
const port: number = util.env.METRICS_PORT ?? 0;
|
|
14
|
+
|
|
15
|
+
// Expose a pull-based metrics exporter on a prometheus endpoint.
|
|
16
|
+
// This is not quite the standard approach of opentelemetry or journey-micro.
|
|
17
|
+
// However, it avoids the need for running a separate sidecar that uses additional resources.
|
|
18
|
+
// We can consider switching to the standard push-based architecture if needed later.
|
|
19
|
+
|
|
20
|
+
export const exporter = new PrometheusExporter({ port: port, preventServerStart: true });
|
|
21
|
+
meterProvider.addMetricReader(exporter);
|
|
22
|
+
|
|
23
|
+
if (port > 0) {
|
|
24
|
+
exporter.startServer();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const meter = meterProvider.getMeter('powersync');
|
|
28
|
+
|
|
29
|
+
// 1. Data processing / month
|
|
30
|
+
|
|
31
|
+
// 1a. Postgres -> PowerSync
|
|
32
|
+
// Record on replication pod
|
|
33
|
+
export const data_replicated_bytes = meter.createCounter('powersync_data_replicated_bytes_total', {
|
|
34
|
+
description: 'Uncompressed size of replicated data',
|
|
35
|
+
unit: 'bytes',
|
|
36
|
+
valueType: ValueType.INT
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
// 1b. PowerSync -> clients
|
|
40
|
+
// Record on API pod
|
|
41
|
+
export const data_synced_bytes = meter.createCounter('powersync_data_synced_bytes_total', {
|
|
42
|
+
description: 'Uncompressed size of synced data',
|
|
43
|
+
unit: 'bytes',
|
|
44
|
+
valueType: ValueType.INT
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
// Unused for pricing
|
|
48
|
+
// Record on replication pod
|
|
49
|
+
export const rows_replicated_total = meter.createCounter('powersync_rows_replicated_total', {
|
|
50
|
+
description: 'Total number of replicated rows',
|
|
51
|
+
valueType: ValueType.INT
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
// Unused for pricing
|
|
55
|
+
// Record on replication pod
|
|
56
|
+
export const transactions_replicated_total = meter.createCounter('powersync_transactions_replicated_total', {
|
|
57
|
+
description: 'Total number of replicated transactions',
|
|
58
|
+
valueType: ValueType.INT
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
// Unused for pricing
|
|
62
|
+
// Record on replication pod
|
|
63
|
+
export const chunks_replicated_total = meter.createCounter('powersync_chunks_replicated_total', {
|
|
64
|
+
description: 'Total number of replication chunks',
|
|
65
|
+
valueType: ValueType.INT
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
// 2. Sync operations / month
|
|
69
|
+
// Record on API pod
|
|
70
|
+
export const operations_synced_total = meter.createCounter('powersync_operations_synced_total', {
|
|
71
|
+
description: 'Number of operations synced',
|
|
72
|
+
valueType: ValueType.INT
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
// 3. Data hosted on PowerSync sync service
|
|
76
|
+
// Record on replication pod
|
|
77
|
+
|
|
78
|
+
// 3a. Replication storage -> raw data as received from Postgres.
|
|
79
|
+
export const replication_storage_size_bytes = meter.createObservableGauge('powersync_replication_storage_size_bytes', {
|
|
80
|
+
description: 'Size of current data stored in PowerSync',
|
|
81
|
+
unit: 'bytes',
|
|
82
|
+
valueType: ValueType.INT
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
// 3b. Operations storage -> transformed history, as will be synced to clients
|
|
86
|
+
export const operation_storage_size_bytes = meter.createObservableGauge('powersync_operation_storage_size_bytes', {
|
|
87
|
+
description: 'Size of operations stored in PowerSync',
|
|
88
|
+
unit: 'bytes',
|
|
89
|
+
valueType: ValueType.INT
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
// 3c. Parameter storage -> used for parameter queries
|
|
93
|
+
export const parameter_storage_size_bytes = meter.createObservableGauge('powersync_parameter_storage_size_bytes', {
|
|
94
|
+
description: 'Size of parameter data stored in PowerSync',
|
|
95
|
+
unit: 'bytes',
|
|
96
|
+
valueType: ValueType.INT
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
// 4. Peak concurrent connections
|
|
100
|
+
// Record on API pod
|
|
101
|
+
|
|
102
|
+
export const concurrent_connections = meter.createUpDownCounter('powersync_concurrent_connections', {
|
|
103
|
+
description: 'Number of concurrent sync connections',
|
|
104
|
+
valueType: ValueType.INT
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
export function configureApiMetrics() {
|
|
108
|
+
// Initialize the metric, so that it reports a value before connections
|
|
109
|
+
// have been opened.
|
|
110
|
+
concurrent_connections.add(0);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export function configureReplicationMetrics(system: CorePowerSyncSystem) {
|
|
114
|
+
// Rate limit collection of these stats, since it may be an expensive query
|
|
115
|
+
const MINIMUM_INTERVAL = 60_000;
|
|
116
|
+
|
|
117
|
+
let cachedRequest: Promise<storage.StorageMetrics | null> | undefined = undefined;
|
|
118
|
+
let cacheTimestamp = 0;
|
|
119
|
+
|
|
120
|
+
function getMetrics() {
|
|
121
|
+
if (cachedRequest == null || Date.now() - cacheTimestamp > MINIMUM_INTERVAL) {
|
|
122
|
+
cachedRequest = system.storage.getStorageMetrics().catch((e) => {
|
|
123
|
+
micro.logger.error(`Failed to get storage metrics`, e);
|
|
124
|
+
return null;
|
|
125
|
+
});
|
|
126
|
+
cacheTimestamp = Date.now();
|
|
127
|
+
}
|
|
128
|
+
return cachedRequest;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
operation_storage_size_bytes.addCallback(async (result) => {
|
|
132
|
+
const metrics = await getMetrics();
|
|
133
|
+
if (metrics) {
|
|
134
|
+
result.observe(metrics.operations_size_bytes);
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
parameter_storage_size_bytes.addCallback(async (result) => {
|
|
139
|
+
const metrics = await getMetrics();
|
|
140
|
+
if (metrics) {
|
|
141
|
+
result.observe(metrics.parameters_size_bytes);
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
replication_storage_size_bytes.addCallback(async (result) => {
|
|
146
|
+
const metrics = await getMetrics();
|
|
147
|
+
if (metrics) {
|
|
148
|
+
result.observe(metrics.replication_size_bytes);
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
// Record replicated bytes using global jpgwire metrics.
|
|
153
|
+
jpgwire.setMetricsRecorder({
|
|
154
|
+
addBytesRead(bytes) {
|
|
155
|
+
data_replicated_bytes.add(bytes);
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export async function getMetricValueForTests(name: string): Promise<number | undefined> {
|
|
161
|
+
const metrics = await exporter.collect();
|
|
162
|
+
const scoped = metrics.resourceMetrics.scopeMetrics[0].metrics;
|
|
163
|
+
const metric = scoped.find((metric) => metric.descriptor.name == name);
|
|
164
|
+
if (metric == null) {
|
|
165
|
+
throw new Error(`Cannot find metric ${name}. Options: ${scoped.map((metric) => metric.descriptor.name).join(',')}`);
|
|
166
|
+
}
|
|
167
|
+
const point = metric.dataPoints[metric.dataPoints.length - 1];
|
|
168
|
+
return point?.value as number;
|
|
169
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import * as mongo from '@/db/mongo.js';
|
|
2
|
+
import * as storage from '@/storage/storage-index.js';
|
|
3
|
+
import * as utils from '@/util/util-index.js';
|
|
4
|
+
|
|
5
|
+
export const up = async (context?: utils.MigrationContext) => {
|
|
6
|
+
const config = await utils.loadConfig(context?.runner_config);
|
|
7
|
+
const database = storage.createPowerSyncMongo(config.storage);
|
|
8
|
+
await mongo.waitForAuth(database.db);
|
|
9
|
+
try {
|
|
10
|
+
await database.bucket_parameters.createIndex(
|
|
11
|
+
{
|
|
12
|
+
'key.g': 1,
|
|
13
|
+
lookup: 1,
|
|
14
|
+
_id: 1
|
|
15
|
+
},
|
|
16
|
+
{ name: 'lookup1' }
|
|
17
|
+
);
|
|
18
|
+
} finally {
|
|
19
|
+
await database.client.close();
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export const down = async (context?: utils.MigrationContext) => {
|
|
24
|
+
const config = await utils.loadConfig(context?.runner_config);
|
|
25
|
+
const database = storage.createPowerSyncMongo(config.storage);
|
|
26
|
+
try {
|
|
27
|
+
if (await database.bucket_parameters.indexExists('lookup')) {
|
|
28
|
+
await database.bucket_parameters.dropIndex('lookup1');
|
|
29
|
+
}
|
|
30
|
+
} finally {
|
|
31
|
+
await database.client.close();
|
|
32
|
+
}
|
|
33
|
+
};
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import * as mongo from '@/db/mongo.js';
|
|
2
|
+
import * as storage from '@/storage/storage-index.js';
|
|
3
|
+
import * as utils from '@/util/util-index.js';
|
|
4
|
+
|
|
5
|
+
interface LegacySyncRulesDocument extends storage.SyncRuleDocument {
|
|
6
|
+
/**
|
|
7
|
+
* True if this is the active sync rules.
|
|
8
|
+
* requires `snapshot_done == true` and `replicating == true`.
|
|
9
|
+
*/
|
|
10
|
+
active?: boolean;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* True if this sync rules should be used for replication.
|
|
14
|
+
*
|
|
15
|
+
* During reprocessing, there is one sync rules with `replicating = true, active = true`,
|
|
16
|
+
* and one with `replicating = true, active = false, auto_activate = true`.
|
|
17
|
+
*/
|
|
18
|
+
replicating?: boolean;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* True if the sync rules should set `active = true` when `snapshot_done` = true.
|
|
22
|
+
*/
|
|
23
|
+
auto_activate?: boolean;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export const up = async (context?: utils.MigrationContext) => {
|
|
27
|
+
const config = await utils.loadConfig(context?.runner_config);
|
|
28
|
+
const db = storage.createPowerSyncMongo(config.storage);
|
|
29
|
+
await mongo.waitForAuth(db.db);
|
|
30
|
+
try {
|
|
31
|
+
// We keep the old flags for existing deployments still shutting down.
|
|
32
|
+
|
|
33
|
+
// 1. New sync rules: `active = false, snapshot_done = false, replicating = true, auto_activate = true`
|
|
34
|
+
await db.sync_rules.updateMany(
|
|
35
|
+
{
|
|
36
|
+
active: { $ne: true },
|
|
37
|
+
replicating: true,
|
|
38
|
+
auto_activate: true
|
|
39
|
+
},
|
|
40
|
+
{ $set: { state: storage.SyncRuleState.PROCESSING } }
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
// 2. Snapshot done: `active = true, snapshot_done = true, replicating = true, auto_activate = false`
|
|
44
|
+
await db.sync_rules.updateMany(
|
|
45
|
+
{
|
|
46
|
+
active: true
|
|
47
|
+
},
|
|
48
|
+
{ $set: { state: storage.SyncRuleState.ACTIVE } }
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
// 3. Stopped: `active = false, snapshot_done = true, replicating = false, auto_activate = false`.
|
|
52
|
+
await db.sync_rules.updateMany(
|
|
53
|
+
{
|
|
54
|
+
active: { $ne: true },
|
|
55
|
+
replicating: { $ne: true },
|
|
56
|
+
auto_activate: { $ne: true }
|
|
57
|
+
},
|
|
58
|
+
{ $set: { state: storage.SyncRuleState.STOP } }
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
const remaining = await db.sync_rules.find({ state: null as any }).toArray();
|
|
62
|
+
if (remaining.length > 0) {
|
|
63
|
+
const slots = remaining.map((doc) => doc.slot_name).join(', ');
|
|
64
|
+
throw new Error(`Invalid state for sync rules: ${slots}`);
|
|
65
|
+
}
|
|
66
|
+
} finally {
|
|
67
|
+
await db.client.close();
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
export const down = async (context?: utils.MigrationContext) => {
|
|
72
|
+
const config = await utils.loadConfig(context?.runner_config);
|
|
73
|
+
|
|
74
|
+
const db = storage.createPowerSyncMongo(config.storage);
|
|
75
|
+
try {
|
|
76
|
+
await db.sync_rules.updateMany(
|
|
77
|
+
{
|
|
78
|
+
state: storage.SyncRuleState.ACTIVE
|
|
79
|
+
},
|
|
80
|
+
{ $set: { active: true, replicating: true } }
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
await db.sync_rules.updateMany(
|
|
84
|
+
{
|
|
85
|
+
state: storage.SyncRuleState.PROCESSING
|
|
86
|
+
},
|
|
87
|
+
{ $set: { active: false, replicating: true, auto_activate: true } }
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
await db.sync_rules.updateMany(
|
|
91
|
+
{
|
|
92
|
+
$or: [{ state: storage.SyncRuleState.STOP }, { state: storage.SyncRuleState.TERMINATED }]
|
|
93
|
+
},
|
|
94
|
+
{ $set: { active: false, replicating: false, auto_activate: false } }
|
|
95
|
+
);
|
|
96
|
+
} finally {
|
|
97
|
+
await db.client.close();
|
|
98
|
+
}
|
|
99
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import * as storage from '@/storage/storage-index.js';
|
|
2
|
+
import * as utils from '@/util/util-index.js';
|
|
3
|
+
|
|
4
|
+
export const up = async (context?: utils.MigrationContext) => {
|
|
5
|
+
const config = await utils.loadConfig(context?.runner_config);
|
|
6
|
+
const db = storage.createPowerSyncMongo(config.storage);
|
|
7
|
+
|
|
8
|
+
try {
|
|
9
|
+
await db.write_checkpoints.createIndex(
|
|
10
|
+
{
|
|
11
|
+
user_id: 1
|
|
12
|
+
},
|
|
13
|
+
{ name: 'user_id' }
|
|
14
|
+
);
|
|
15
|
+
} finally {
|
|
16
|
+
await db.client.close();
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export const down = async (context?: utils.MigrationContext) => {
|
|
21
|
+
const config = await utils.loadConfig(context?.runner_config);
|
|
22
|
+
|
|
23
|
+
const db = storage.createPowerSyncMongo(config.storage);
|
|
24
|
+
|
|
25
|
+
try {
|
|
26
|
+
if (await db.write_checkpoints.indexExists('user_id')) {
|
|
27
|
+
await db.write_checkpoints.dropIndex('user_id');
|
|
28
|
+
}
|
|
29
|
+
} finally {
|
|
30
|
+
await db.client.close();
|
|
31
|
+
}
|
|
32
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import * as micro_migrate from '@journeyapps-platform/micro-migrate';
|
|
2
|
+
import * as utils from '@/util/util-index.js';
|
|
3
|
+
|
|
4
|
+
const config = await utils.loadConfig();
|
|
5
|
+
|
|
6
|
+
export default micro_migrate.createMongoMigrationStore({
|
|
7
|
+
uri: config.storage.uri,
|
|
8
|
+
database: config.storage.database,
|
|
9
|
+
username: config.storage.username,
|
|
10
|
+
password: config.storage.password
|
|
11
|
+
});
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import * as fs from 'fs/promises';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import { fileURLToPath } from 'url';
|
|
4
|
+
|
|
5
|
+
import { Lock, createMongoLockManager } from '@journeyapps-platform/micro-locks';
|
|
6
|
+
import { Direction, createMongoMigrationStore, execute, writeLogsToStore } from '@journeyapps-platform/micro-migrate';
|
|
7
|
+
|
|
8
|
+
import * as db from '@/db/db-index.js';
|
|
9
|
+
import * as util from '@/util/util-index.js';
|
|
10
|
+
|
|
11
|
+
const DEFAULT_MONGO_LOCK_COLLECTION = 'locks';
|
|
12
|
+
const MONGO_LOCK_PROCESS = 'migrations';
|
|
13
|
+
|
|
14
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
15
|
+
const __dirname = path.dirname(__filename);
|
|
16
|
+
|
|
17
|
+
const MIGRATIONS_DIR = path.join(__dirname, '/db/migrations');
|
|
18
|
+
|
|
19
|
+
export type MigrationOptions = {
|
|
20
|
+
direction: Direction;
|
|
21
|
+
runner_config: util.RunnerConfig;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Loads migrations and injects a custom context for loading the specified
|
|
26
|
+
* runner configuration.
|
|
27
|
+
*/
|
|
28
|
+
const loadMigrations = async (dir: string, runner_config: util.RunnerConfig) => {
|
|
29
|
+
const files = await fs.readdir(dir);
|
|
30
|
+
const migrations = files.filter((file) => {
|
|
31
|
+
return path.extname(file) === '.js';
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
const context: util.MigrationContext = {
|
|
35
|
+
runner_config
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
return await Promise.all(
|
|
39
|
+
migrations.map(async (migration) => {
|
|
40
|
+
const module = await import(path.resolve(dir, migration));
|
|
41
|
+
return {
|
|
42
|
+
name: path.basename(migration).replace(path.extname(migration), ''),
|
|
43
|
+
up: () => module.up(context),
|
|
44
|
+
down: () => module.down(context)
|
|
45
|
+
};
|
|
46
|
+
})
|
|
47
|
+
);
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Runs migration scripts exclusively using Mongo locks
|
|
52
|
+
*/
|
|
53
|
+
export const migrate = async (options: MigrationOptions) => {
|
|
54
|
+
const { direction, runner_config } = options;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Try and get Mongo from config file.
|
|
58
|
+
* But this might not be available in Journey Micro as we use the standard Mongo.
|
|
59
|
+
*/
|
|
60
|
+
|
|
61
|
+
const config = await util.loadConfig(runner_config);
|
|
62
|
+
const { storage } = config;
|
|
63
|
+
|
|
64
|
+
const client = db.mongo.createMongoClient(storage);
|
|
65
|
+
await client.connect();
|
|
66
|
+
|
|
67
|
+
const clientDB = client.db(storage.database);
|
|
68
|
+
const collection = clientDB.collection<Lock>(DEFAULT_MONGO_LOCK_COLLECTION);
|
|
69
|
+
|
|
70
|
+
const manager = createMongoLockManager(collection, {
|
|
71
|
+
name: MONGO_LOCK_PROCESS
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
// Only one process should execute this at a time.
|
|
75
|
+
const lockId = await manager.acquire();
|
|
76
|
+
|
|
77
|
+
if (!lockId) {
|
|
78
|
+
throw new Error('Could not acquire lock_id');
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
let isReleased = false;
|
|
82
|
+
const releaseLock = async () => {
|
|
83
|
+
if (isReleased) {
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
await manager.release(lockId);
|
|
87
|
+
isReleased = true;
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
// For the case where the migration is terminated
|
|
91
|
+
process.addListener('beforeExit', releaseLock);
|
|
92
|
+
|
|
93
|
+
try {
|
|
94
|
+
const migrations = await loadMigrations(MIGRATIONS_DIR, runner_config);
|
|
95
|
+
|
|
96
|
+
// Use the provided config to connect to Mongo
|
|
97
|
+
const store = createMongoMigrationStore({
|
|
98
|
+
uri: storage.uri,
|
|
99
|
+
database: storage.database,
|
|
100
|
+
username: storage.username,
|
|
101
|
+
password: storage.password
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
const state = await store.load();
|
|
105
|
+
|
|
106
|
+
const logStream = execute({
|
|
107
|
+
direction: direction,
|
|
108
|
+
migrations,
|
|
109
|
+
state
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
await writeLogsToStore({
|
|
113
|
+
log_stream: logStream,
|
|
114
|
+
store,
|
|
115
|
+
state
|
|
116
|
+
});
|
|
117
|
+
} finally {
|
|
118
|
+
await releaseLock();
|
|
119
|
+
await client.close(true);
|
|
120
|
+
process.removeListener('beforeExit', releaseLock);
|
|
121
|
+
}
|
|
122
|
+
};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { setTimeout } from 'timers/promises';
|
|
2
|
+
|
|
3
|
+
export interface ErrorRateLimiter {
|
|
4
|
+
waitUntilAllowed(options?: { signal?: AbortSignal }): Promise<void>;
|
|
5
|
+
reportError(e: any): void;
|
|
6
|
+
|
|
7
|
+
mayPing(): boolean;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export class DefaultErrorRateLimiter implements ErrorRateLimiter {
|
|
11
|
+
nextAllowed: number = Date.now();
|
|
12
|
+
|
|
13
|
+
async waitUntilAllowed(options?: { signal?: AbortSignal | undefined } | undefined): Promise<void> {
|
|
14
|
+
const delay = Math.max(0, this.nextAllowed - Date.now());
|
|
15
|
+
this.setDelay(5_000);
|
|
16
|
+
await setTimeout(delay, undefined, { signal: options?.signal });
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
mayPing(): boolean {
|
|
20
|
+
return Date.now() >= this.nextAllowed;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
reportError(e: any): void {
|
|
24
|
+
const message = (e.message as string) ?? '';
|
|
25
|
+
if (message.includes('password authentication failed')) {
|
|
26
|
+
// Wait 15 minutes, to avoid triggering Supabase's fail2ban
|
|
27
|
+
this.setDelay(900_000);
|
|
28
|
+
} else if (message.includes('ENOTFOUND')) {
|
|
29
|
+
// DNS lookup issue - incorrect URI or deleted instance
|
|
30
|
+
this.setDelay(120_000);
|
|
31
|
+
} else if (message.includes('ECONNREFUSED')) {
|
|
32
|
+
// Could be fail2ban or similar
|
|
33
|
+
this.setDelay(120_000);
|
|
34
|
+
} else if (
|
|
35
|
+
message.includes('Unable to do postgres query on ended pool') ||
|
|
36
|
+
message.includes('Postgres unexpectedly closed connection')
|
|
37
|
+
) {
|
|
38
|
+
// Connection timed out - ignore / immediately retry
|
|
39
|
+
// We don't explicitly set the delay to 0, since there could have been another error that
|
|
40
|
+
// we need to respect.
|
|
41
|
+
} else {
|
|
42
|
+
this.setDelay(30_000);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
private setDelay(delay: number) {
|
|
47
|
+
this.nextAllowed = Math.max(this.nextAllowed, Date.now() + delay);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { PgoutputRelation } from '@powersync/service-jpgwire';
|
|
2
|
+
|
|
3
|
+
export interface PgRelation {
|
|
4
|
+
readonly relationId: number;
|
|
5
|
+
readonly schema: string;
|
|
6
|
+
readonly name: string;
|
|
7
|
+
readonly replicaIdentity: ReplicationIdentity;
|
|
8
|
+
readonly replicationColumns: ReplicationColumn[];
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export type ReplicationIdentity = 'default' | 'nothing' | 'full' | 'index';
|
|
12
|
+
|
|
13
|
+
export interface ReplicationColumn {
|
|
14
|
+
readonly name: string;
|
|
15
|
+
readonly typeOid: number;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function getReplicaIdColumns(relation: PgoutputRelation): ReplicationColumn[] {
|
|
19
|
+
if (relation.replicaIdentity == 'nothing') {
|
|
20
|
+
return [];
|
|
21
|
+
} else {
|
|
22
|
+
return relation.columns.filter((c) => (c.flags & 0b1) != 0).map((c) => ({ name: c.name, typeOid: c.typeOid }));
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
export function getRelId(source: PgoutputRelation): number {
|
|
26
|
+
// Source types are wrong here
|
|
27
|
+
const relId = (source as any).relationOid as number;
|
|
28
|
+
if (relId == null || typeof relId != 'number') {
|
|
29
|
+
throw new Error(`No relation id!`);
|
|
30
|
+
}
|
|
31
|
+
return relId;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function getPgOutputRelation(source: PgoutputRelation): PgRelation {
|
|
35
|
+
return {
|
|
36
|
+
name: source.name,
|
|
37
|
+
schema: source.schema,
|
|
38
|
+
relationId: getRelId(source),
|
|
39
|
+
replicaIdentity: source.replicaIdentity,
|
|
40
|
+
replicationColumns: getReplicaIdColumns(source)
|
|
41
|
+
};
|
|
42
|
+
}
|