@powersync/service-module-mysql 0.0.0-dev-20250117095455 → 0.0.0-dev-20250214100224
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 +52 -8
- package/dist/api/MySQLRouteAPIAdapter.d.ts +2 -1
- package/dist/api/MySQLRouteAPIAdapter.js +8 -0
- package/dist/api/MySQLRouteAPIAdapter.js.map +1 -1
- package/dist/common/ReplicatedGTID.js +5 -4
- package/dist/common/ReplicatedGTID.js.map +1 -1
- package/dist/module/MySQLModule.d.ts +3 -2
- package/dist/module/MySQLModule.js +8 -2
- package/dist/module/MySQLModule.js.map +1 -1
- package/dist/replication/BinLogReplicationJob.js +3 -2
- package/dist/replication/BinLogReplicationJob.js.map +1 -1
- package/dist/replication/BinLogReplicator.d.ts +1 -0
- package/dist/replication/BinLogReplicator.js +5 -0
- package/dist/replication/BinLogReplicator.js.map +1 -1
- package/dist/replication/BinLogStream.js +12 -6
- package/dist/replication/BinLogStream.js.map +1 -1
- package/dist/replication/MySQLConnectionManager.js +12 -2
- package/dist/replication/MySQLConnectionManager.js.map +1 -1
- package/dist/replication/MySQLConnectionManagerFactory.d.ts +1 -1
- package/dist/replication/MySQLConnectionManagerFactory.js +2 -0
- package/dist/replication/MySQLConnectionManagerFactory.js.map +1 -1
- package/dist/replication/MySQLErrorRateLimiter.js +5 -7
- package/dist/replication/MySQLErrorRateLimiter.js.map +1 -1
- package/dist/types/types.js +6 -6
- package/dist/types/types.js.map +1 -1
- package/package.json +9 -9
- package/src/api/MySQLRouteAPIAdapter.ts +10 -1
- package/src/module/MySQLModule.ts +18 -4
- package/src/replication/BinLogReplicationJob.ts +1 -1
- package/src/replication/BinLogReplicator.ts +5 -0
- package/src/replication/BinLogStream.ts +4 -4
- package/src/replication/MySQLConnectionManagerFactory.ts +1 -1
- package/src/types/types.ts +9 -7
- package/test/src/BinlogStreamUtils.ts +1 -1
- package/tsconfig.tsbuildinfo +1 -1
package/dist/types/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/types/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,0BAA0B,EAAE,MAAM,mCAAmC,CAAC;
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/types/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@powersync/service-module-mysql",
|
|
3
3
|
"repository": "https://github.com/powersync-ja/powersync-service",
|
|
4
4
|
"types": "dist/index.d.ts",
|
|
5
|
-
"version": "0.0.0-dev-
|
|
5
|
+
"version": "0.0.0-dev-20250214100224",
|
|
6
6
|
"license": "FSL-1.1-Apache-2.0",
|
|
7
7
|
"main": "dist/index.js",
|
|
8
8
|
"type": "module",
|
|
@@ -29,19 +29,19 @@
|
|
|
29
29
|
"ts-codec": "^1.3.0",
|
|
30
30
|
"uri-js": "^4.4.1",
|
|
31
31
|
"uuid": "^9.0.1",
|
|
32
|
-
"@powersync/lib-services-framework": "0.
|
|
33
|
-
"@powersync/service-core": "0.0.0-dev-
|
|
34
|
-
"@powersync/service-sync-rules": "0.23.
|
|
35
|
-
"@powersync/service-
|
|
36
|
-
"@powersync/service-
|
|
32
|
+
"@powersync/lib-services-framework": "0.5.1",
|
|
33
|
+
"@powersync/service-core": "0.0.0-dev-20250214100224",
|
|
34
|
+
"@powersync/service-sync-rules": "0.23.4",
|
|
35
|
+
"@powersync/service-jsonbig": "0.17.10",
|
|
36
|
+
"@powersync/service-types": "0.8.0"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
39
|
"@types/semver": "^7.5.4",
|
|
40
40
|
"@types/async": "^3.2.24",
|
|
41
41
|
"@types/uuid": "^9.0.4",
|
|
42
|
-
"@powersync/service-core-tests": "0.0.0-dev-
|
|
43
|
-
"@powersync/service-module-mongodb-storage": "0.0.0-dev-
|
|
44
|
-
"@powersync/service-module-postgres-storage": "0.0.0-dev-
|
|
42
|
+
"@powersync/service-core-tests": "0.0.0-dev-20250214100224",
|
|
43
|
+
"@powersync/service-module-mongodb-storage": "0.0.0-dev-20250214100224",
|
|
44
|
+
"@powersync/service-module-postgres-storage": "0.0.0-dev-20250214100224"
|
|
45
45
|
},
|
|
46
46
|
"scripts": {
|
|
47
47
|
"build": "tsc -b",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { api, ParseSyncRulesOptions, storage } from '@powersync/service-core';
|
|
1
|
+
import { api, ParseSyncRulesOptions, ReplicationHeadCallback, storage } from '@powersync/service-core';
|
|
2
2
|
|
|
3
3
|
import * as sync_rules from '@powersync/service-sync-rules';
|
|
4
4
|
import * as service_types from '@powersync/service-types';
|
|
@@ -275,6 +275,15 @@ export class MySQLRouteAPIAdapter implements api.RouteAPI {
|
|
|
275
275
|
return result.comparable;
|
|
276
276
|
}
|
|
277
277
|
|
|
278
|
+
async createReplicationHead<T>(callback: ReplicationHeadCallback<T>): Promise<T> {
|
|
279
|
+
const head = await this.getReplicationHead();
|
|
280
|
+
const r = await callback(head);
|
|
281
|
+
|
|
282
|
+
// TODO: make sure another message is replicated
|
|
283
|
+
|
|
284
|
+
return r;
|
|
285
|
+
}
|
|
286
|
+
|
|
278
287
|
async getConnectionSchema(): Promise<service_types.DatabaseSchema[]> {
|
|
279
288
|
const [results] = await this.retriedQuery({
|
|
280
289
|
query: `
|
|
@@ -1,4 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
api,
|
|
3
|
+
ConfigurationFileSyncRulesProvider,
|
|
4
|
+
ConnectionTestResult,
|
|
5
|
+
replication,
|
|
6
|
+
system,
|
|
7
|
+
TearDownOptions
|
|
8
|
+
} from '@powersync/service-core';
|
|
2
9
|
|
|
3
10
|
import { MySQLRouteAPIAdapter } from '../api/MySQLRouteAPIAdapter.js';
|
|
4
11
|
import { BinLogReplicator } from '../replication/BinLogReplicator.js';
|
|
@@ -54,10 +61,14 @@ export class MySQLModule extends replication.ReplicationModule<types.MySQLConnec
|
|
|
54
61
|
// No specific teardown required for MySQL
|
|
55
62
|
}
|
|
56
63
|
|
|
57
|
-
async testConnection(config: MySQLConnectionConfig)
|
|
64
|
+
async testConnection(config: MySQLConnectionConfig) {
|
|
58
65
|
this.decodeConfig(config);
|
|
59
|
-
const
|
|
60
|
-
|
|
66
|
+
const normalizedConfig = this.resolveConfig(this.decodedConfig!);
|
|
67
|
+
return await MySQLModule.testConnection(normalizedConfig);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
static async testConnection(normalizedConfig: types.ResolvedConnectionConfig): Promise<ConnectionTestResult> {
|
|
71
|
+
const connectionManager = new MySQLConnectionManager(normalizedConfig, {});
|
|
61
72
|
const connection = await connectionManager.getConnection();
|
|
62
73
|
try {
|
|
63
74
|
const errors = await checkSourceConfiguration(connection);
|
|
@@ -67,5 +78,8 @@ export class MySQLModule extends replication.ReplicationModule<types.MySQLConnec
|
|
|
67
78
|
} finally {
|
|
68
79
|
await connectionManager.end();
|
|
69
80
|
}
|
|
81
|
+
return {
|
|
82
|
+
connectionDescription: normalizedConfig.hostname
|
|
83
|
+
};
|
|
70
84
|
}
|
|
71
85
|
}
|
|
@@ -70,7 +70,7 @@ export class BinLogReplicationJob extends replication.AbstractReplicationJob {
|
|
|
70
70
|
if (this.abortController.signal.aborted) {
|
|
71
71
|
return;
|
|
72
72
|
}
|
|
73
|
-
this.logger.error(`Replication error`, e);
|
|
73
|
+
this.logger.error(`Sync rules ${this.id} Replication error`, e);
|
|
74
74
|
if (e.cause != null) {
|
|
75
75
|
this.logger.error(`cause`, e.cause);
|
|
76
76
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { replication, storage } from '@powersync/service-core';
|
|
2
2
|
import { BinLogReplicationJob } from './BinLogReplicationJob.js';
|
|
3
3
|
import { MySQLConnectionManagerFactory } from './MySQLConnectionManagerFactory.js';
|
|
4
|
+
import { MySQLModule } from '../module/MySQLModule.js';
|
|
4
5
|
|
|
5
6
|
export interface BinLogReplicatorOptions extends replication.AbstractReplicatorOptions {
|
|
6
7
|
connectionFactory: MySQLConnectionManagerFactory;
|
|
@@ -32,4 +33,8 @@ export class BinLogReplicator extends replication.AbstractReplicator<BinLogRepli
|
|
|
32
33
|
await super.stop();
|
|
33
34
|
await this.connectionFactory.shutdown();
|
|
34
35
|
}
|
|
36
|
+
|
|
37
|
+
async testConnection() {
|
|
38
|
+
return await MySQLModule.testConnection(this.connectionFactory.connectionConfig);
|
|
39
|
+
}
|
|
35
40
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { logger } from '@powersync/lib-services-framework';
|
|
1
|
+
import { logger, ReplicationAbortedError, ReplicationAssertionError } from '@powersync/lib-services-framework';
|
|
2
2
|
import * as sync_rules from '@powersync/service-sync-rules';
|
|
3
3
|
import async from 'async';
|
|
4
4
|
|
|
@@ -318,11 +318,11 @@ AND table_type = 'BASE TABLE';`,
|
|
|
318
318
|
|
|
319
319
|
for await (let row of stream) {
|
|
320
320
|
if (this.stopped) {
|
|
321
|
-
throw new
|
|
321
|
+
throw new ReplicationAbortedError('Abort signal received - initial replication interrupted.');
|
|
322
322
|
}
|
|
323
323
|
|
|
324
324
|
if (columns == null) {
|
|
325
|
-
throw new
|
|
325
|
+
throw new ReplicationAssertionError(`No 'fields' event emitted`);
|
|
326
326
|
}
|
|
327
327
|
|
|
328
328
|
const record = common.toSQLiteRow(row, columns!);
|
|
@@ -383,7 +383,7 @@ AND table_type = 'BASE TABLE';`,
|
|
|
383
383
|
if (table == null) {
|
|
384
384
|
// We should always receive a replication message before the relation is used.
|
|
385
385
|
// If we can't find it, it's a bug.
|
|
386
|
-
throw new
|
|
386
|
+
throw new ReplicationAssertionError(`Missing relation cache for ${tableId}`);
|
|
387
387
|
}
|
|
388
388
|
return table;
|
|
389
389
|
}
|
|
@@ -5,7 +5,7 @@ import { ResolvedConnectionConfig } from '../types/types.js';
|
|
|
5
5
|
|
|
6
6
|
export class MySQLConnectionManagerFactory {
|
|
7
7
|
private readonly connectionManagers: MySQLConnectionManager[];
|
|
8
|
-
|
|
8
|
+
public readonly connectionConfig: ResolvedConnectionConfig;
|
|
9
9
|
|
|
10
10
|
constructor(connectionConfig: ResolvedConnectionConfig) {
|
|
11
11
|
this.connectionConfig = connectionConfig;
|
package/src/types/types.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { makeHostnameLookupFunction } from '@powersync/lib-services-framework';
|
|
1
|
+
import { ErrorCode, makeHostnameLookupFunction, ServiceError } from '@powersync/lib-services-framework';
|
|
2
2
|
import * as service_types from '@powersync/service-types';
|
|
3
|
-
import { reject } from 'async';
|
|
4
3
|
import { LookupFunction } from 'node:net';
|
|
5
4
|
import * as t from 'ts-codec';
|
|
6
5
|
import * as urijs from 'uri-js';
|
|
@@ -65,7 +64,10 @@ export function normalizeConnectionConfig(options: MySQLConnectionConfig): Norma
|
|
|
65
64
|
if (options.uri) {
|
|
66
65
|
uri = urijs.parse(options.uri);
|
|
67
66
|
if (uri.scheme != 'mysql') {
|
|
68
|
-
throw new
|
|
67
|
+
throw new ServiceError(
|
|
68
|
+
ErrorCode.PSYNC_S1109,
|
|
69
|
+
`Invalid URI - protocol must be mysql, got ${JSON.stringify(uri.scheme)}`
|
|
70
|
+
);
|
|
69
71
|
}
|
|
70
72
|
} else {
|
|
71
73
|
uri = urijs.parse('mysql:///');
|
|
@@ -82,19 +84,19 @@ export function normalizeConnectionConfig(options: MySQLConnectionConfig): Norma
|
|
|
82
84
|
const password = options.password ?? uri_password ?? '';
|
|
83
85
|
|
|
84
86
|
if (hostname == '') {
|
|
85
|
-
throw new
|
|
87
|
+
throw new ServiceError(ErrorCode.PSYNC_S1106, `MySQL connection: hostname required`);
|
|
86
88
|
}
|
|
87
89
|
|
|
88
90
|
if (username == '') {
|
|
89
|
-
throw new
|
|
91
|
+
throw new ServiceError(ErrorCode.PSYNC_S1107, `MySQL connection: username required`);
|
|
90
92
|
}
|
|
91
93
|
|
|
92
94
|
if (password == '') {
|
|
93
|
-
throw new
|
|
95
|
+
throw new ServiceError(ErrorCode.PSYNC_S1108, `MySQL connection: password required`);
|
|
94
96
|
}
|
|
95
97
|
|
|
96
98
|
if (database == '') {
|
|
97
|
-
throw new
|
|
99
|
+
throw new ServiceError(ErrorCode.PSYNC_S1105, `MySQL connection: database required`);
|
|
98
100
|
}
|
|
99
101
|
|
|
100
102
|
const lookup = makeHostnameLookupFunction(hostname, { reject_ip_ranges: options.reject_ip_ranges ?? [] });
|
|
@@ -61,7 +61,7 @@ export class BinlogStreamTestContext {
|
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
async updateSyncRules(content: string): Promise<SyncRulesBucketStorage> {
|
|
64
|
-
const syncRules = await this.factory.updateSyncRules({ content: content });
|
|
64
|
+
const syncRules = await this.factory.updateSyncRules({ content: content, validate: true });
|
|
65
65
|
this.storage = this.factory.getInstance(syncRules);
|
|
66
66
|
return this.storage!;
|
|
67
67
|
}
|