@powersync/service-core 1.13.1 → 1.13.3
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 +13 -0
- package/dist/replication/AbstractReplicator.d.ts +8 -2
- package/dist/replication/AbstractReplicator.js +25 -9
- package/dist/replication/AbstractReplicator.js.map +1 -1
- package/dist/routes/configure-rsocket.js +4 -2
- package/dist/routes/configure-rsocket.js.map +1 -1
- package/dist/routes/router.d.ts +1 -2
- package/dist/routes/router.js.map +1 -1
- package/package.json +1 -1
- package/src/replication/AbstractReplicator.ts +30 -10
- package/src/routes/configure-rsocket.ts +3 -2
- package/src/routes/router.ts +0 -1
- package/tsconfig.tsbuildinfo +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# @powersync/service-core
|
|
2
2
|
|
|
3
|
+
## 1.13.3
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 3e7d629: Fix MongoDB initial replication with mixed \_id types.
|
|
8
|
+
- e8cb8db: Fix websocket auth errors not correctly propagating the details, previously resulting in generic "[PSYNC_S2106] Authentication required" messages.
|
|
9
|
+
|
|
10
|
+
## 1.13.2
|
|
11
|
+
|
|
12
|
+
### Patch Changes
|
|
13
|
+
|
|
14
|
+
- c002948: Fix sync rule clearing process to not block sync rule processing.
|
|
15
|
+
|
|
3
16
|
## 1.13.1
|
|
4
17
|
|
|
5
18
|
### Patch Changes
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import winston from 'winston';
|
|
2
|
+
import { MetricsEngine } from '../metrics/MetricsEngine.js';
|
|
2
3
|
import * as storage from '../storage/storage-index.js';
|
|
3
4
|
import { StorageEngine } from '../storage/storage-index.js';
|
|
4
5
|
import { SyncRulesProvider } from '../util/config/sync-rules/sync-rules-provider.js';
|
|
5
6
|
import { AbstractReplicationJob } from './AbstractReplicationJob.js';
|
|
6
7
|
import { ErrorRateLimiter } from './ErrorRateLimiter.js';
|
|
7
8
|
import { ConnectionTestResult } from './ReplicationModule.js';
|
|
8
|
-
import { MetricsEngine } from '../metrics/MetricsEngine.js';
|
|
9
9
|
export interface CreateJobOptions {
|
|
10
10
|
lock: storage.ReplicationLock;
|
|
11
11
|
storage: storage.SyncRulesBucketStorage;
|
|
@@ -31,9 +31,15 @@ export declare abstract class AbstractReplicator<T extends AbstractReplicationJo
|
|
|
31
31
|
/**
|
|
32
32
|
* Map of replication jobs by sync rule id. Usually there is only one running job, but there could be two when
|
|
33
33
|
* transitioning to a new set of sync rules.
|
|
34
|
-
* @private
|
|
35
34
|
*/
|
|
36
35
|
private replicationJobs;
|
|
36
|
+
/**
|
|
37
|
+
* Map of sync rule ids to promises that are clearing the sync rule configuration.
|
|
38
|
+
*
|
|
39
|
+
* We primarily do this to keep track of what we're currently clearing, but don't currently
|
|
40
|
+
* use the Promise value.
|
|
41
|
+
*/
|
|
42
|
+
private clearingJobs;
|
|
37
43
|
/**
|
|
38
44
|
* Used for replication lag computation.
|
|
39
45
|
*/
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { container, logger } from '@powersync/lib-services-framework';
|
|
2
|
-
import { hrtime } from 'node:process';
|
|
3
2
|
import { ReplicationMetric } from '@powersync/service-types';
|
|
3
|
+
import { hrtime } from 'node:process';
|
|
4
4
|
// 5 minutes
|
|
5
5
|
const PING_INTERVAL = 1000000000n * 300n;
|
|
6
6
|
/**
|
|
@@ -14,9 +14,15 @@ export class AbstractReplicator {
|
|
|
14
14
|
/**
|
|
15
15
|
* Map of replication jobs by sync rule id. Usually there is only one running job, but there could be two when
|
|
16
16
|
* transitioning to a new set of sync rules.
|
|
17
|
-
* @private
|
|
18
17
|
*/
|
|
19
18
|
replicationJobs = new Map();
|
|
19
|
+
/**
|
|
20
|
+
* Map of sync rule ids to promises that are clearing the sync rule configuration.
|
|
21
|
+
*
|
|
22
|
+
* We primarily do this to keep track of what we're currently clearing, but don't currently
|
|
23
|
+
* use the Promise value.
|
|
24
|
+
*/
|
|
25
|
+
clearingJobs = new Map();
|
|
20
26
|
/**
|
|
21
27
|
* Used for replication lag computation.
|
|
22
28
|
*/
|
|
@@ -194,17 +200,25 @@ export class AbstractReplicator {
|
|
|
194
200
|
this.logger.warn('Failed to stop old replication job}', e);
|
|
195
201
|
}
|
|
196
202
|
}
|
|
197
|
-
// Sync rules stopped previously
|
|
203
|
+
// Sync rules stopped previously, including by a different process.
|
|
198
204
|
const stopped = await this.storage.getStoppedSyncRules();
|
|
199
205
|
for (let syncRules of stopped) {
|
|
200
|
-
|
|
201
|
-
//
|
|
202
|
-
|
|
203
|
-
await this.terminateSyncRules(syncRuleStorage);
|
|
206
|
+
if (this.clearingJobs.has(syncRules.id)) {
|
|
207
|
+
// Already in progress
|
|
208
|
+
continue;
|
|
204
209
|
}
|
|
205
|
-
|
|
210
|
+
// We clear storage asynchronously.
|
|
211
|
+
// It is important to be able to continue running the refresh loop, otherwise we cannot
|
|
212
|
+
// retry locked sync rules, for example.
|
|
213
|
+
const syncRuleStorage = this.storage.getInstance(syncRules, { skipLifecycleHooks: true });
|
|
214
|
+
const promise = this.terminateSyncRules(syncRuleStorage)
|
|
215
|
+
.catch((e) => {
|
|
206
216
|
this.logger.warn(`Failed clean up replication config for sync rule: ${syncRules.id}`, e);
|
|
207
|
-
}
|
|
217
|
+
})
|
|
218
|
+
.finally(() => {
|
|
219
|
+
this.clearingJobs.delete(syncRules.id);
|
|
220
|
+
});
|
|
221
|
+
this.clearingJobs.set(syncRules.id, promise);
|
|
208
222
|
}
|
|
209
223
|
}
|
|
210
224
|
createJobId(syncRuleId) {
|
|
@@ -212,6 +226,8 @@ export class AbstractReplicator {
|
|
|
212
226
|
}
|
|
213
227
|
async terminateSyncRules(syncRuleStorage) {
|
|
214
228
|
this.logger.info(`Terminating sync rules: ${syncRuleStorage.group_id}...`);
|
|
229
|
+
// This deletes postgres replication slots - should complete quickly.
|
|
230
|
+
// It is safe to do before or after clearing the data in the storage.
|
|
215
231
|
await this.cleanUp(syncRuleStorage);
|
|
216
232
|
await syncRuleStorage.terminate({ signal: this.abortController?.signal, clearStorage: true });
|
|
217
233
|
this.logger.info(`Successfully terminated sync rules: ${syncRuleStorage.group_id}`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AbstractReplicator.js","sourceRoot":"","sources":["../../src/replication/AbstractReplicator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,mCAAmC,CAAC;AACtE,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"AbstractReplicator.js","sourceRoot":"","sources":["../../src/replication/AbstractReplicator.ts"],"names":[],"mappings":"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"}
|
|
@@ -22,14 +22,16 @@ export function configureRSocket(router, options) {
|
|
|
22
22
|
const extracted_token = getTokenFromHeader(token);
|
|
23
23
|
if (extracted_token != null) {
|
|
24
24
|
const { context, tokenError } = await generateContext(options.service_context, extracted_token);
|
|
25
|
-
if (
|
|
25
|
+
if (tokenError != null) {
|
|
26
|
+
throw tokenError;
|
|
27
|
+
}
|
|
28
|
+
else if (context?.token_payload == null) {
|
|
26
29
|
throw new errors.AuthorizationError(ErrorCode.PSYNC_S2106, 'Authentication required');
|
|
27
30
|
}
|
|
28
31
|
return {
|
|
29
32
|
token,
|
|
30
33
|
user_agent,
|
|
31
34
|
...context,
|
|
32
|
-
token_error: tokenError,
|
|
33
35
|
service_context: service_context,
|
|
34
36
|
logger: connectionLogger
|
|
35
37
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"configure-rsocket.js","sourceRoot":"","sources":["../../src/routes/configure-rsocket.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,MAAM,CAAC;AAEnC,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAE7B,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,mCAAmC,CAAC;AAC9E,OAAO,EAAwB,kBAAkB,EAAe,MAAM,mCAAmC,CAAC;AAG1G,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAChE,OAAO,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AACjE,OAAO,EAAE,kBAAkB,EAAwB,MAAM,oBAAoB,CAAC;AAS9E,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,kBAAkB,CAAC,CAAC;AAE1D,MAAM,UAAU,gBAAgB,CAAC,MAAqC,EAAE,OAA4B;IAClG,MAAM,EAAE,gBAAgB,GAAG,qBAAqB,EAAE,MAAM,EAAE,eAAe,EAAE,GAAG,OAAO,CAAC;IAEtF,MAAM,CAAC,uBAAuB,CAAC,MAAM,EAAE;QACrC,eAAe,EAAE,KAAK,EAAE,IAAiB,EAAwC,EAAE;YACjF,MAAM,gBAAgB,GAAG,MAAM,CAAC,KAAK,CAAC;gBACpC,6CAA6C;gBAC7C,GAAG,EAAE,KAAK,IAAI,CAAC,EAAE,EAAE,EAAE;aACtB,CAAC,CAAC;YACH,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,GAAG,kBAAkB,CAAC,MAAM,CAAC,WAAW,CAAC,IAAI,CAAQ,CAAC,CAAC;YAElF,IAAI,CAAC,KAAK,EAAE,CAAC;gBACX,MAAM,IAAI,MAAM,CAAC,kBAAkB,CAAC,SAAS,CAAC,WAAW,EAAE,mBAAmB,CAAC,CAAC;YAClF,CAAC;YAED,IAAI,CAAC;gBACH,MAAM,eAAe,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAC;gBAClD,IAAI,eAAe,IAAI,IAAI,EAAE,CAAC;oBAC5B,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,GAAG,MAAM,eAAe,CAAC,OAAO,CAAC,eAAe,EAAE,eAAe,CAAC,CAAC;oBAChG,IAAI,OAAO,EAAE,aAAa,IAAI,IAAI,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"configure-rsocket.js","sourceRoot":"","sources":["../../src/routes/configure-rsocket.ts"],"names":[],"mappings":"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"}
|
package/dist/routes/router.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { router,
|
|
1
|
+
import { router, Logger } from '@powersync/lib-services-framework';
|
|
2
2
|
import type { JwtPayload } from '../auth/auth-index.js';
|
|
3
3
|
import { ServiceContext } from '../system/ServiceContext.js';
|
|
4
4
|
/**
|
|
@@ -12,7 +12,6 @@ export type Context = {
|
|
|
12
12
|
user_id?: string;
|
|
13
13
|
service_context: RouterServiceContext;
|
|
14
14
|
token_payload?: JwtPayload;
|
|
15
|
-
token_error?: ServiceError;
|
|
16
15
|
/**
|
|
17
16
|
* Only on websocket endpoints.
|
|
18
17
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"router.js","sourceRoot":"","sources":["../../src/routes/router.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"router.js","sourceRoot":"","sources":["../../src/routes/router.ts"],"names":[],"mappings":"AAuDA;;GAEG;AACH,MAAM,UAAU,eAAe,CAC7B,MAA4C;IAE5C,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { container, logger } from '@powersync/lib-services-framework';
|
|
2
|
+
import { ReplicationMetric } from '@powersync/service-types';
|
|
2
3
|
import { hrtime } from 'node:process';
|
|
3
4
|
import winston from 'winston';
|
|
5
|
+
import { MetricsEngine } from '../metrics/MetricsEngine.js';
|
|
4
6
|
import * as storage from '../storage/storage-index.js';
|
|
5
7
|
import { StorageEngine } from '../storage/storage-index.js';
|
|
6
8
|
import { SyncRulesProvider } from '../util/config/sync-rules/sync-rules-provider.js';
|
|
7
9
|
import { AbstractReplicationJob } from './AbstractReplicationJob.js';
|
|
8
10
|
import { ErrorRateLimiter } from './ErrorRateLimiter.js';
|
|
9
11
|
import { ConnectionTestResult } from './ReplicationModule.js';
|
|
10
|
-
import { MetricsEngine } from '../metrics/MetricsEngine.js';
|
|
11
|
-
import { ReplicationMetric } from '@powersync/service-types';
|
|
12
12
|
|
|
13
13
|
// 5 minutes
|
|
14
14
|
const PING_INTERVAL = 1_000_000_000n * 300n;
|
|
@@ -40,9 +40,17 @@ export abstract class AbstractReplicator<T extends AbstractReplicationJob = Abst
|
|
|
40
40
|
/**
|
|
41
41
|
* Map of replication jobs by sync rule id. Usually there is only one running job, but there could be two when
|
|
42
42
|
* transitioning to a new set of sync rules.
|
|
43
|
-
* @private
|
|
44
43
|
*/
|
|
45
44
|
private replicationJobs = new Map<number, T>();
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Map of sync rule ids to promises that are clearing the sync rule configuration.
|
|
48
|
+
*
|
|
49
|
+
* We primarily do this to keep track of what we're currently clearing, but don't currently
|
|
50
|
+
* use the Promise value.
|
|
51
|
+
*/
|
|
52
|
+
private clearingJobs = new Map<number, Promise<void>>();
|
|
53
|
+
|
|
46
54
|
/**
|
|
47
55
|
* Used for replication lag computation.
|
|
48
56
|
*/
|
|
@@ -242,16 +250,26 @@ export abstract class AbstractReplicator<T extends AbstractReplicationJob = Abst
|
|
|
242
250
|
}
|
|
243
251
|
}
|
|
244
252
|
|
|
245
|
-
// Sync rules stopped previously
|
|
253
|
+
// Sync rules stopped previously, including by a different process.
|
|
246
254
|
const stopped = await this.storage.getStoppedSyncRules();
|
|
247
255
|
for (let syncRules of stopped) {
|
|
248
|
-
|
|
249
|
-
//
|
|
250
|
-
|
|
251
|
-
await this.terminateSyncRules(syncRuleStorage);
|
|
252
|
-
} catch (e) {
|
|
253
|
-
this.logger.warn(`Failed clean up replication config for sync rule: ${syncRules.id}`, e);
|
|
256
|
+
if (this.clearingJobs.has(syncRules.id)) {
|
|
257
|
+
// Already in progress
|
|
258
|
+
continue;
|
|
254
259
|
}
|
|
260
|
+
|
|
261
|
+
// We clear storage asynchronously.
|
|
262
|
+
// It is important to be able to continue running the refresh loop, otherwise we cannot
|
|
263
|
+
// retry locked sync rules, for example.
|
|
264
|
+
const syncRuleStorage = this.storage.getInstance(syncRules, { skipLifecycleHooks: true });
|
|
265
|
+
const promise = this.terminateSyncRules(syncRuleStorage)
|
|
266
|
+
.catch((e) => {
|
|
267
|
+
this.logger.warn(`Failed clean up replication config for sync rule: ${syncRules.id}`, e);
|
|
268
|
+
})
|
|
269
|
+
.finally(() => {
|
|
270
|
+
this.clearingJobs.delete(syncRules.id);
|
|
271
|
+
});
|
|
272
|
+
this.clearingJobs.set(syncRules.id, promise);
|
|
255
273
|
}
|
|
256
274
|
}
|
|
257
275
|
|
|
@@ -261,6 +279,8 @@ export abstract class AbstractReplicator<T extends AbstractReplicationJob = Abst
|
|
|
261
279
|
|
|
262
280
|
protected async terminateSyncRules(syncRuleStorage: storage.SyncRulesBucketStorage) {
|
|
263
281
|
this.logger.info(`Terminating sync rules: ${syncRuleStorage.group_id}...`);
|
|
282
|
+
// This deletes postgres replication slots - should complete quickly.
|
|
283
|
+
// It is safe to do before or after clearing the data in the storage.
|
|
264
284
|
await this.cleanUp(syncRuleStorage);
|
|
265
285
|
await syncRuleStorage.terminate({ signal: this.abortController?.signal, clearStorage: true });
|
|
266
286
|
this.logger.info(`Successfully terminated sync rules: ${syncRuleStorage.group_id}`);
|
|
@@ -38,7 +38,9 @@ export function configureRSocket(router: ReactiveSocketRouter<Context>, options:
|
|
|
38
38
|
const extracted_token = getTokenFromHeader(token);
|
|
39
39
|
if (extracted_token != null) {
|
|
40
40
|
const { context, tokenError } = await generateContext(options.service_context, extracted_token);
|
|
41
|
-
if (
|
|
41
|
+
if (tokenError != null) {
|
|
42
|
+
throw tokenError;
|
|
43
|
+
} else if (context?.token_payload == null) {
|
|
42
44
|
throw new errors.AuthorizationError(ErrorCode.PSYNC_S2106, 'Authentication required');
|
|
43
45
|
}
|
|
44
46
|
|
|
@@ -46,7 +48,6 @@ export function configureRSocket(router: ReactiveSocketRouter<Context>, options:
|
|
|
46
48
|
token,
|
|
47
49
|
user_agent,
|
|
48
50
|
...context,
|
|
49
|
-
token_error: tokenError,
|
|
50
51
|
service_context: service_context as RouterServiceContext,
|
|
51
52
|
logger: connectionLogger
|
|
52
53
|
};
|