@powersync/service-core 0.8.8 → 0.9.0
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/CHANGELOG.md +31 -0
- package/dist/api/RouteAPI.d.ts +67 -0
- package/dist/api/RouteAPI.js +2 -0
- package/dist/api/RouteAPI.js.map +1 -0
- package/dist/api/api-index.d.ts +1 -0
- package/dist/api/api-index.js +1 -0
- package/dist/api/api-index.js.map +1 -1
- package/dist/api/diagnostics.d.ts +4 -4
- package/dist/api/diagnostics.js +170 -158
- package/dist/api/diagnostics.js.map +1 -1
- package/dist/api/schema.d.ts +3 -5
- package/dist/api/schema.js +14 -80
- package/dist/api/schema.js.map +1 -1
- package/dist/auth/CachedKeyCollector.js.map +1 -1
- package/dist/auth/KeySpec.js.map +1 -1
- package/dist/auth/KeyStore.d.ts +7 -4
- package/dist/auth/KeyStore.js +1 -1
- package/dist/auth/KeyStore.js.map +1 -1
- package/dist/auth/LeakyBucket.js.map +1 -1
- package/dist/auth/RemoteJWKSCollector.d.ts +0 -2
- package/dist/auth/RemoteJWKSCollector.js.map +1 -1
- package/dist/auth/auth-index.d.ts +0 -1
- package/dist/auth/auth-index.js +0 -1
- package/dist/auth/auth-index.js.map +1 -1
- package/dist/db/mongo.js +5 -3
- package/dist/db/mongo.js.map +1 -1
- package/dist/entry/cli-entry.js +3 -2
- package/dist/entry/cli-entry.js.map +1 -1
- package/dist/entry/commands/compact-action.js +90 -14
- package/dist/entry/commands/compact-action.js.map +1 -1
- package/dist/entry/commands/migrate-action.js +4 -5
- package/dist/entry/commands/migrate-action.js.map +1 -1
- package/dist/entry/commands/teardown-action.js +2 -2
- package/dist/entry/commands/teardown-action.js.map +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/dist/locks/MongoLocks.js.map +1 -1
- package/dist/metrics/Metrics.d.ts +2 -2
- package/dist/metrics/Metrics.js +5 -13
- package/dist/metrics/Metrics.js.map +1 -1
- package/dist/migrations/db/migrations/1684951997326-init.d.ts +2 -2
- package/dist/migrations/db/migrations/1684951997326-init.js +4 -2
- package/dist/migrations/db/migrations/1684951997326-init.js.map +1 -1
- package/dist/migrations/db/migrations/1702295701188-sync-rule-state.d.ts +2 -2
- package/dist/migrations/db/migrations/1702295701188-sync-rule-state.js +4 -2
- package/dist/migrations/db/migrations/1702295701188-sync-rule-state.js.map +1 -1
- package/dist/migrations/db/migrations/1711543888062-write-checkpoint-index.d.ts +2 -2
- package/dist/migrations/db/migrations/1711543888062-write-checkpoint-index.js +4 -2
- package/dist/migrations/db/migrations/1711543888062-write-checkpoint-index.js.map +1 -1
- package/dist/migrations/db/migrations/1727099539247-custom-write-checkpoint-index.d.ts +3 -0
- package/dist/migrations/db/migrations/1727099539247-custom-write-checkpoint-index.js +31 -0
- package/dist/migrations/db/migrations/1727099539247-custom-write-checkpoint-index.js.map +1 -0
- package/dist/migrations/executor.js.map +1 -1
- package/dist/migrations/migrations.d.ts +8 -0
- package/dist/migrations/migrations.js +19 -7
- package/dist/migrations/migrations.js.map +1 -1
- package/dist/migrations/store/migration-store.js.map +1 -1
- package/dist/modules/AbstractModule.d.ts +26 -0
- package/dist/modules/AbstractModule.js +11 -0
- package/dist/modules/AbstractModule.js.map +1 -0
- package/dist/modules/ModuleManager.d.ts +11 -0
- package/dist/modules/ModuleManager.js +32 -0
- package/dist/modules/ModuleManager.js.map +1 -0
- package/dist/modules/modules-index.d.ts +2 -0
- package/dist/modules/modules-index.js +3 -0
- package/dist/modules/modules-index.js.map +1 -0
- package/dist/replication/AbstractReplicationJob.d.ts +37 -0
- package/dist/replication/AbstractReplicationJob.js +51 -0
- package/dist/replication/AbstractReplicationJob.js.map +1 -0
- package/dist/replication/AbstractReplicator.d.ts +53 -0
- package/dist/replication/AbstractReplicator.js +250 -0
- package/dist/replication/AbstractReplicator.js.map +1 -0
- package/dist/replication/ErrorRateLimiter.d.ts +0 -10
- package/dist/replication/ErrorRateLimiter.js +1 -42
- package/dist/replication/ErrorRateLimiter.js.map +1 -1
- package/dist/replication/ReplicationEngine.d.ts +18 -0
- package/dist/replication/ReplicationEngine.js +41 -0
- package/dist/replication/ReplicationEngine.js.map +1 -0
- package/dist/replication/ReplicationModule.d.ts +51 -0
- package/dist/replication/ReplicationModule.js +68 -0
- package/dist/replication/ReplicationModule.js.map +1 -0
- package/dist/replication/replication-index.d.ts +4 -6
- package/dist/replication/replication-index.js +4 -6
- package/dist/replication/replication-index.js.map +1 -1
- package/dist/routes/RouterEngine.d.ts +42 -0
- package/dist/routes/RouterEngine.js +80 -0
- package/dist/routes/RouterEngine.js.map +1 -0
- package/dist/routes/auth.d.ts +2 -2
- package/dist/routes/auth.js +11 -11
- package/dist/routes/auth.js.map +1 -1
- package/dist/routes/configure-fastify.d.ts +37 -23
- package/dist/routes/configure-fastify.js +18 -18
- package/dist/routes/configure-fastify.js.map +1 -1
- package/dist/routes/configure-rsocket.d.ts +3 -4
- package/dist/routes/configure-rsocket.js +7 -4
- package/dist/routes/configure-rsocket.js.map +1 -1
- package/dist/routes/endpoints/admin.d.ts +30 -0
- package/dist/routes/endpoints/admin.js +46 -67
- package/dist/routes/endpoints/admin.js.map +1 -1
- package/dist/routes/endpoints/checkpointing.js +103 -15
- package/dist/routes/endpoints/checkpointing.js.map +1 -1
- package/dist/routes/endpoints/socket-route.js +8 -6
- package/dist/routes/endpoints/socket-route.js.map +1 -1
- package/dist/routes/endpoints/sync-rules.d.ts +1 -1
- package/dist/routes/endpoints/sync-rules.js +32 -23
- package/dist/routes/endpoints/sync-rules.js.map +1 -1
- package/dist/routes/endpoints/sync-stream.d.ts +0 -1
- package/dist/routes/endpoints/sync-stream.js +8 -8
- package/dist/routes/endpoints/sync-stream.js.map +1 -1
- package/dist/routes/hooks.js.map +1 -1
- package/dist/routes/route-register.js.map +1 -1
- package/dist/routes/router.d.ts +9 -2
- package/dist/routes/router.js.map +1 -1
- package/dist/routes/routes-index.d.ts +1 -0
- package/dist/routes/routes-index.js +1 -0
- package/dist/routes/routes-index.js.map +1 -1
- package/dist/runner/teardown.js +109 -76
- package/dist/runner/teardown.js.map +1 -1
- package/dist/storage/BucketStorage.d.ts +86 -36
- package/dist/storage/BucketStorage.js +6 -10
- package/dist/storage/BucketStorage.js.map +1 -1
- package/dist/storage/ChecksumCache.js.map +1 -1
- package/dist/storage/MongoBucketStorage.d.ts +7 -11
- package/dist/storage/MongoBucketStorage.js +48 -41
- package/dist/storage/MongoBucketStorage.js.map +1 -1
- package/dist/storage/ReplicationEventPayload.d.ts +14 -0
- package/dist/storage/ReplicationEventPayload.js +2 -0
- package/dist/storage/ReplicationEventPayload.js.map +1 -0
- package/dist/storage/SourceEntity.d.ts +20 -0
- package/dist/storage/SourceEntity.js +2 -0
- package/dist/storage/SourceEntity.js.map +1 -0
- package/dist/storage/SourceTable.d.ts +12 -5
- package/dist/storage/SourceTable.js +12 -5
- package/dist/storage/SourceTable.js.map +1 -1
- package/dist/storage/StorageEngine.d.ts +28 -0
- package/dist/storage/StorageEngine.js +45 -0
- package/dist/storage/StorageEngine.js.map +1 -0
- package/dist/storage/StorageProvider.d.ts +21 -0
- package/dist/storage/StorageProvider.js +2 -0
- package/dist/storage/StorageProvider.js.map +1 -0
- package/dist/storage/WriteCheckpointAPI.d.ts +74 -0
- package/dist/storage/WriteCheckpointAPI.js +16 -0
- package/dist/storage/WriteCheckpointAPI.js.map +1 -0
- package/dist/storage/mongo/MongoBucketBatch.d.ts +24 -5
- package/dist/storage/mongo/MongoBucketBatch.js +119 -62
- package/dist/storage/mongo/MongoBucketBatch.js.map +1 -1
- package/dist/storage/mongo/MongoCompactor.js +20 -3
- package/dist/storage/mongo/MongoCompactor.js.map +1 -1
- package/dist/storage/mongo/MongoIdSequence.js.map +1 -1
- package/dist/storage/mongo/MongoPersistedSyncRulesContent.d.ts +2 -2
- package/dist/storage/mongo/MongoPersistedSyncRulesContent.js +2 -2
- package/dist/storage/mongo/MongoPersistedSyncRulesContent.js.map +1 -1
- package/dist/storage/mongo/MongoStorageProvider.d.ts +5 -0
- package/dist/storage/mongo/MongoStorageProvider.js +26 -0
- package/dist/storage/mongo/MongoStorageProvider.js.map +1 -0
- package/dist/storage/mongo/MongoSyncBucketStorage.d.ts +18 -10
- package/dist/storage/mongo/MongoSyncBucketStorage.js +140 -25
- package/dist/storage/mongo/MongoSyncBucketStorage.js.map +1 -1
- package/dist/storage/mongo/MongoSyncRulesLock.js +1 -1
- package/dist/storage/mongo/MongoSyncRulesLock.js.map +1 -1
- package/dist/storage/mongo/MongoWriteCheckpointAPI.d.ts +20 -0
- package/dist/storage/mongo/MongoWriteCheckpointAPI.js +103 -0
- package/dist/storage/mongo/MongoWriteCheckpointAPI.js.map +1 -0
- package/dist/storage/mongo/OperationBatch.d.ts +13 -4
- package/dist/storage/mongo/OperationBatch.js +25 -7
- package/dist/storage/mongo/OperationBatch.js.map +1 -1
- package/dist/storage/mongo/PersistedBatch.d.ts +3 -3
- package/dist/storage/mongo/PersistedBatch.js +2 -2
- package/dist/storage/mongo/PersistedBatch.js.map +1 -1
- package/dist/storage/mongo/config.d.ts +19 -0
- package/dist/storage/mongo/config.js +26 -0
- package/dist/storage/mongo/config.js.map +1 -0
- package/dist/storage/mongo/db.d.ts +3 -2
- package/dist/storage/mongo/db.js +1 -0
- package/dist/storage/mongo/db.js.map +1 -1
- package/dist/storage/mongo/models.d.ts +20 -5
- package/dist/storage/mongo/models.js.map +1 -1
- package/dist/storage/mongo/util.d.ts +12 -1
- package/dist/storage/mongo/util.js +50 -2
- package/dist/storage/mongo/util.js.map +1 -1
- package/dist/storage/storage-index.d.ts +8 -2
- package/dist/storage/storage-index.js +8 -2
- package/dist/storage/storage-index.js.map +1 -1
- package/dist/sync/BroadcastIterable.d.ts +0 -1
- package/dist/sync/BroadcastIterable.js.map +1 -1
- package/dist/sync/LastValueSink.d.ts +0 -1
- package/dist/sync/LastValueSink.js.map +1 -1
- package/dist/sync/merge.d.ts +0 -1
- package/dist/sync/merge.js.map +1 -1
- package/dist/sync/safeRace.js.map +1 -1
- package/dist/sync/sync.d.ts +1 -1
- package/dist/sync/sync.js +5 -5
- package/dist/sync/sync.js.map +1 -1
- package/dist/sync/util.d.ts +0 -2
- package/dist/sync/util.js.map +1 -1
- package/dist/system/ServiceContext.d.ts +37 -0
- package/dist/system/ServiceContext.js +48 -0
- package/dist/system/ServiceContext.js.map +1 -0
- package/dist/system/system-index.d.ts +1 -1
- package/dist/system/system-index.js +1 -1
- package/dist/system/system-index.js.map +1 -1
- package/dist/util/Mutex.js.map +1 -1
- package/dist/util/config/collectors/config-collector.js.map +1 -1
- package/dist/util/config/collectors/impl/base64-config-collector.js.map +1 -1
- package/dist/util/config/collectors/impl/filesystem-config-collector.js.map +1 -1
- package/dist/util/config/compound-config-collector.d.ts +9 -2
- package/dist/util/config/compound-config-collector.js +16 -24
- package/dist/util/config/compound-config-collector.js.map +1 -1
- package/dist/util/config/sync-rules/impl/base64-sync-rules-collector.js.map +1 -1
- package/dist/util/config/sync-rules/impl/filesystem-sync-rules-collector.js.map +1 -1
- package/dist/util/config/sync-rules/impl/inline-sync-rules-collector.js.map +1 -1
- package/dist/util/config/sync-rules/sync-rules-provider.d.ts +9 -0
- package/dist/util/config/sync-rules/sync-rules-provider.js +15 -0
- package/dist/util/config/sync-rules/sync-rules-provider.js.map +1 -0
- package/dist/util/config/types.d.ts +7 -4
- package/dist/util/config/types.js.map +1 -1
- package/dist/util/config.d.ts +3 -4
- package/dist/util/config.js +5 -20
- package/dist/util/config.js.map +1 -1
- package/dist/util/memory-tracking.js.map +1 -1
- package/dist/util/secs.js.map +1 -1
- package/dist/util/util-index.d.ts +3 -6
- package/dist/util/util-index.js +3 -6
- package/dist/util/util-index.js.map +1 -1
- package/dist/util/utils.d.ts +10 -7
- package/dist/util/utils.js +36 -25
- package/dist/util/utils.js.map +1 -1
- package/package.json +8 -12
- package/src/api/RouteAPI.ts +78 -0
- package/src/api/api-index.ts +1 -0
- package/src/api/diagnostics.ts +18 -70
- package/src/api/schema.ts +18 -90
- package/src/auth/KeyStore.ts +9 -6
- package/src/auth/RemoteJWKSCollector.ts +4 -1
- package/src/auth/auth-index.ts +0 -1
- package/src/db/mongo.ts +5 -3
- package/src/entry/cli-entry.ts +3 -2
- package/src/entry/commands/compact-action.ts +24 -12
- package/src/entry/commands/migrate-action.ts +5 -8
- package/src/entry/commands/teardown-action.ts +2 -2
- package/src/index.ts +5 -2
- package/src/metrics/Metrics.ts +6 -16
- package/src/migrations/db/migrations/1684951997326-init.ts +9 -4
- package/src/migrations/db/migrations/1702295701188-sync-rule-state.ts +7 -4
- package/src/migrations/db/migrations/1711543888062-write-checkpoint-index.ts +6 -4
- package/src/migrations/db/migrations/1727099539247-custom-write-checkpoint-index.ts +37 -0
- package/src/migrations/migrations.ts +24 -8
- package/src/modules/AbstractModule.ts +37 -0
- package/src/modules/ModuleManager.ts +34 -0
- package/src/modules/modules-index.ts +2 -0
- package/src/replication/AbstractReplicationJob.ts +79 -0
- package/src/replication/AbstractReplicator.ts +228 -0
- package/src/replication/ErrorRateLimiter.ts +0 -44
- package/src/replication/ReplicationEngine.ts +43 -0
- package/src/replication/ReplicationModule.ts +122 -0
- package/src/replication/replication-index.ts +4 -6
- package/src/routes/RouterEngine.ts +120 -0
- package/src/routes/auth.ts +21 -12
- package/src/routes/configure-fastify.ts +26 -27
- package/src/routes/configure-rsocket.ts +13 -8
- package/src/routes/endpoints/admin.ts +72 -76
- package/src/routes/endpoints/checkpointing.ts +51 -11
- package/src/routes/endpoints/socket-route.ts +10 -6
- package/src/routes/endpoints/sync-rules.ts +41 -25
- package/src/routes/endpoints/sync-stream.ts +8 -8
- package/src/routes/router.ts +8 -3
- package/src/routes/routes-index.ts +1 -0
- package/src/runner/teardown.ts +50 -88
- package/src/storage/BucketStorage.ts +103 -41
- package/src/storage/MongoBucketStorage.ts +65 -53
- package/src/storage/ReplicationEventPayload.ts +16 -0
- package/src/storage/SourceEntity.ts +22 -0
- package/src/storage/SourceTable.ts +14 -7
- package/src/storage/StorageEngine.ts +62 -0
- package/src/storage/StorageProvider.ts +27 -0
- package/src/storage/WriteCheckpointAPI.ts +85 -0
- package/src/storage/mongo/MongoBucketBatch.ts +164 -84
- package/src/storage/mongo/MongoCompactor.ts +25 -4
- package/src/storage/mongo/MongoPersistedSyncRulesContent.ts +7 -4
- package/src/storage/mongo/MongoStorageProvider.ts +31 -0
- package/src/storage/mongo/MongoSyncBucketStorage.ts +118 -41
- package/src/storage/mongo/MongoSyncRulesLock.ts +7 -3
- package/src/storage/mongo/MongoWriteCheckpointAPI.ts +151 -0
- package/src/storage/mongo/OperationBatch.ts +28 -12
- package/src/storage/mongo/PersistedBatch.ts +10 -6
- package/src/storage/mongo/config.ts +40 -0
- package/src/storage/mongo/db.ts +4 -1
- package/src/storage/mongo/models.ts +21 -5
- package/src/storage/mongo/util.ts +48 -3
- package/src/storage/storage-index.ts +8 -2
- package/src/sync/sync.ts +7 -4
- package/src/sync/util.ts +0 -1
- package/src/system/ServiceContext.ts +68 -0
- package/src/system/system-index.ts +1 -1
- package/src/util/config/compound-config-collector.ts +31 -31
- package/src/util/config/sync-rules/sync-rules-provider.ts +18 -0
- package/src/util/config/types.ts +7 -5
- package/src/util/config.ts +6 -23
- package/src/util/util-index.ts +3 -6
- package/src/util/utils.ts +48 -41
- package/test/src/__snapshots__/sync.test.ts.snap +14 -14
- package/test/src/auth.test.ts +7 -7
- package/test/src/broadcast_iterable.test.ts +1 -1
- package/test/src/compacting.test.ts +50 -40
- package/test/src/data_storage.test.ts +382 -202
- package/test/src/env.ts +1 -3
- package/test/src/merge_iterable.test.ts +1 -6
- package/test/src/routes/probes.integration.test.ts +34 -30
- package/test/src/setup.ts +1 -1
- package/test/src/stream_utils.ts +42 -0
- package/test/src/sync.test.ts +115 -39
- package/test/src/util.ts +48 -51
- package/test/tsconfig.json +1 -1
- package/tsconfig.tsbuildinfo +1 -1
- package/vitest.config.ts +7 -1
- package/dist/auth/SupabaseKeyCollector.d.ts +0 -22
- package/dist/auth/SupabaseKeyCollector.js +0 -61
- package/dist/auth/SupabaseKeyCollector.js.map +0 -1
- package/dist/replication/PgRelation.d.ts +0 -16
- package/dist/replication/PgRelation.js +0 -26
- package/dist/replication/PgRelation.js.map +0 -1
- package/dist/replication/WalConnection.d.ts +0 -34
- package/dist/replication/WalConnection.js +0 -190
- package/dist/replication/WalConnection.js.map +0 -1
- package/dist/replication/WalStream.d.ts +0 -57
- package/dist/replication/WalStream.js +0 -519
- package/dist/replication/WalStream.js.map +0 -1
- package/dist/replication/WalStreamManager.d.ts +0 -30
- package/dist/replication/WalStreamManager.js +0 -198
- package/dist/replication/WalStreamManager.js.map +0 -1
- package/dist/replication/WalStreamRunner.d.ts +0 -38
- package/dist/replication/WalStreamRunner.js +0 -155
- package/dist/replication/WalStreamRunner.js.map +0 -1
- package/dist/replication/util.d.ts +0 -9
- package/dist/replication/util.js +0 -62
- package/dist/replication/util.js.map +0 -1
- package/dist/system/CorePowerSyncSystem.d.ts +0 -23
- package/dist/system/CorePowerSyncSystem.js +0 -52
- package/dist/system/CorePowerSyncSystem.js.map +0 -1
- package/dist/util/PgManager.d.ts +0 -24
- package/dist/util/PgManager.js +0 -55
- package/dist/util/PgManager.js.map +0 -1
- package/dist/util/migration_lib.d.ts +0 -11
- package/dist/util/migration_lib.js +0 -64
- package/dist/util/migration_lib.js.map +0 -1
- package/dist/util/pgwire_utils.d.ts +0 -24
- package/dist/util/pgwire_utils.js +0 -117
- package/dist/util/pgwire_utils.js.map +0 -1
- package/dist/util/populate_test_data.d.ts +0 -8
- package/dist/util/populate_test_data.js +0 -65
- package/dist/util/populate_test_data.js.map +0 -1
- package/src/auth/SupabaseKeyCollector.ts +0 -67
- package/src/replication/PgRelation.ts +0 -42
- package/src/replication/WalConnection.ts +0 -227
- package/src/replication/WalStream.ts +0 -631
- package/src/replication/WalStreamManager.ts +0 -213
- package/src/replication/WalStreamRunner.ts +0 -180
- package/src/replication/util.ts +0 -76
- package/src/system/CorePowerSyncSystem.ts +0 -64
- package/src/util/PgManager.ts +0 -64
- package/src/util/migration_lib.ts +0 -79
- package/src/util/pgwire_utils.ts +0 -139
- package/src/util/populate_test_data.ts +0 -78
- package/test/src/__snapshots__/pg_test.test.ts.snap +0 -256
- package/test/src/large_batch.test.ts +0 -194
- package/test/src/pg_test.test.ts +0 -450
- package/test/src/schema_changes.test.ts +0 -545
- package/test/src/slow_tests.test.ts +0 -338
- package/test/src/validation.test.ts +0 -63
- package/test/src/wal_stream.test.ts +0 -319
- package/test/src/wal_stream_utils.ts +0 -156
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { logger } from '@powersync/lib-services-framework';
|
|
2
|
+
import { AbstractReplicator } from './AbstractReplicator.js';
|
|
3
|
+
|
|
4
|
+
export class ReplicationEngine {
|
|
5
|
+
private readonly replicators: Map<string, AbstractReplicator> = new Map();
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Register a Replicator with the engine
|
|
9
|
+
*
|
|
10
|
+
* @param replicator
|
|
11
|
+
*/
|
|
12
|
+
public register(replicator: AbstractReplicator) {
|
|
13
|
+
if (this.replicators.has(replicator.id)) {
|
|
14
|
+
throw new Error(`Replicator with id: ${replicator.id} already registered`);
|
|
15
|
+
}
|
|
16
|
+
logger.info(`Successfully registered Replicator ${replicator.id} with ReplicationEngine`);
|
|
17
|
+
this.replicators.set(replicator.id, replicator);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Start replication on all managed Replicators
|
|
22
|
+
*/
|
|
23
|
+
public start(): void {
|
|
24
|
+
logger.info('Starting Replication Engine...');
|
|
25
|
+
for (const replicator of this.replicators.values()) {
|
|
26
|
+
logger.info(`Starting Replicator: ${replicator.id}`);
|
|
27
|
+
replicator.start();
|
|
28
|
+
}
|
|
29
|
+
logger.info('Successfully started Replication Engine.');
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Stop replication on all managed Replicators
|
|
34
|
+
*/
|
|
35
|
+
public async shutDown(): Promise<void> {
|
|
36
|
+
logger.info('Shutting down Replication Engine...');
|
|
37
|
+
for (const replicator of this.replicators.values()) {
|
|
38
|
+
logger.info(`Stopping Replicator: ${replicator.id}`);
|
|
39
|
+
await replicator.stop();
|
|
40
|
+
}
|
|
41
|
+
logger.info('Successfully shut down Replication Engine.');
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { DataSourceConfig } from '@powersync/service-types/dist/config/PowerSyncConfig.js';
|
|
2
|
+
import * as t from 'ts-codec';
|
|
3
|
+
|
|
4
|
+
import * as types from '@powersync/service-types';
|
|
5
|
+
import * as api from '../api/api-index.js';
|
|
6
|
+
import * as modules from '../modules/modules-index.js';
|
|
7
|
+
import * as system from '../system/system-index.js';
|
|
8
|
+
import { schema } from '@powersync/lib-services-framework';
|
|
9
|
+
import { AbstractReplicator } from './AbstractReplicator.js';
|
|
10
|
+
import { TearDownOptions } from '../modules/modules-index.js';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Provides a common interface for testing the connection to a DataSource.
|
|
14
|
+
*/
|
|
15
|
+
export interface ConnectionTester<TConfig extends DataSourceConfig> {
|
|
16
|
+
/**
|
|
17
|
+
* Confirm if a connection can be established to the datasource for the provided datasource configuration
|
|
18
|
+
* @param config
|
|
19
|
+
*/
|
|
20
|
+
testConnection(config: TConfig): Promise<void>;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface ReplicationModuleOptions extends modules.AbstractModuleOptions {
|
|
24
|
+
type: string;
|
|
25
|
+
configSchema: t.AnyCodec;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* A replication module describes all the functionality that PowerSync requires to
|
|
30
|
+
* replicate data from a DataSource. Whenever a new data source is added to powersync this class should be extended.
|
|
31
|
+
*/
|
|
32
|
+
export abstract class ReplicationModule<TConfig extends DataSourceConfig>
|
|
33
|
+
extends modules.AbstractModule
|
|
34
|
+
implements ConnectionTester<TConfig>
|
|
35
|
+
{
|
|
36
|
+
protected type: string;
|
|
37
|
+
protected configSchema: t.AnyCodec;
|
|
38
|
+
protected decodedConfig: TConfig | undefined;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* @protected
|
|
42
|
+
* @param options
|
|
43
|
+
*/
|
|
44
|
+
protected constructor(options: ReplicationModuleOptions) {
|
|
45
|
+
super(options);
|
|
46
|
+
this.type = options.type;
|
|
47
|
+
this.configSchema = options.configSchema;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Create the RouteAPI adapter for the DataSource required to service the sync API
|
|
52
|
+
* endpoints.
|
|
53
|
+
*/
|
|
54
|
+
protected abstract createRouteAPIAdapter(): api.RouteAPI;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Create the Replicator to be used by the ReplicationEngine.
|
|
58
|
+
*/
|
|
59
|
+
protected abstract createReplicator(context: system.ServiceContext): AbstractReplicator;
|
|
60
|
+
|
|
61
|
+
public abstract testConnection(config: TConfig): Promise<void>;
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Register this module's Replicators and RouteAPI adapters if the required configuration is present.
|
|
65
|
+
*/
|
|
66
|
+
public async initialize(context: system.ServiceContext): Promise<void> {
|
|
67
|
+
if (!context.configuration.connections) {
|
|
68
|
+
// No data source configuration found in the config skip for now
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const matchingConfig = context.configuration.connections.filter((dataSource) => dataSource.type === this.type);
|
|
73
|
+
if (!matchingConfig.length) {
|
|
74
|
+
// No configuration for this module was found
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (matchingConfig.length > 1) {
|
|
79
|
+
this.logger.warning(
|
|
80
|
+
`Multiple data sources of type ${this.type} found in the configuration. Only the first will be used.`
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
try {
|
|
85
|
+
const baseMatchingConfig = matchingConfig[0] as TConfig;
|
|
86
|
+
// If decoding fails, log the error and continue, no replication will happen for this data source
|
|
87
|
+
this.decodeConfig(baseMatchingConfig);
|
|
88
|
+
|
|
89
|
+
context.replicationEngine?.register(this.createReplicator(context));
|
|
90
|
+
context.routerEngine?.registerAPI(this.createRouteAPIAdapter());
|
|
91
|
+
} catch (e) {
|
|
92
|
+
this.logger.error('Failed to initialize.', e);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
protected decodeConfig(config: TConfig): void {
|
|
97
|
+
this.validateConfig(config);
|
|
98
|
+
this.decodedConfig = this.configSchema.decode(config);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
private validateConfig(config: TConfig): void {
|
|
102
|
+
const validator = schema
|
|
103
|
+
.parseJSONSchema(
|
|
104
|
+
// This generates a schema for the encoded form of the codec
|
|
105
|
+
t.generateJSONSchema(this.configSchema, {
|
|
106
|
+
allowAdditional: true,
|
|
107
|
+
parsers: [types.configFile.portParser]
|
|
108
|
+
})
|
|
109
|
+
)
|
|
110
|
+
.validator();
|
|
111
|
+
|
|
112
|
+
const valid = validator.validate(config);
|
|
113
|
+
|
|
114
|
+
if (!valid.valid) {
|
|
115
|
+
throw new Error(`Failed to validate Module ${this.name} configuration: ${valid.errors.join(', ')}`);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
protected getDefaultId(dataSourceName: string): string {
|
|
120
|
+
return `${this.type}-${dataSourceName}`;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
@@ -1,7 +1,5 @@
|
|
|
1
|
+
export * from './AbstractReplicationJob.js';
|
|
2
|
+
export * from './AbstractReplicator.js';
|
|
1
3
|
export * from './ErrorRateLimiter.js';
|
|
2
|
-
export * from './
|
|
3
|
-
export * from './
|
|
4
|
-
export * from './WalConnection.js';
|
|
5
|
-
export * from './WalStream.js';
|
|
6
|
-
export * from './WalStreamManager.js';
|
|
7
|
-
export * from './WalStreamRunner.js';
|
|
4
|
+
export * from './ReplicationEngine.js';
|
|
5
|
+
export * from './ReplicationModule.js';
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { logger } from '@powersync/lib-services-framework';
|
|
2
|
+
|
|
3
|
+
import * as api from '../api/api-index.js';
|
|
4
|
+
|
|
5
|
+
import { ADMIN_ROUTES } from './endpoints/admin.js';
|
|
6
|
+
import { CHECKPOINT_ROUTES } from './endpoints/checkpointing.js';
|
|
7
|
+
import { syncStreamReactive } from './endpoints/socket-route.js';
|
|
8
|
+
import { SYNC_RULES_ROUTES } from './endpoints/sync-rules.js';
|
|
9
|
+
import { SYNC_STREAM_ROUTES } from './endpoints/sync-stream.js';
|
|
10
|
+
import { SocketRouteGenerator } from './router-socket.js';
|
|
11
|
+
import { RouteDefinition } from './router.js';
|
|
12
|
+
|
|
13
|
+
export type RouterSetupResponse = {
|
|
14
|
+
onShutdown: () => Promise<void>;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export type RouterEngineRoutes = {
|
|
18
|
+
api_routes: RouteDefinition[];
|
|
19
|
+
stream_routes: RouteDefinition[];
|
|
20
|
+
socket_routes: SocketRouteGenerator[];
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export type RouterSetup = (routes: RouterEngineRoutes) => Promise<RouterSetupResponse>;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Serves as a registry from which SyncAPIs can be retrieved based on Replication DataSource type
|
|
27
|
+
* Initially only one SyncAPI per DataSource type is supported
|
|
28
|
+
*/
|
|
29
|
+
export class RouterEngine {
|
|
30
|
+
closed: boolean;
|
|
31
|
+
routes: RouterEngineRoutes;
|
|
32
|
+
|
|
33
|
+
protected stopHandlers: Set<() => void>;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* A final cleanup handler to be executed after all stopHandlers
|
|
37
|
+
*/
|
|
38
|
+
protected cleanupHandler: (() => Promise<void>) | null;
|
|
39
|
+
|
|
40
|
+
private api: api.RouteAPI | null;
|
|
41
|
+
|
|
42
|
+
constructor() {
|
|
43
|
+
this.api = null;
|
|
44
|
+
this.stopHandlers = new Set();
|
|
45
|
+
this.cleanupHandler = null;
|
|
46
|
+
this.closed = false;
|
|
47
|
+
|
|
48
|
+
// Default routes
|
|
49
|
+
this.routes = {
|
|
50
|
+
api_routes: [...ADMIN_ROUTES, ...CHECKPOINT_ROUTES, ...SYNC_RULES_ROUTES],
|
|
51
|
+
stream_routes: [...SYNC_STREAM_ROUTES],
|
|
52
|
+
socket_routes: [syncStreamReactive]
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
public registerAPI(api: api.RouteAPI) {
|
|
57
|
+
if (this.api) {
|
|
58
|
+
logger.warn('A RouteAPI has already been registered. Overriding existing implementation');
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
this.api = api;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
public getAPI(): api.RouteAPI {
|
|
65
|
+
if (!this.api) {
|
|
66
|
+
throw new Error('No RouteAPI adapter has been registered yet.');
|
|
67
|
+
}
|
|
68
|
+
return this.api;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Starts the router given the configuration provided
|
|
73
|
+
*/
|
|
74
|
+
async start(setup: RouterSetup) {
|
|
75
|
+
logger.info('Starting Router Engine...');
|
|
76
|
+
const { onShutdown } = await setup(this.routes);
|
|
77
|
+
this.cleanupHandler = onShutdown;
|
|
78
|
+
logger.info('Successfully started Router Engine.');
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Runs all stop handlers then final cleanup.
|
|
83
|
+
*/
|
|
84
|
+
async shutDown() {
|
|
85
|
+
logger.info('Shutting down Router Engine...');
|
|
86
|
+
// Close open streams, so that they don't block the server from closing.
|
|
87
|
+
// Note: This does not work well when streaming requests are queued. In that case, the server still doesn't
|
|
88
|
+
// close in the 30-second timeout.
|
|
89
|
+
this.closed = true;
|
|
90
|
+
|
|
91
|
+
logger.info(`Closing ${this.stopHandlers.size} streams.`);
|
|
92
|
+
for (let handler of this.stopHandlers) {
|
|
93
|
+
handler();
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
logger.info(`Running cleanup.`);
|
|
97
|
+
|
|
98
|
+
// Typically closes the server
|
|
99
|
+
await this.cleanupHandler?.();
|
|
100
|
+
|
|
101
|
+
// Close the api handlers
|
|
102
|
+
await this.api?.shutdown();
|
|
103
|
+
logger.info('Successfully shut down Router Engine.');
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Add a stop handler callback to be executed when the router engine is being
|
|
108
|
+
* shutdown.
|
|
109
|
+
*/
|
|
110
|
+
addStopHandler(handler: () => void): () => void {
|
|
111
|
+
if (this.closed) {
|
|
112
|
+
handler();
|
|
113
|
+
return () => {};
|
|
114
|
+
}
|
|
115
|
+
this.stopHandlers.add(handler);
|
|
116
|
+
return () => {
|
|
117
|
+
this.stopHandlers.delete(handler);
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
}
|
package/src/routes/auth.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import * as jose from 'jose';
|
|
2
2
|
|
|
3
3
|
import * as auth from '../auth/auth-index.js';
|
|
4
|
+
import { ServiceContext } from '../system/ServiceContext.js';
|
|
4
5
|
import * as util from '../util/util-index.js';
|
|
5
6
|
import { BasicRouterRequest, Context, RequestEndpointHandlerPayload } from './router.js';
|
|
6
|
-
import { CorePowerSyncSystem } from '../system/CorePowerSyncSystem.js';
|
|
7
7
|
|
|
8
8
|
export function endpoint(req: BasicRouterRequest) {
|
|
9
9
|
const protocol = req.headers['x-forwarded-proto'] ?? req.protocol;
|
|
@@ -108,7 +108,7 @@ export async function authorizeUser(context: Context, authHeader: string = '') {
|
|
|
108
108
|
};
|
|
109
109
|
}
|
|
110
110
|
|
|
111
|
-
const { context: tokenContext, errors } = await generateContext(context.
|
|
111
|
+
const { context: tokenContext, errors } = await generateContext(context.service_context, token);
|
|
112
112
|
|
|
113
113
|
if (!tokenContext) {
|
|
114
114
|
return {
|
|
@@ -121,14 +121,14 @@ export async function authorizeUser(context: Context, authHeader: string = '') {
|
|
|
121
121
|
return { authorized: true };
|
|
122
122
|
}
|
|
123
123
|
|
|
124
|
-
export async function generateContext(
|
|
125
|
-
const
|
|
124
|
+
export async function generateContext(serviceContext: ServiceContext, token: string) {
|
|
125
|
+
const { configuration } = serviceContext;
|
|
126
126
|
|
|
127
127
|
let tokenPayload: auth.JwtPayload;
|
|
128
128
|
try {
|
|
129
|
-
const maxAge =
|
|
130
|
-
tokenPayload = await
|
|
131
|
-
defaultAudiences:
|
|
129
|
+
const maxAge = configuration.token_max_expiration;
|
|
130
|
+
tokenPayload = await configuration.client_keystore.verifyJwt(token, {
|
|
131
|
+
defaultAudiences: configuration.jwt_audiences,
|
|
132
132
|
maxAge: maxAge
|
|
133
133
|
});
|
|
134
134
|
return {
|
|
@@ -149,9 +149,14 @@ export async function generateContext(system: CorePowerSyncSystem, token: string
|
|
|
149
149
|
* @deprecated
|
|
150
150
|
*/
|
|
151
151
|
export const authDevUser = async (payload: RequestEndpointHandlerPayload) => {
|
|
152
|
-
const
|
|
152
|
+
const {
|
|
153
|
+
context: {
|
|
154
|
+
service_context: { configuration }
|
|
155
|
+
}
|
|
156
|
+
} = payload;
|
|
157
|
+
|
|
153
158
|
const token = getTokenFromHeader(payload.request.headers.authorization as string);
|
|
154
|
-
if (!
|
|
159
|
+
if (!configuration.dev.demo_auth) {
|
|
155
160
|
return {
|
|
156
161
|
authorized: false,
|
|
157
162
|
errors: ['Authentication disabled']
|
|
@@ -170,7 +175,7 @@ export const authDevUser = async (payload: RequestEndpointHandlerPayload) => {
|
|
|
170
175
|
|
|
171
176
|
let tokenPayload: auth.JwtPayload;
|
|
172
177
|
try {
|
|
173
|
-
tokenPayload = await
|
|
178
|
+
tokenPayload = await configuration.dev_client_keystore.verifyJwt(token, {
|
|
174
179
|
defaultAudiences: audience,
|
|
175
180
|
maxAge: '31d'
|
|
176
181
|
});
|
|
@@ -186,8 +191,12 @@ export const authDevUser = async (payload: RequestEndpointHandlerPayload) => {
|
|
|
186
191
|
};
|
|
187
192
|
|
|
188
193
|
export const authApi = (payload: RequestEndpointHandlerPayload) => {
|
|
189
|
-
const
|
|
190
|
-
|
|
194
|
+
const {
|
|
195
|
+
context: {
|
|
196
|
+
service_context: { configuration }
|
|
197
|
+
}
|
|
198
|
+
} = payload;
|
|
199
|
+
const api_keys = configuration.api_tokens;
|
|
191
200
|
if (api_keys.length == 0) {
|
|
192
201
|
return {
|
|
193
202
|
authorized: false,
|
|
@@ -9,7 +9,7 @@ import { PROBES_ROUTES } from './endpoints/probes.js';
|
|
|
9
9
|
import { SYNC_RULES_ROUTES } from './endpoints/sync-rules.js';
|
|
10
10
|
import { SYNC_STREAM_ROUTES } from './endpoints/sync-stream.js';
|
|
11
11
|
import { createRequestQueueHook, CreateRequestQueueParams } from './hooks.js';
|
|
12
|
-
import { RouteDefinition } from './router.js';
|
|
12
|
+
import { RouteDefinition, RouterServiceContext } from './router.js';
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
15
|
* A list of route definitions to be registered as endpoints.
|
|
@@ -17,7 +17,7 @@ import { RouteDefinition } from './router.js';
|
|
|
17
17
|
*/
|
|
18
18
|
export type RouteRegistrationOptions = {
|
|
19
19
|
routes: RouteDefinition[];
|
|
20
|
-
|
|
20
|
+
queue_options: CreateRequestQueueParams;
|
|
21
21
|
};
|
|
22
22
|
|
|
23
23
|
/**
|
|
@@ -26,25 +26,25 @@ export type RouteRegistrationOptions = {
|
|
|
26
26
|
*/
|
|
27
27
|
export type RouteDefinitions = {
|
|
28
28
|
api?: Partial<RouteRegistrationOptions>;
|
|
29
|
-
|
|
29
|
+
sync_stream?: Partial<RouteRegistrationOptions>;
|
|
30
30
|
};
|
|
31
31
|
|
|
32
32
|
export type FastifyServerConfig = {
|
|
33
|
-
|
|
33
|
+
service_context: system.ServiceContext;
|
|
34
34
|
routes?: RouteDefinitions;
|
|
35
35
|
};
|
|
36
36
|
|
|
37
37
|
export const DEFAULT_ROUTE_OPTIONS = {
|
|
38
38
|
api: {
|
|
39
39
|
routes: [...ADMIN_ROUTES, ...CHECKPOINT_ROUTES, ...SYNC_RULES_ROUTES, ...PROBES_ROUTES],
|
|
40
|
-
|
|
40
|
+
queue_options: {
|
|
41
41
|
concurrency: 10,
|
|
42
42
|
max_queue_depth: 20
|
|
43
43
|
}
|
|
44
44
|
},
|
|
45
|
-
|
|
45
|
+
sync_stream: {
|
|
46
46
|
routes: [...SYNC_STREAM_ROUTES],
|
|
47
|
-
|
|
47
|
+
queue_options: {
|
|
48
48
|
concurrency: 200,
|
|
49
49
|
max_queue_depth: 0
|
|
50
50
|
}
|
|
@@ -56,7 +56,20 @@ export const DEFAULT_ROUTE_OPTIONS = {
|
|
|
56
56
|
* concurrency queue limits or override routes.
|
|
57
57
|
*/
|
|
58
58
|
export function configureFastifyServer(server: fastify.FastifyInstance, options: FastifyServerConfig) {
|
|
59
|
-
const {
|
|
59
|
+
const { service_context, routes = DEFAULT_ROUTE_OPTIONS } = options;
|
|
60
|
+
|
|
61
|
+
const generateContext = async () => {
|
|
62
|
+
const { routerEngine } = service_context;
|
|
63
|
+
if (!routerEngine) {
|
|
64
|
+
throw new Error(`RouterEngine has not been registered`);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return {
|
|
68
|
+
user_id: undefined,
|
|
69
|
+
service_context: service_context as RouterServiceContext
|
|
70
|
+
};
|
|
71
|
+
};
|
|
72
|
+
|
|
60
73
|
/**
|
|
61
74
|
* Fastify creates an encapsulated context for each `.register` call.
|
|
62
75
|
* Creating a separate context here to separate the concurrency limits for Admin APIs
|
|
@@ -64,20 +77,11 @@ export function configureFastifyServer(server: fastify.FastifyInstance, options:
|
|
|
64
77
|
* https://github.com/fastify/fastify/blob/main/docs/Reference/Encapsulation.md
|
|
65
78
|
*/
|
|
66
79
|
server.register(async function (childContext) {
|
|
67
|
-
registerFastifyRoutes(
|
|
68
|
-
childContext,
|
|
69
|
-
async () => {
|
|
70
|
-
return {
|
|
71
|
-
user_id: undefined,
|
|
72
|
-
system: system
|
|
73
|
-
};
|
|
74
|
-
},
|
|
75
|
-
routes.api?.routes ?? DEFAULT_ROUTE_OPTIONS.api.routes
|
|
76
|
-
);
|
|
80
|
+
registerFastifyRoutes(childContext, generateContext, routes.api?.routes ?? DEFAULT_ROUTE_OPTIONS.api.routes);
|
|
77
81
|
// Limit the active concurrent requests
|
|
78
82
|
childContext.addHook(
|
|
79
83
|
'onRequest',
|
|
80
|
-
createRequestQueueHook(routes.api?.
|
|
84
|
+
createRequestQueueHook(routes.api?.queue_options ?? DEFAULT_ROUTE_OPTIONS.api.queue_options)
|
|
81
85
|
);
|
|
82
86
|
});
|
|
83
87
|
|
|
@@ -85,18 +89,13 @@ export function configureFastifyServer(server: fastify.FastifyInstance, options:
|
|
|
85
89
|
server.register(async function (childContext) {
|
|
86
90
|
registerFastifyRoutes(
|
|
87
91
|
childContext,
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
user_id: undefined,
|
|
91
|
-
system: system
|
|
92
|
-
};
|
|
93
|
-
},
|
|
94
|
-
routes.syncStream?.routes ?? DEFAULT_ROUTE_OPTIONS.syncStream.routes
|
|
92
|
+
generateContext,
|
|
93
|
+
routes.sync_stream?.routes ?? DEFAULT_ROUTE_OPTIONS.sync_stream.routes
|
|
95
94
|
);
|
|
96
95
|
// Limit the active concurrent requests
|
|
97
96
|
childContext.addHook(
|
|
98
97
|
'onRequest',
|
|
99
|
-
createRequestQueueHook(routes.
|
|
98
|
+
createRequestQueueHook(routes.sync_stream?.queue_options ?? DEFAULT_ROUTE_OPTIONS.sync_stream.queue_options)
|
|
100
99
|
);
|
|
101
100
|
});
|
|
102
101
|
}
|
|
@@ -4,22 +4,22 @@ import * as http from 'http';
|
|
|
4
4
|
import { errors, logger } from '@powersync/lib-services-framework';
|
|
5
5
|
import { ReactiveSocketRouter, RSocketRequestMeta } from '@powersync/service-rsocket-router';
|
|
6
6
|
|
|
7
|
-
import {
|
|
7
|
+
import { ServiceContext } from '../system/ServiceContext.js';
|
|
8
8
|
import { generateContext, getTokenFromHeader } from './auth.js';
|
|
9
9
|
import { syncStreamReactive } from './endpoints/socket-route.js';
|
|
10
10
|
import { RSocketContextMeta, SocketRouteGenerator } from './router-socket.js';
|
|
11
|
-
import { Context } from './router.js';
|
|
11
|
+
import { Context, RouterServiceContext } from './router.js';
|
|
12
12
|
|
|
13
13
|
export type RSockerRouterConfig = {
|
|
14
|
-
|
|
14
|
+
service_context: ServiceContext;
|
|
15
15
|
server: http.Server;
|
|
16
|
-
|
|
16
|
+
route_generators?: SocketRouteGenerator[];
|
|
17
17
|
};
|
|
18
18
|
|
|
19
19
|
export const DEFAULT_SOCKET_ROUTES = [syncStreamReactive];
|
|
20
20
|
|
|
21
21
|
export function configureRSocket(router: ReactiveSocketRouter<Context>, options: RSockerRouterConfig) {
|
|
22
|
-
const {
|
|
22
|
+
const { route_generators = DEFAULT_SOCKET_ROUTES, server, service_context } = options;
|
|
23
23
|
|
|
24
24
|
router.applyWebSocketEndpoints(server, {
|
|
25
25
|
contextProvider: async (data: Buffer) => {
|
|
@@ -32,16 +32,21 @@ export function configureRSocket(router: ReactiveSocketRouter<Context>, options:
|
|
|
32
32
|
try {
|
|
33
33
|
const extracted_token = getTokenFromHeader(token);
|
|
34
34
|
if (extracted_token != null) {
|
|
35
|
-
const { context, errors: token_errors } = await generateContext(
|
|
35
|
+
const { context, errors: token_errors } = await generateContext(options.service_context, extracted_token);
|
|
36
36
|
if (context?.token_payload == null) {
|
|
37
37
|
throw new errors.AuthorizationError(token_errors ?? 'Authentication required');
|
|
38
38
|
}
|
|
39
|
+
|
|
40
|
+
if (!service_context.routerEngine) {
|
|
41
|
+
throw new Error(`RouterEngine has not been registered`);
|
|
42
|
+
}
|
|
43
|
+
|
|
39
44
|
return {
|
|
40
45
|
token,
|
|
41
46
|
user_agent,
|
|
42
47
|
...context,
|
|
43
48
|
token_errors: token_errors,
|
|
44
|
-
|
|
49
|
+
service_context: service_context as RouterServiceContext
|
|
45
50
|
};
|
|
46
51
|
} else {
|
|
47
52
|
throw new errors.AuthorizationError('No token provided');
|
|
@@ -51,7 +56,7 @@ export function configureRSocket(router: ReactiveSocketRouter<Context>, options:
|
|
|
51
56
|
throw ex;
|
|
52
57
|
}
|
|
53
58
|
},
|
|
54
|
-
endpoints:
|
|
59
|
+
endpoints: route_generators.map((generator) => generator(router)),
|
|
55
60
|
metaDecoder: async (meta: Buffer) => {
|
|
56
61
|
return RSocketRequestMeta.decode(deserialize(meta) as any);
|
|
57
62
|
},
|