@powersync/service-core 0.0.0-dev-20240718134716 → 0.0.0-dev-20240918082156
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +89 -6
- package/dist/api/RouteAPI.d.ts +68 -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 +11 -65
- package/dist/api/diagnostics.js.map +1 -1
- package/dist/api/schema.d.ts +3 -5
- package/dist/api/schema.js +9 -79
- package/dist/api/schema.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/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/entry/cli-entry.js +4 -2
- package/dist/entry/cli-entry.js.map +1 -1
- package/dist/entry/commands/compact-action.d.ts +2 -0
- package/dist/entry/commands/compact-action.js +52 -0
- package/dist/entry/commands/compact-action.js.map +1 -0
- 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/entry/entry-index.d.ts +1 -0
- package/dist/entry/entry-index.js +1 -0
- package/dist/entry/entry-index.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/metrics/Metrics.d.ts +6 -5
- package/dist/metrics/Metrics.js +53 -10
- 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/migrations.d.ts +8 -0
- package/dist/migrations/migrations.js +19 -7
- package/dist/migrations/migrations.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 +38 -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 +187 -0
- package/dist/replication/AbstractReplicator.js.map +1 -0
- package/dist/replication/ErrorRateLimiter.d.ts +0 -9
- 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 +39 -0
- package/dist/replication/ReplicationModule.js +65 -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 +737 -0
- package/dist/routes/configure-fastify.js +57 -0
- package/dist/routes/configure-fastify.js.map +1 -0
- package/dist/routes/configure-rsocket.d.ts +13 -0
- package/dist/routes/configure-rsocket.js +47 -0
- package/dist/routes/configure-rsocket.js.map +1 -0
- package/dist/routes/endpoints/admin.d.ts +0 -34
- package/dist/routes/endpoints/admin.js +48 -89
- package/dist/routes/endpoints/admin.js.map +1 -1
- package/dist/routes/endpoints/checkpointing.d.ts +56 -16
- package/dist/routes/endpoints/checkpointing.js +33 -12
- package/dist/routes/endpoints/checkpointing.js.map +1 -1
- package/dist/routes/endpoints/route-endpoints-index.d.ts +0 -1
- package/dist/routes/endpoints/route-endpoints-index.js +0 -1
- package/dist/routes/endpoints/route-endpoints-index.js.map +1 -1
- package/dist/routes/endpoints/socket-route.js +46 -39
- 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 +10 -0
- package/dist/routes/endpoints/sync-stream.js +17 -13
- package/dist/routes/endpoints/sync-stream.js.map +1 -1
- package/dist/routes/route-register.d.ts +1 -1
- package/dist/routes/route-register.js +1 -1
- package/dist/routes/route-register.js.map +1 -1
- package/dist/routes/router-socket.d.ts +5 -4
- package/dist/routes/router-socket.js +2 -1
- package/dist/routes/router-socket.js.map +1 -1
- package/dist/routes/router.d.ts +7 -2
- package/dist/routes/router.js.map +1 -1
- package/dist/routes/routes-index.d.ts +3 -0
- package/dist/routes/routes-index.js +3 -0
- package/dist/routes/routes-index.js.map +1 -1
- package/dist/runner/teardown.js +47 -76
- package/dist/runner/teardown.js.map +1 -1
- package/dist/storage/BucketStorage.d.ts +61 -20
- package/dist/storage/BucketStorage.js +0 -10
- package/dist/storage/BucketStorage.js.map +1 -1
- package/dist/storage/MongoBucketStorage.d.ts +4 -4
- package/dist/storage/MongoBucketStorage.js +19 -24
- package/dist/storage/MongoBucketStorage.js.map +1 -1
- 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 +4 -5
- package/dist/storage/SourceTable.js +3 -4
- package/dist/storage/SourceTable.js.map +1 -1
- package/dist/storage/StorageEngine.d.ts +24 -0
- package/dist/storage/StorageEngine.js +43 -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/mongo/MongoBucketBatch.d.ts +1 -1
- package/dist/storage/mongo/MongoBucketBatch.js +6 -7
- package/dist/storage/mongo/MongoBucketBatch.js.map +1 -1
- package/dist/storage/mongo/MongoCompactor.d.ts +40 -0
- package/dist/storage/mongo/MongoCompactor.js +293 -0
- package/dist/storage/mongo/MongoCompactor.js.map +1 -0
- 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 +9 -7
- package/dist/storage/mongo/MongoSyncBucketStorage.js +43 -28
- 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/OperationBatch.d.ts +7 -3
- package/dist/storage/mongo/OperationBatch.js +16 -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/models.d.ts +17 -7
- package/dist/storage/mongo/models.js.map +1 -1
- package/dist/storage/mongo/util.d.ts +14 -0
- package/dist/storage/mongo/util.js +70 -0
- package/dist/storage/mongo/util.js.map +1 -1
- package/dist/storage/storage-index.d.ts +5 -2
- package/dist/storage/storage-index.js +5 -2
- package/dist/storage/storage-index.js.map +1 -1
- package/dist/sync/RequestTracker.js +2 -3
- package/dist/sync/RequestTracker.js.map +1 -1
- package/dist/sync/sync-index.d.ts +1 -0
- package/dist/sync/sync-index.js +1 -0
- package/dist/sync/sync-index.js.map +1 -1
- package/dist/sync/sync.d.ts +2 -1
- package/dist/sync/sync.js +56 -17
- package/dist/sync/sync.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/config/collectors/config-collector.d.ts +12 -0
- package/dist/util/config/collectors/config-collector.js +43 -0
- package/dist/util/config/collectors/config-collector.js.map +1 -1
- package/dist/util/config/compound-config-collector.d.ts +10 -29
- package/dist/util/config/compound-config-collector.js +28 -84
- package/dist/util/config/compound-config-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 +6 -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/protocol-types.d.ts +4 -0
- package/dist/util/protocol-types.js +5 -1
- package/dist/util/protocol-types.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 -6
- package/dist/util/utils.js +45 -25
- package/dist/util/utils.js.map +1 -1
- package/package.json +7 -7
- package/src/api/RouteAPI.ts +78 -0
- package/src/api/api-index.ts +1 -0
- package/src/api/diagnostics.ts +16 -71
- package/src/api/schema.ts +13 -89
- package/src/auth/KeyStore.ts +9 -6
- package/src/auth/auth-index.ts +0 -1
- package/src/entry/cli-entry.ts +4 -2
- package/src/entry/commands/compact-action.ts +57 -0
- package/src/entry/commands/migrate-action.ts +5 -8
- package/src/entry/commands/teardown-action.ts +2 -2
- package/src/entry/entry-index.ts +1 -0
- package/src/index.ts +5 -2
- package/src/metrics/Metrics.ts +70 -15
- 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/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 +227 -0
- package/src/replication/ErrorRateLimiter.ts +0 -44
- package/src/replication/ReplicationEngine.ts +43 -0
- package/src/replication/ReplicationModule.ts +101 -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 +101 -0
- package/src/routes/configure-rsocket.ts +60 -0
- package/src/routes/endpoints/admin.ts +74 -100
- package/src/routes/endpoints/checkpointing.ts +46 -12
- package/src/routes/endpoints/route-endpoints-index.ts +0 -1
- package/src/routes/endpoints/socket-route.ts +50 -42
- package/src/routes/endpoints/sync-rules.ts +41 -25
- package/src/routes/endpoints/sync-stream.ts +17 -13
- package/src/routes/route-register.ts +2 -2
- package/src/routes/router-socket.ts +6 -5
- package/src/routes/router.ts +7 -2
- package/src/routes/routes-index.ts +3 -0
- package/src/runner/teardown.ts +50 -88
- package/src/storage/BucketStorage.ts +74 -26
- package/src/storage/MongoBucketStorage.ts +23 -26
- package/src/storage/SourceEntity.ts +22 -0
- package/src/storage/SourceTable.ts +4 -6
- package/src/storage/StorageEngine.ts +55 -0
- package/src/storage/StorageProvider.ts +27 -0
- package/src/storage/mongo/MongoBucketBatch.ts +8 -8
- package/src/storage/mongo/MongoCompactor.ts +372 -0
- package/src/storage/mongo/MongoPersistedSyncRulesContent.ts +3 -3
- package/src/storage/mongo/MongoStorageProvider.ts +31 -0
- package/src/storage/mongo/MongoSyncBucketStorage.ts +64 -34
- package/src/storage/mongo/MongoSyncRulesLock.ts +1 -1
- package/src/storage/mongo/OperationBatch.ts +18 -11
- package/src/storage/mongo/PersistedBatch.ts +6 -5
- package/src/storage/mongo/models.ts +17 -7
- package/src/storage/mongo/util.ts +71 -1
- package/src/storage/storage-index.ts +5 -2
- package/src/sync/RequestTracker.ts +3 -3
- package/src/sync/sync-index.ts +1 -0
- package/src/sync/sync.ts +66 -17
- package/src/system/ServiceContext.ts +68 -0
- package/src/system/system-index.ts +1 -1
- package/src/util/config/collectors/config-collector.ts +48 -0
- package/src/util/config/compound-config-collector.ts +45 -110
- package/src/util/config/sync-rules/sync-rules-provider.ts +18 -0
- package/src/util/config/types.ts +6 -5
- package/src/util/config.ts +6 -23
- package/src/util/protocol-types.ts +6 -1
- package/src/util/util-index.ts +3 -6
- package/src/util/utils.ts +55 -39
- package/test/src/__snapshots__/sync.test.ts.snap +90 -5
- package/test/src/auth.test.ts +7 -7
- package/test/src/broadcast_iterable.test.ts +1 -1
- package/test/src/bucket_validation.test.ts +142 -0
- package/test/src/bucket_validation.ts +116 -0
- package/test/src/checksum_cache.test.ts +3 -3
- package/test/src/compacting.test.ts +216 -0
- package/test/src/data_storage.test.ts +275 -204
- package/test/src/env.ts +1 -3
- package/test/src/merge_iterable.test.ts +1 -6
- package/test/src/setup.ts +1 -1
- package/test/src/stream_utils.ts +42 -0
- package/test/src/sync.test.ts +209 -48
- package/test/src/util.ts +110 -55
- package/test/tsconfig.json +1 -1
- package/tsconfig.tsbuildinfo +1 -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 -517
- 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/routes/endpoints/dev.d.ts +0 -312
- package/dist/routes/endpoints/dev.js +0 -172
- package/dist/routes/endpoints/dev.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 -628
- package/src/replication/WalStreamManager.ts +0 -213
- package/src/replication/WalStreamRunner.ts +0 -180
- package/src/replication/util.ts +0 -76
- package/src/routes/endpoints/dev.ts +0 -199
- 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 -296
- package/test/src/validation.test.ts +0 -63
- package/test/src/wal_stream.test.ts +0 -314
- package/test/src/wal_stream_utils.ts +0 -147
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,
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import type fastify from 'fastify';
|
|
2
|
+
import { registerFastifyRoutes } from './route-register.js';
|
|
3
|
+
|
|
4
|
+
import * as system from '../system/system-index.js';
|
|
5
|
+
|
|
6
|
+
import { ADMIN_ROUTES } from './endpoints/admin.js';
|
|
7
|
+
import { CHECKPOINT_ROUTES } from './endpoints/checkpointing.js';
|
|
8
|
+
import { SYNC_RULES_ROUTES } from './endpoints/sync-rules.js';
|
|
9
|
+
import { SYNC_STREAM_ROUTES } from './endpoints/sync-stream.js';
|
|
10
|
+
import { createRequestQueueHook, CreateRequestQueueParams } from './hooks.js';
|
|
11
|
+
import { RouteDefinition } from './router.js';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* A list of route definitions to be registered as endpoints.
|
|
15
|
+
* Supplied concurrency limits will be applied to the grouped routes.
|
|
16
|
+
*/
|
|
17
|
+
export type RouteRegistrationOptions = {
|
|
18
|
+
routes: RouteDefinition[];
|
|
19
|
+
queue_options: CreateRequestQueueParams;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* HTTP routes separated by API and Sync stream categories.
|
|
24
|
+
* This allows for separate concurrency limits.
|
|
25
|
+
*/
|
|
26
|
+
export type RouteDefinitions = {
|
|
27
|
+
api?: Partial<RouteRegistrationOptions>;
|
|
28
|
+
sync_stream?: Partial<RouteRegistrationOptions>;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export type FastifyServerConfig = {
|
|
32
|
+
service_context: system.ServiceContext;
|
|
33
|
+
routes?: RouteDefinitions;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export const DEFAULT_ROUTE_OPTIONS = {
|
|
37
|
+
api: {
|
|
38
|
+
routes: [...ADMIN_ROUTES, ...CHECKPOINT_ROUTES, ...SYNC_RULES_ROUTES],
|
|
39
|
+
queue_options: {
|
|
40
|
+
concurrency: 10,
|
|
41
|
+
max_queue_depth: 20
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
sync_stream: {
|
|
45
|
+
routes: [...SYNC_STREAM_ROUTES],
|
|
46
|
+
queue_options: {
|
|
47
|
+
concurrency: 200,
|
|
48
|
+
max_queue_depth: 0
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Registers default routes on a Fastify server. Consumers can optionally configure
|
|
55
|
+
* concurrency queue limits or override routes.
|
|
56
|
+
*/
|
|
57
|
+
export function configureFastifyServer(server: fastify.FastifyInstance, options: FastifyServerConfig) {
|
|
58
|
+
const { service_context, routes = DEFAULT_ROUTE_OPTIONS } = options;
|
|
59
|
+
/**
|
|
60
|
+
* Fastify creates an encapsulated context for each `.register` call.
|
|
61
|
+
* Creating a separate context here to separate the concurrency limits for Admin APIs
|
|
62
|
+
* and Sync Streaming routes.
|
|
63
|
+
* https://github.com/fastify/fastify/blob/main/docs/Reference/Encapsulation.md
|
|
64
|
+
*/
|
|
65
|
+
server.register(async function (childContext) {
|
|
66
|
+
registerFastifyRoutes(
|
|
67
|
+
childContext,
|
|
68
|
+
async () => {
|
|
69
|
+
return {
|
|
70
|
+
user_id: undefined,
|
|
71
|
+
service_context
|
|
72
|
+
};
|
|
73
|
+
},
|
|
74
|
+
routes.api?.routes ?? DEFAULT_ROUTE_OPTIONS.api.routes
|
|
75
|
+
);
|
|
76
|
+
// Limit the active concurrent requests
|
|
77
|
+
childContext.addHook(
|
|
78
|
+
'onRequest',
|
|
79
|
+
createRequestQueueHook(routes.api?.queue_options ?? DEFAULT_ROUTE_OPTIONS.api.queue_options)
|
|
80
|
+
);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
// Create a separate context for concurrency queueing
|
|
84
|
+
server.register(async function (childContext) {
|
|
85
|
+
registerFastifyRoutes(
|
|
86
|
+
childContext,
|
|
87
|
+
async () => {
|
|
88
|
+
return {
|
|
89
|
+
user_id: undefined,
|
|
90
|
+
service_context
|
|
91
|
+
};
|
|
92
|
+
},
|
|
93
|
+
routes.sync_stream?.routes ?? DEFAULT_ROUTE_OPTIONS.sync_stream.routes
|
|
94
|
+
);
|
|
95
|
+
// Limit the active concurrent requests
|
|
96
|
+
childContext.addHook(
|
|
97
|
+
'onRequest',
|
|
98
|
+
createRequestQueueHook(routes.sync_stream?.queue_options ?? DEFAULT_ROUTE_OPTIONS.sync_stream.queue_options)
|
|
99
|
+
);
|
|
100
|
+
});
|
|
101
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { deserialize } from 'bson';
|
|
2
|
+
import * as http from 'http';
|
|
3
|
+
|
|
4
|
+
import { errors, logger } from '@powersync/lib-services-framework';
|
|
5
|
+
import { ReactiveSocketRouter, RSocketRequestMeta } from '@powersync/service-rsocket-router';
|
|
6
|
+
|
|
7
|
+
import { ServiceContext } from '../system/ServiceContext.js';
|
|
8
|
+
import { generateContext, getTokenFromHeader } from './auth.js';
|
|
9
|
+
import { syncStreamReactive } from './endpoints/socket-route.js';
|
|
10
|
+
import { RSocketContextMeta, SocketRouteGenerator } from './router-socket.js';
|
|
11
|
+
import { Context } from './router.js';
|
|
12
|
+
|
|
13
|
+
export type RSockerRouterConfig = {
|
|
14
|
+
service_context: ServiceContext;
|
|
15
|
+
server: http.Server;
|
|
16
|
+
route_generators?: SocketRouteGenerator[];
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export const DEFAULT_SOCKET_ROUTES = [syncStreamReactive];
|
|
20
|
+
|
|
21
|
+
export function configureRSocket(router: ReactiveSocketRouter<Context>, options: RSockerRouterConfig) {
|
|
22
|
+
const { route_generators = DEFAULT_SOCKET_ROUTES, server, service_context } = options;
|
|
23
|
+
|
|
24
|
+
router.applyWebSocketEndpoints(server, {
|
|
25
|
+
contextProvider: async (data: Buffer) => {
|
|
26
|
+
const { token, user_agent } = RSocketContextMeta.decode(deserialize(data) as any);
|
|
27
|
+
|
|
28
|
+
if (!token) {
|
|
29
|
+
throw new errors.AuthorizationError('No token provided');
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
try {
|
|
33
|
+
const extracted_token = getTokenFromHeader(token);
|
|
34
|
+
if (extracted_token != null) {
|
|
35
|
+
const { context, errors: token_errors } = await generateContext(options.service_context, extracted_token);
|
|
36
|
+
if (context?.token_payload == null) {
|
|
37
|
+
throw new errors.AuthorizationError(token_errors ?? 'Authentication required');
|
|
38
|
+
}
|
|
39
|
+
return {
|
|
40
|
+
token,
|
|
41
|
+
user_agent,
|
|
42
|
+
...context,
|
|
43
|
+
token_errors: token_errors,
|
|
44
|
+
service_context
|
|
45
|
+
};
|
|
46
|
+
} else {
|
|
47
|
+
throw new errors.AuthorizationError('No token provided');
|
|
48
|
+
}
|
|
49
|
+
} catch (ex) {
|
|
50
|
+
logger.error(ex);
|
|
51
|
+
throw ex;
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
endpoints: route_generators.map((generator) => generator(router)),
|
|
55
|
+
metaDecoder: async (meta: Buffer) => {
|
|
56
|
+
return RSocketRequestMeta.decode(deserialize(meta) as any);
|
|
57
|
+
},
|
|
58
|
+
payloadDecoder: async (rawData?: Buffer) => rawData && deserialize(rawData)
|
|
59
|
+
});
|
|
60
|
+
}
|
|
@@ -1,35 +1,11 @@
|
|
|
1
1
|
import { errors, router, schema } from '@powersync/lib-services-framework';
|
|
2
|
-
import { SqlSyncRules,
|
|
2
|
+
import { SqlSyncRules, StaticSchema } from '@powersync/service-sync-rules';
|
|
3
3
|
import { internal_routes } from '@powersync/service-types';
|
|
4
4
|
|
|
5
5
|
import * as api from '../../api/api-index.js';
|
|
6
|
-
import * as
|
|
7
|
-
|
|
8
|
-
import { routeDefinition } from '../router.js';
|
|
9
|
-
import { PersistedSyncRulesContent } from '../../storage/BucketStorage.js';
|
|
6
|
+
import * as storage from '../../storage/storage-index.js';
|
|
10
7
|
import { authApi } from '../auth.js';
|
|
11
|
-
|
|
12
|
-
const demoCredentials = routeDefinition({
|
|
13
|
-
path: '/api/admin/v1/demo-credentials',
|
|
14
|
-
method: router.HTTPMethod.POST,
|
|
15
|
-
authorize: authApi,
|
|
16
|
-
validator: schema.createTsCodecValidator(internal_routes.DemoCredentialsRequest, {
|
|
17
|
-
allowAdditional: true
|
|
18
|
-
}),
|
|
19
|
-
handler: async (payload) => {
|
|
20
|
-
const connection = payload.context.system.config.connection;
|
|
21
|
-
if (connection == null || !connection.demo_database) {
|
|
22
|
-
return internal_routes.DemoCredentialsResponse.encode({});
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
const uri = util.buildDemoPgUri(connection);
|
|
26
|
-
return internal_routes.DemoCredentialsResponse.encode({
|
|
27
|
-
credentials: {
|
|
28
|
-
postgres_uri: uri
|
|
29
|
-
}
|
|
30
|
-
});
|
|
31
|
-
}
|
|
32
|
-
});
|
|
8
|
+
import { routeDefinition } from '../router.js';
|
|
33
9
|
|
|
34
10
|
export const executeSql = routeDefinition({
|
|
35
11
|
path: '/api/admin/v1/execute-sql',
|
|
@@ -37,47 +13,27 @@ export const executeSql = routeDefinition({
|
|
|
37
13
|
authorize: authApi,
|
|
38
14
|
validator: schema.createTsCodecValidator(internal_routes.ExecuteSqlRequest, { allowAdditional: true }),
|
|
39
15
|
handler: async (payload) => {
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
rows: []
|
|
46
|
-
},
|
|
47
|
-
success: false,
|
|
48
|
-
error: 'SQL querying is not enabled'
|
|
49
|
-
});
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
const pool = payload.context.system.requirePgPool();
|
|
53
|
-
|
|
54
|
-
const { query, args } = payload.params.sql;
|
|
16
|
+
const {
|
|
17
|
+
params: {
|
|
18
|
+
sql: { query, args }
|
|
19
|
+
}
|
|
20
|
+
} = payload;
|
|
55
21
|
|
|
56
|
-
|
|
57
|
-
const result = await pool.query({
|
|
58
|
-
statement: query,
|
|
59
|
-
params: args.map(util.autoParameter)
|
|
60
|
-
});
|
|
22
|
+
const apiHandler = payload.context.service_context.routerEngine!.getAPI();
|
|
61
23
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
results: {
|
|
65
|
-
columns: result.columns.map((c) => c.name),
|
|
66
|
-
rows: result.rows.map((row) => {
|
|
67
|
-
return row.map((value) => mapColumnValue(toSyncRulesValue(value)));
|
|
68
|
-
})
|
|
69
|
-
}
|
|
70
|
-
});
|
|
71
|
-
} catch (e) {
|
|
24
|
+
const sourceConfig = await apiHandler.getSourceConfig();
|
|
25
|
+
if (!sourceConfig.debug_api) {
|
|
72
26
|
return internal_routes.ExecuteSqlResponse.encode({
|
|
73
27
|
results: {
|
|
74
28
|
columns: [],
|
|
75
29
|
rows: []
|
|
76
30
|
},
|
|
77
31
|
success: false,
|
|
78
|
-
error:
|
|
32
|
+
error: 'SQL querying is not enabled'
|
|
79
33
|
});
|
|
80
34
|
}
|
|
35
|
+
|
|
36
|
+
return internal_routes.ExecuteSqlResponse.encode(await apiHandler.executeQuery(query, args));
|
|
81
37
|
}
|
|
82
38
|
});
|
|
83
39
|
|
|
@@ -87,34 +43,45 @@ export const diagnostics = routeDefinition({
|
|
|
87
43
|
authorize: authApi,
|
|
88
44
|
validator: schema.createTsCodecValidator(internal_routes.DiagnosticsRequest, { allowAdditional: true }),
|
|
89
45
|
handler: async (payload) => {
|
|
46
|
+
const { context } = payload;
|
|
47
|
+
const { service_context } = context;
|
|
90
48
|
const include_content = payload.params.sync_rules_content ?? false;
|
|
91
|
-
const system = payload.context.system;
|
|
92
49
|
|
|
93
|
-
const
|
|
94
|
-
|
|
50
|
+
const apiHandler = service_context.routerEngine!.getAPI();
|
|
51
|
+
|
|
52
|
+
const status = await apiHandler.getConnectionStatus();
|
|
53
|
+
if (!status) {
|
|
95
54
|
return internal_routes.DiagnosticsResponse.encode({
|
|
96
55
|
connections: []
|
|
97
56
|
});
|
|
98
57
|
}
|
|
99
58
|
|
|
100
|
-
const {
|
|
101
|
-
|
|
102
|
-
|
|
59
|
+
const {
|
|
60
|
+
storageEngine: { activeBucketStorage }
|
|
61
|
+
} = service_context;
|
|
62
|
+
const active = await activeBucketStorage.getActiveSyncRulesContent();
|
|
63
|
+
const next = await activeBucketStorage.getNextSyncRulesContent();
|
|
103
64
|
|
|
104
|
-
const active_status = await api.getSyncRulesStatus(
|
|
65
|
+
const active_status = await api.getSyncRulesStatus(activeBucketStorage, apiHandler, active, {
|
|
105
66
|
include_content,
|
|
106
67
|
check_connection: status.connected,
|
|
107
68
|
live_status: true
|
|
108
69
|
});
|
|
109
70
|
|
|
110
|
-
const next_status = await api.getSyncRulesStatus(
|
|
71
|
+
const next_status = await api.getSyncRulesStatus(activeBucketStorage, apiHandler, next, {
|
|
111
72
|
include_content,
|
|
112
73
|
check_connection: status.connected,
|
|
113
74
|
live_status: true
|
|
114
75
|
});
|
|
115
76
|
|
|
116
77
|
return internal_routes.DiagnosticsResponse.encode({
|
|
117
|
-
connections: [
|
|
78
|
+
connections: [
|
|
79
|
+
{
|
|
80
|
+
...status,
|
|
81
|
+
// TODO update this in future
|
|
82
|
+
postgres_uri: status.uri
|
|
83
|
+
}
|
|
84
|
+
],
|
|
118
85
|
active_sync_rules: active_status,
|
|
119
86
|
deploying_sync_rules: next_status
|
|
120
87
|
});
|
|
@@ -127,9 +94,9 @@ export const getSchema = routeDefinition({
|
|
|
127
94
|
authorize: authApi,
|
|
128
95
|
validator: schema.createTsCodecValidator(internal_routes.GetSchemaRequest, { allowAdditional: true }),
|
|
129
96
|
handler: async (payload) => {
|
|
130
|
-
const
|
|
97
|
+
const apiHandler = payload.context.service_context.routerEngine!.getAPI();
|
|
131
98
|
|
|
132
|
-
return internal_routes.GetSchemaResponse.encode(await api.getConnectionsSchema(
|
|
99
|
+
return internal_routes.GetSchemaResponse.encode(await api.getConnectionsSchema(apiHandler));
|
|
133
100
|
}
|
|
134
101
|
});
|
|
135
102
|
|
|
@@ -139,15 +106,19 @@ export const reprocess = routeDefinition({
|
|
|
139
106
|
authorize: authApi,
|
|
140
107
|
validator: schema.createTsCodecValidator(internal_routes.ReprocessRequest, { allowAdditional: true }),
|
|
141
108
|
handler: async (payload) => {
|
|
142
|
-
const
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
const
|
|
109
|
+
const {
|
|
110
|
+
context: { service_context }
|
|
111
|
+
} = payload;
|
|
112
|
+
const {
|
|
113
|
+
storageEngine: { activeBucketStorage }
|
|
114
|
+
} = service_context;
|
|
115
|
+
const apiHandler = service_context.routerEngine!.getAPI();
|
|
116
|
+
const next = await activeBucketStorage.getNextSyncRules(apiHandler.getParseSyncRulesOptions());
|
|
146
117
|
if (next != null) {
|
|
147
118
|
throw new Error(`Busy processing sync rules - cannot reprocess`);
|
|
148
119
|
}
|
|
149
120
|
|
|
150
|
-
const active = await
|
|
121
|
+
const active = await activeBucketStorage.getActiveSyncRules(apiHandler.getParseSyncRulesOptions());
|
|
151
122
|
if (active == null) {
|
|
152
123
|
throw new errors.JourneyError({
|
|
153
124
|
status: 422,
|
|
@@ -156,15 +127,18 @@ export const reprocess = routeDefinition({
|
|
|
156
127
|
});
|
|
157
128
|
}
|
|
158
129
|
|
|
159
|
-
const new_rules = await
|
|
130
|
+
const new_rules = await activeBucketStorage.updateSyncRules({
|
|
160
131
|
content: active.sync_rules.content
|
|
161
132
|
});
|
|
162
133
|
|
|
134
|
+
const baseConfig = await apiHandler.getSourceConfig();
|
|
135
|
+
|
|
163
136
|
return internal_routes.ReprocessResponse.encode({
|
|
164
137
|
connections: [
|
|
165
138
|
{
|
|
166
|
-
|
|
167
|
-
|
|
139
|
+
// Previously the connection was asserted with `!`
|
|
140
|
+
tag: baseConfig!.tag!,
|
|
141
|
+
id: baseConfig!.id,
|
|
168
142
|
slot_name: new_rules.slot_name
|
|
169
143
|
}
|
|
170
144
|
]
|
|
@@ -178,14 +152,16 @@ export const validate = routeDefinition({
|
|
|
178
152
|
authorize: authApi,
|
|
179
153
|
validator: schema.createTsCodecValidator(internal_routes.ValidateRequest, { allowAdditional: true }),
|
|
180
154
|
handler: async (payload) => {
|
|
181
|
-
const
|
|
182
|
-
|
|
155
|
+
const {
|
|
156
|
+
context: { service_context }
|
|
157
|
+
} = payload;
|
|
183
158
|
const content = payload.params.sync_rules;
|
|
159
|
+
const apiHandler = service_context.routerEngine!.getAPI();
|
|
184
160
|
|
|
185
|
-
const schemaData = await api.getConnectionsSchema(
|
|
161
|
+
const schemaData = await api.getConnectionsSchema(apiHandler);
|
|
186
162
|
const schema = new StaticSchema(schemaData.connections);
|
|
187
163
|
|
|
188
|
-
const sync_rules: PersistedSyncRulesContent = {
|
|
164
|
+
const sync_rules: storage.PersistedSyncRulesContent = {
|
|
189
165
|
// Dummy values
|
|
190
166
|
id: 0,
|
|
191
167
|
slot_name: '',
|
|
@@ -193,7 +169,10 @@ export const validate = routeDefinition({
|
|
|
193
169
|
parsed() {
|
|
194
170
|
return {
|
|
195
171
|
...this,
|
|
196
|
-
sync_rules: SqlSyncRules.fromYaml(content, {
|
|
172
|
+
sync_rules: SqlSyncRules.fromYaml(content, {
|
|
173
|
+
...apiHandler.getParseSyncRulesOptions(),
|
|
174
|
+
schema
|
|
175
|
+
})
|
|
197
176
|
};
|
|
198
177
|
},
|
|
199
178
|
sync_rules_content: content,
|
|
@@ -202,19 +181,24 @@ export const validate = routeDefinition({
|
|
|
202
181
|
}
|
|
203
182
|
};
|
|
204
183
|
|
|
205
|
-
const connectionStatus = await
|
|
206
|
-
if (connectionStatus
|
|
184
|
+
const connectionStatus = await apiHandler.getConnectionStatus();
|
|
185
|
+
if (!connectionStatus) {
|
|
207
186
|
return internal_routes.ValidateResponse.encode({
|
|
208
187
|
errors: [{ level: 'fatal', message: 'No connection configured' }],
|
|
209
188
|
connections: []
|
|
210
189
|
});
|
|
211
190
|
}
|
|
212
191
|
|
|
213
|
-
const status = (await api.getSyncRulesStatus(
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
192
|
+
const status = (await api.getSyncRulesStatus(
|
|
193
|
+
service_context.storageEngine.activeBucketStorage,
|
|
194
|
+
apiHandler,
|
|
195
|
+
sync_rules,
|
|
196
|
+
{
|
|
197
|
+
include_content: false,
|
|
198
|
+
check_connection: connectionStatus.connected,
|
|
199
|
+
live_status: false
|
|
200
|
+
}
|
|
201
|
+
))!;
|
|
218
202
|
|
|
219
203
|
if (connectionStatus == null) {
|
|
220
204
|
status.errors.push({ level: 'fatal', message: 'No connection configured' });
|
|
@@ -224,14 +208,4 @@ export const validate = routeDefinition({
|
|
|
224
208
|
}
|
|
225
209
|
});
|
|
226
210
|
|
|
227
|
-
|
|
228
|
-
if (typeof value == 'bigint') {
|
|
229
|
-
return Number(value);
|
|
230
|
-
} else if (isJsonValue(value)) {
|
|
231
|
-
return value;
|
|
232
|
-
} else {
|
|
233
|
-
return null;
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
export const ADMIN_ROUTES = [demoCredentials, executeSql, diagnostics, getSchema, reprocess, validate];
|
|
211
|
+
export const ADMIN_ROUTES = [executeSql, diagnostics, getSchema, reprocess, validate];
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import * as t from 'ts-codec';
|
|
2
|
-
import { router, schema } from '@powersync/lib-services-framework';
|
|
2
|
+
import { logger, router, schema } from '@powersync/lib-services-framework';
|
|
3
3
|
|
|
4
4
|
import * as util from '../../util/util-index.js';
|
|
5
5
|
import { authUser } from '../auth.js';
|
|
6
6
|
import { routeDefinition } from '../router.js';
|
|
7
7
|
|
|
8
|
-
const WriteCheckpointRequest = t.object({
|
|
8
|
+
const WriteCheckpointRequest = t.object({
|
|
9
|
+
client_id: t.string.optional()
|
|
10
|
+
});
|
|
9
11
|
|
|
10
12
|
export const writeCheckpoint = routeDefinition({
|
|
11
13
|
path: '/write-checkpoint.json',
|
|
@@ -13,13 +15,33 @@ export const writeCheckpoint = routeDefinition({
|
|
|
13
15
|
authorize: authUser,
|
|
14
16
|
validator: schema.createTsCodecValidator(WriteCheckpointRequest, { allowAdditional: true }),
|
|
15
17
|
handler: async (payload) => {
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
+
const {
|
|
19
|
+
context: { service_context }
|
|
20
|
+
} = payload;
|
|
21
|
+
const apiHandler = service_context.routerEngine!.getAPI();
|
|
18
22
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
+
// This old API needs a persisted checkpoint id.
|
|
24
|
+
// Since we don't use LSNs anymore, the only way to get that is to wait.
|
|
25
|
+
const start = Date.now();
|
|
26
|
+
|
|
27
|
+
const head = await apiHandler.getReplicationHead();
|
|
28
|
+
|
|
29
|
+
const timeout = 50_000;
|
|
30
|
+
|
|
31
|
+
logger.info(`Waiting for LSN checkpoint: ${head}`);
|
|
32
|
+
while (Date.now() - start < timeout) {
|
|
33
|
+
const cp = await service_context.storageEngine.activeBucketStorage.getActiveCheckpoint();
|
|
34
|
+
if (!cp.hasSyncRules()) {
|
|
35
|
+
throw new Error('No sync rules available');
|
|
36
|
+
}
|
|
37
|
+
if (cp.lsn && cp.lsn >= head) {
|
|
38
|
+
logger.info(`Got write checkpoint: ${head} : ${cp.checkpoint}`);
|
|
39
|
+
return { checkpoint: cp.checkpoint };
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
await new Promise((resolve) => setTimeout(resolve, 30));
|
|
43
|
+
}
|
|
44
|
+
throw new Error('Timeout while waiting for checkpoint');
|
|
23
45
|
}
|
|
24
46
|
});
|
|
25
47
|
|
|
@@ -29,11 +51,23 @@ export const writeCheckpoint2 = routeDefinition({
|
|
|
29
51
|
authorize: authUser,
|
|
30
52
|
validator: schema.createTsCodecValidator(WriteCheckpointRequest, { allowAdditional: true }),
|
|
31
53
|
handler: async (payload) => {
|
|
32
|
-
const { user_id,
|
|
33
|
-
|
|
34
|
-
const
|
|
54
|
+
const { user_id, service_context } = payload.context;
|
|
55
|
+
|
|
56
|
+
const apiHandler = service_context.routerEngine!.getAPI();
|
|
57
|
+
|
|
58
|
+
const client_id = payload.params.client_id;
|
|
59
|
+
const full_user_id = util.checkpointUserId(user_id, client_id);
|
|
60
|
+
|
|
61
|
+
const currentCheckpoint = await apiHandler.getReplicationHead();
|
|
62
|
+
const {
|
|
63
|
+
storageEngine: { activeBucketStorage }
|
|
64
|
+
} = service_context;
|
|
65
|
+
|
|
66
|
+
const writeCheckpoint = await activeBucketStorage.createWriteCheckpoint(full_user_id, { '1': currentCheckpoint });
|
|
67
|
+
logger.info(`Write checkpoint 2: ${JSON.stringify({ currentCheckpoint, id: String(full_user_id) })}`);
|
|
68
|
+
|
|
35
69
|
return {
|
|
36
|
-
write_checkpoint: String(
|
|
70
|
+
write_checkpoint: String(writeCheckpoint)
|
|
37
71
|
};
|
|
38
72
|
}
|
|
39
73
|
});
|