@vlasky/zongji 0.5.9 → 0.6.1
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 +60 -0
- package/README.md +48 -20
- package/docker-compose.yml +14 -13
- package/docker-test.sh +7 -7
- package/eslint.config.js +35 -0
- package/example.js +1 -1
- package/index.d.ts +314 -0
- package/index.js +444 -272
- package/jsconfig.json +15 -0
- package/lib/binlog_event.js +296 -217
- package/lib/code_map.js +7 -4
- package/lib/common.js +35 -22
- package/lib/datetime_decode.js +147 -34
- package/lib/json_decode.js +12 -6
- package/lib/packet/binlog.js +3 -3
- package/lib/packet/combinlog.js +22 -20
- package/lib/packet/index.js +50 -50
- package/lib/reader.js +215 -109
- package/lib/rows_event.js +98 -102
- package/lib/sequence/binlog.js +142 -39
- package/package.json +16 -11
- package/scripts/start-mysql.sh +28 -0
- package/.eslintrc +0 -19
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to @vlasky/zongji since forking from nevill/zongji.
|
|
4
|
+
|
|
5
|
+
## [0.6.1] - 2026-02-13
|
|
6
|
+
|
|
7
|
+
- Updated .gitignore and .npmignore to exclude AI tool and build/test files
|
|
8
|
+
- Added npm version, downloads, node version, and licence badges to README
|
|
9
|
+
|
|
10
|
+
## [0.6.0] - 2026-02-13
|
|
11
|
+
|
|
12
|
+
- Migrate from @vlasky/mysql to mysql2
|
|
13
|
+
- Convert codebase to ES modules
|
|
14
|
+
- Add TypeScript definitions
|
|
15
|
+
- Add official support for MySQL 8.4
|
|
16
|
+
- Fix sequence ID warnings when using compression with binlog streams
|
|
17
|
+
- Fix connection cleanup in stop() to prevent reuse of destroyed connections
|
|
18
|
+
- Add stopped flag to support dynamic filter updates and safe stop during init
|
|
19
|
+
- Fix flaky error test by handling all error events instead of just the first
|
|
20
|
+
|
|
21
|
+
## [0.5.9] - 2023-01-11
|
|
22
|
+
|
|
23
|
+
- Allow BLOB columns with utf8mb3 charset
|
|
24
|
+
|
|
25
|
+
## [0.5.8] - 2021-09-19
|
|
26
|
+
|
|
27
|
+
- Internal version bump
|
|
28
|
+
|
|
29
|
+
## [0.5.7] - 2021-07-08
|
|
30
|
+
|
|
31
|
+
- Fix connection when binlog_checksum is NONE
|
|
32
|
+
|
|
33
|
+
## [0.5.6] - 2021-04-30
|
|
34
|
+
|
|
35
|
+
- Update to @vlasky/mysql 2.18.5 with keepalive probe packet support
|
|
36
|
+
|
|
37
|
+
## [0.5.5] - 2021-04-17
|
|
38
|
+
|
|
39
|
+
- Update to @vlasky/mysql 2.18.4 to support additional charset collations in MySQL 8
|
|
40
|
+
|
|
41
|
+
## [0.5.4] - 2021-04-17
|
|
42
|
+
|
|
43
|
+
- Update to @vlasky/mysql 2.18.3 to support caching_sha2_password authentication plugin (MySQL 8 default)
|
|
44
|
+
|
|
45
|
+
## [0.5.3] - 2021-03-24
|
|
46
|
+
|
|
47
|
+
- Update to @vlasky/mysql 2.18.2 to support new MySQL 8 error codes
|
|
48
|
+
- Handle table map events that change table IDs (from YousefED)
|
|
49
|
+
- Fix null value in JSON column causing buffer RangeError (from YousefED)
|
|
50
|
+
- MySQL 8 compatibility fix for column mapping query order
|
|
51
|
+
|
|
52
|
+
## [0.5.2] - 2020-11-11
|
|
53
|
+
|
|
54
|
+
- Fix IEEE754 conversion error using DataView (from jefbarn)
|
|
55
|
+
- Update dependencies
|
|
56
|
+
|
|
57
|
+
## [0.5.1] - 2019-11-09
|
|
58
|
+
|
|
59
|
+
- Initial fork from nevill/zongji
|
|
60
|
+
- Add binlog_row_image support
|
package/README.md
CHANGED
|
@@ -1,23 +1,26 @@
|
|
|
1
|
-
|
|
1
|
+
[](https://www.npmjs.com/package/@vlasky/zongji)
|
|
2
|
+
[](https://www.npmjs.com/package/@vlasky/zongji)
|
|
3
|
+
[](https://www.npmjs.com/package/@vlasky/zongji)
|
|
4
|
+
[](https://github.com/vlasky/zongji/blob/master/LICENSE)
|
|
2
5
|
|
|
3
|
-
|
|
6
|
+
MySQL binlog-based change data capture (CDC) for Node.js, [originally created by Nevill Dutt](https://github.com/nevill/zongji).
|
|
4
7
|
|
|
5
|
-
|
|
8
|
+
[@vlasky/zongji](https://github.com/vlasky/zongji) has been tested working with MySQL 5.7, 8.0 and 8.4.
|
|
6
9
|
|
|
7
|
-
|
|
8
|
-
* Partial support for the MySQL compressed protocol (reads compressed data sent by server)
|
|
9
|
-
* Optional sending of keepalive probe packets to check the state of the connection to the MySQL server and help keep the connection open when the network socket is idle
|
|
10
|
+
It leverages [`mysql2`](https://github.com/sidorares/node-mysql2) for connections and authentication, while using zongji's binlog parsing and event pipeline.
|
|
10
11
|
|
|
11
12
|
# Latest Release
|
|
12
13
|
|
|
13
|
-
|
|
14
|
+
Version 0.6.0 is a major modernisation that rewrites the codebase to use the mysql2 module, ES6 syntax and ESM exports, adds TypeScript definitions, and adds official support for MySQL 8.4.
|
|
14
15
|
|
|
15
|
-
Version 0.
|
|
16
|
+
Version 0.5.9 is the last release that supports Node.js versions below 18 and CommonJS.
|
|
16
17
|
|
|
17
18
|
## Quick Start
|
|
18
19
|
|
|
19
20
|
```javascript
|
|
20
|
-
|
|
21
|
+
import ZongJi from '@vlasky/zongji';
|
|
22
|
+
|
|
23
|
+
const zongji = new ZongJi({ /* ... MySQL Connection Settings ... */ });
|
|
21
24
|
|
|
22
25
|
// Each change to the replication log results in an event
|
|
23
26
|
zongji.on('binlog', function(evt) {
|
|
@@ -30,18 +33,37 @@ zongji.start({
|
|
|
30
33
|
});
|
|
31
34
|
```
|
|
32
35
|
|
|
36
|
+
### GTID example
|
|
37
|
+
|
|
38
|
+
```javascript
|
|
39
|
+
zongji.on('binlog', function(evt) {
|
|
40
|
+
const type = evt.getTypeName();
|
|
41
|
+
if (type === 'Gtid' || type === 'AnonymousGtid') {
|
|
42
|
+
console.log('GTID:', evt.gtid, 'SID:', evt.sid, 'GNO:', evt.gno);
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### TypeScript
|
|
48
|
+
|
|
49
|
+
TypeScript definitions are included:
|
|
50
|
+
|
|
51
|
+
```typescript
|
|
52
|
+
import ZongJi from '@vlasky/zongji';
|
|
53
|
+
```
|
|
54
|
+
|
|
33
55
|
For a complete implementation see [`example.js`](example.js)...
|
|
34
56
|
|
|
35
57
|
## Installation
|
|
36
58
|
|
|
37
|
-
* Requires Node.js
|
|
59
|
+
* Requires Node.js v18+
|
|
38
60
|
|
|
39
61
|
```bash
|
|
40
62
|
$ npm install @vlasky/zongji
|
|
41
63
|
```
|
|
42
64
|
|
|
43
65
|
* Enable MySQL binlog in `my.cnf`, restart MySQL server after making the changes.
|
|
44
|
-
>
|
|
66
|
+
> Binlog checksum is enabled by default in all supported MySQL versions. Zongji can work with it, but it doesn't verify the checksum.
|
|
45
67
|
|
|
46
68
|
```
|
|
47
69
|
# Must be unique integer from 1-2^32
|
|
@@ -66,12 +88,12 @@ For a complete implementation see [`example.js`](example.js)...
|
|
|
66
88
|
|
|
67
89
|
The `ZongJi` constructor accepts one argument of either:
|
|
68
90
|
|
|
69
|
-
* An object containing MySQL connection details in the same format as used by [package
|
|
70
|
-
* Or, a [
|
|
91
|
+
* An object containing MySQL connection details in the same format as used by [package mysql2](https://npm.im/mysql2)
|
|
92
|
+
* Or, a [mysql2](https://npm.im/mysql2) `Connection` or `Pool` object that will be used for querying column information.
|
|
71
93
|
|
|
72
94
|
If a `Connection` or `Pool` object is passed to the constructor, it will not be destroyed/ended by Zongji's `stop()` method.
|
|
73
95
|
|
|
74
|
-
|
|
96
|
+
The `dateStrings` and `timezone` configuration options from the connection details are respected for date/time value handling.
|
|
75
97
|
|
|
76
98
|
Each instance includes the following methods:
|
|
77
99
|
|
|
@@ -85,7 +107,7 @@ Some events can be emitted in different phases:
|
|
|
85
107
|
|
|
86
108
|
Event Name | Description
|
|
87
109
|
-----------|------------------------
|
|
88
|
-
`ready` | This event
|
|
110
|
+
`ready` | This event occurs right after ZongJi successfully establishes a connection, sets up replica (slave) status, and sets the binlog position.
|
|
89
111
|
`binlog` | Once a binlog is received and passes the filter, it will bubble up with this event.
|
|
90
112
|
`error` | Every error will be caught by this event.
|
|
91
113
|
`stopped` | Emitted when ZongJi connection is stopped (ZongJi#stop is called).
|
|
@@ -116,6 +138,9 @@ Event name | Description
|
|
|
116
138
|
`rotate` | [New Binlog file](https://dev.mysql.com/doc/internals/en/rotate-event.html) Not required to be included to rotate to new files, but it is required to be included in order to keep the `filename` and `position` properties updated with current values for [graceful restarting on errors](https://gist.github.com/numtel/5b37b2a7f47b380c1a099596c6f3db2f).
|
|
117
139
|
`format` | [Format Description](https://dev.mysql.com/doc/internals/en/format-description-event.html)
|
|
118
140
|
`xid` | [Transaction ID](https://dev.mysql.com/doc/internals/en/xid-event.html)
|
|
141
|
+
`gtid` | GTID event with `gtid`, `sid`, `gno` properties
|
|
142
|
+
`anonymousgtid` | Anonymous GTID event (same shape as `gtid`)
|
|
143
|
+
`previousgtids` | Previous GTIDs event with `gtidSet` and `sids`
|
|
119
144
|
`tablemap` | Before any row event (must be included for any other row events)
|
|
120
145
|
`writerows` | Rows inserted, row data array available as `rows` property on event object
|
|
121
146
|
`updaterows` | Rows changed, row data array available as `rows` property on event object
|
|
@@ -132,20 +157,23 @@ Name | Description
|
|
|
132
157
|
|
|
133
158
|
## Important Notes
|
|
134
159
|
|
|
135
|
-
* :star2:
|
|
160
|
+
* :star2: All MySQL column types are supported, with type casting similar to [mysql2](https://github.com/sidorares/node-mysql2).
|
|
136
161
|
* :speak_no_evil: 64-bit integer is supported via package big-integer(see #108). If an integer is within the safe range of JS number (-2^53, 2^53), a Number object will returned, otherwise, will return as String.
|
|
137
162
|
* :point_right: `TRUNCATE` statement does not cause corresponding `DeleteRows` event. Use unqualified `DELETE FROM` for same effect.
|
|
138
|
-
* When using fractional seconds with `DATETIME` and `TIMESTAMP` data types
|
|
163
|
+
* When using fractional seconds with `DATETIME` and `TIMESTAMP` data types, only millisecond precision is available due to the limit of Javascript's `Date` object.
|
|
164
|
+
* Binlog checksums (e.g. `CRC32`) are supported; zongji will detect and ignore the checksum bytes at the end of row events.
|
|
139
165
|
|
|
140
166
|
## Run Tests
|
|
141
167
|
|
|
142
|
-
*
|
|
143
|
-
*
|
|
168
|
+
* Install [Docker](https://www.docker.com/community-edition#download)
|
|
169
|
+
* Run `docker-compose up -d` to start MySQL containers
|
|
170
|
+
* Run `npm test` to execute the test suite
|
|
144
171
|
|
|
145
172
|
## References
|
|
146
173
|
|
|
147
174
|
The following resources provided valuable information that greatly assisted in creating ZongJi:
|
|
148
175
|
|
|
176
|
+
* https://github.com/sidorares/node-mysql2
|
|
149
177
|
* https://github.com/mysqljs/mysql
|
|
150
178
|
* https://github.com/felixge/faster-than-c/
|
|
151
179
|
* https://web.archive.org/web/20130117004733/https://intuitive-search.blogspot.co.uk/2011/07/binary-log-api-and-replication-listener.html
|
|
@@ -153,7 +181,7 @@ The following resources provided valuable information that greatly assisted in c
|
|
|
153
181
|
* https://kkaefer.com/node-cpp-modules/
|
|
154
182
|
* https://dev.mysql.com/doc/internals/en/replication-protocol.html
|
|
155
183
|
* https://web.archive.org/web/20200201195450/https://www.cs.wichita.edu/~chang/lecture/cs742/program/how-mysql-c-api.html
|
|
156
|
-
* https://github.com/jeremycole/mysql_binlog (Ruby
|
|
184
|
+
* https://github.com/jeremycole/mysql_binlog (Ruby implementation of MySQL binlog parser)
|
|
157
185
|
* https://dev.mysql.com/doc/internals/en/date-and-time-data-type-representation.html
|
|
158
186
|
|
|
159
187
|
## License
|
package/docker-compose.yml
CHANGED
|
@@ -1,32 +1,33 @@
|
|
|
1
1
|
---
|
|
2
|
-
version: '2'
|
|
3
2
|
services:
|
|
4
|
-
|
|
5
|
-
image: mysql:5.
|
|
3
|
+
mysql57:
|
|
4
|
+
image: mysql:5.7
|
|
6
5
|
command: [ "--server-id=1", "--log-bin=/var/lib/mysql/mysql-bin.log", "--binlog-format=row"]
|
|
7
6
|
networks:
|
|
8
7
|
default:
|
|
9
8
|
aliases:
|
|
10
|
-
-
|
|
9
|
+
- mysql57
|
|
11
10
|
environment:
|
|
12
|
-
MYSQL_ROOT_PASSWORD:
|
|
11
|
+
MYSQL_ROOT_PASSWORD: secret
|
|
13
12
|
|
|
14
|
-
|
|
15
|
-
image: mysql:
|
|
13
|
+
mysql80:
|
|
14
|
+
image: mysql:8.0
|
|
16
15
|
command: [ "--server-id=1", "--log-bin=/var/lib/mysql/mysql-bin.log", "--binlog-format=row"]
|
|
17
16
|
networks:
|
|
18
17
|
default:
|
|
19
18
|
aliases:
|
|
20
|
-
-
|
|
19
|
+
- mysql80
|
|
21
20
|
environment:
|
|
22
|
-
MYSQL_ROOT_PASSWORD:
|
|
21
|
+
MYSQL_ROOT_PASSWORD: secret
|
|
23
22
|
|
|
24
|
-
|
|
25
|
-
image: mysql:
|
|
23
|
+
mysql84:
|
|
24
|
+
image: mysql:8.4
|
|
26
25
|
command: [ "--server-id=1", "--log-bin=/var/lib/mysql/mysql-bin.log", "--binlog-format=row"]
|
|
26
|
+
ports:
|
|
27
|
+
- "3306:3306"
|
|
27
28
|
networks:
|
|
28
29
|
default:
|
|
29
30
|
aliases:
|
|
30
|
-
-
|
|
31
|
+
- mysql84
|
|
31
32
|
environment:
|
|
32
|
-
MYSQL_ROOT_PASSWORD:
|
|
33
|
+
MYSQL_ROOT_PASSWORD: secret
|
package/docker-test.sh
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
|
-
MYSQL_HOSTS="
|
|
2
|
+
MYSQL_HOSTS="mysql57 mysql80 mysql84"
|
|
3
3
|
|
|
4
4
|
for hostname in ${MYSQL_HOSTS}; do
|
|
5
|
-
echo $hostname + node
|
|
6
|
-
docker run -it --network=zongji_default -e MYSQL_HOST=$hostname -w /build -v $PWD:/build node:
|
|
7
|
-
echo $hostname + node
|
|
8
|
-
docker run -it --network=zongji_default -e MYSQL_HOST=$hostname -w /build -v $PWD:/build node:
|
|
9
|
-
echo $hostname + node
|
|
10
|
-
docker run -it --network=zongji_default -e MYSQL_HOST=$hostname -w /build -v $PWD:/build node:
|
|
5
|
+
echo $hostname + node 18
|
|
6
|
+
docker run -it --network=zongji_default -e MYSQL_HOST=$hostname -w /build -v $PWD:/build node:18 npm test
|
|
7
|
+
echo $hostname + node 20
|
|
8
|
+
docker run -it --network=zongji_default -e MYSQL_HOST=$hostname -w /build -v $PWD:/build node:20 npm test
|
|
9
|
+
echo $hostname + node 22
|
|
10
|
+
docker run -it --network=zongji_default -e MYSQL_HOST=$hostname -w /build -v $PWD:/build node:22 npm test
|
|
11
11
|
done
|
package/eslint.config.js
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import js from '@eslint/js';
|
|
2
|
+
|
|
3
|
+
export default [
|
|
4
|
+
{ ignores: ['.tap/'] },
|
|
5
|
+
js.configs.recommended,
|
|
6
|
+
{
|
|
7
|
+
languageOptions: {
|
|
8
|
+
ecmaVersion: 2022,
|
|
9
|
+
sourceType: 'module',
|
|
10
|
+
globals: {
|
|
11
|
+
Buffer: 'readonly',
|
|
12
|
+
clearImmediate: 'readonly',
|
|
13
|
+
clearInterval: 'readonly',
|
|
14
|
+
clearTimeout: 'readonly',
|
|
15
|
+
console: 'readonly',
|
|
16
|
+
process: 'readonly',
|
|
17
|
+
setImmediate: 'readonly',
|
|
18
|
+
setInterval: 'readonly',
|
|
19
|
+
setTimeout: 'readonly',
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
rules: {
|
|
23
|
+
'comma-dangle': ['warn', 'only-multiline'],
|
|
24
|
+
'eol-last': ['error'],
|
|
25
|
+
'keyword-spacing': ['error', { before: true }],
|
|
26
|
+
'no-console': 'off',
|
|
27
|
+
'no-trailing-spaces': ['error', { skipBlankLines: true }],
|
|
28
|
+
'no-unused-vars': 'warn',
|
|
29
|
+
'no-var': 'warn',
|
|
30
|
+
'quotes': ['warn', 'single', 'avoid-escape'],
|
|
31
|
+
'semi': ['error', 'always'],
|
|
32
|
+
'space-before-blocks': 'error',
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
];
|
package/example.js
CHANGED
package/index.d.ts
ADDED
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
import { EventEmitter } from 'events';
|
|
2
|
+
import { Connection, Pool, ConnectionOptions, PoolOptions } from 'mysql2';
|
|
3
|
+
|
|
4
|
+
// Configuration options for ZongJi
|
|
5
|
+
export interface ZongJiOptions {
|
|
6
|
+
/** Unique server ID for the binlog connection (default: 1) */
|
|
7
|
+
serverId?: number;
|
|
8
|
+
/** If true, start reading from the end of the binlog */
|
|
9
|
+
startAtEnd?: boolean;
|
|
10
|
+
/** Binlog filename to start from */
|
|
11
|
+
filename?: string;
|
|
12
|
+
/** Binlog position to start from */
|
|
13
|
+
position?: number;
|
|
14
|
+
/** If true, use non-blocking mode */
|
|
15
|
+
nonBlock?: boolean;
|
|
16
|
+
/** List of event types to include (e.g., ['tablemap', 'writerows']) */
|
|
17
|
+
includeEvents?: string[];
|
|
18
|
+
/** List of event types to exclude */
|
|
19
|
+
excludeEvents?: string[];
|
|
20
|
+
/** Schema/table filter for inclusion. Use `true` for all tables in a schema, or array of table names */
|
|
21
|
+
includeSchema?: Record<string, string[] | true>;
|
|
22
|
+
/** Schema/table filter for exclusion */
|
|
23
|
+
excludeSchema?: Record<string, string[] | true>;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Column metadata from INFORMATION_SCHEMA
|
|
27
|
+
export interface ColumnSchema {
|
|
28
|
+
COLUMN_NAME: string;
|
|
29
|
+
COLLATION_NAME: string | null;
|
|
30
|
+
CHARACTER_SET_NAME: string | null;
|
|
31
|
+
COLUMN_COMMENT: string;
|
|
32
|
+
COLUMN_TYPE: string;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Column information from TableMap event
|
|
36
|
+
export interface ColumnInfo {
|
|
37
|
+
name: string;
|
|
38
|
+
charset: string | null;
|
|
39
|
+
type: number;
|
|
40
|
+
metadata: Record<string, unknown>;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Table metadata cached by ZongJi
|
|
44
|
+
export interface TableMapEntry {
|
|
45
|
+
columnSchemas: ColumnSchema[];
|
|
46
|
+
parentSchema: string;
|
|
47
|
+
tableName: string;
|
|
48
|
+
columns?: ColumnInfo[];
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Base binlog event class
|
|
52
|
+
export interface BinlogEvent {
|
|
53
|
+
/** Timestamp of the event in milliseconds */
|
|
54
|
+
timestamp: number;
|
|
55
|
+
/** Position in the binlog after this event */
|
|
56
|
+
nextPosition: number;
|
|
57
|
+
/** Size of the event in bytes */
|
|
58
|
+
size: number;
|
|
59
|
+
/** Get the lowercase event name */
|
|
60
|
+
getEventName(): string;
|
|
61
|
+
/** Get the event class name */
|
|
62
|
+
getTypeName(): string;
|
|
63
|
+
/** Print event details to console */
|
|
64
|
+
dump(): void;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Rotate event - indicates binlog file change
|
|
68
|
+
export interface RotateEvent extends BinlogEvent {
|
|
69
|
+
/** Position in the new binlog file */
|
|
70
|
+
position: number;
|
|
71
|
+
/** Name of the new binlog file */
|
|
72
|
+
binlogName: string;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Format Description event
|
|
76
|
+
export interface FormatEvent extends BinlogEvent {}
|
|
77
|
+
|
|
78
|
+
// GTID event
|
|
79
|
+
export interface GtidEvent extends BinlogEvent {
|
|
80
|
+
/** GTID flags */
|
|
81
|
+
flags: number;
|
|
82
|
+
/** Source UUID */
|
|
83
|
+
sid: string;
|
|
84
|
+
/** Group number */
|
|
85
|
+
gno: number;
|
|
86
|
+
/** Full GTID string (sid:gno) */
|
|
87
|
+
gtid: string;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Anonymous GTID event
|
|
91
|
+
export interface AnonymousGtidEvent extends BinlogEvent {
|
|
92
|
+
/** GTID flags */
|
|
93
|
+
flags: number;
|
|
94
|
+
/** Source UUID */
|
|
95
|
+
sid: string;
|
|
96
|
+
/** Group number */
|
|
97
|
+
gno: number;
|
|
98
|
+
/** Full GTID string (sid:gno) */
|
|
99
|
+
gtid: string;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Previous GTIDs event
|
|
103
|
+
export interface GtidInterval {
|
|
104
|
+
start: number;
|
|
105
|
+
end: number;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export interface GtidSidEntry {
|
|
109
|
+
sid: string;
|
|
110
|
+
intervals: GtidInterval[];
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export interface PreviousGtidsEvent extends BinlogEvent {
|
|
114
|
+
/** Array of SID entries with their intervals */
|
|
115
|
+
sids: GtidSidEntry[];
|
|
116
|
+
/** GTID set as a formatted string */
|
|
117
|
+
gtidSet: string;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// XID (commit) event
|
|
121
|
+
export interface XidEvent extends BinlogEvent {
|
|
122
|
+
/** Transaction ID for 2PC */
|
|
123
|
+
xid: number | string;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Query event
|
|
127
|
+
export interface QueryEvent extends BinlogEvent {
|
|
128
|
+
/** Slave proxy ID */
|
|
129
|
+
slaveProxyId: number;
|
|
130
|
+
/** Time in seconds the query took to execute */
|
|
131
|
+
executionTime: number;
|
|
132
|
+
/** Length of the schema name */
|
|
133
|
+
schemaLength: number;
|
|
134
|
+
/** Error code (0 for success) */
|
|
135
|
+
errorCode: number;
|
|
136
|
+
/** Length of status variables */
|
|
137
|
+
statusVarsLength: number;
|
|
138
|
+
/** Status variables */
|
|
139
|
+
statusVars: string;
|
|
140
|
+
/** Database/schema name */
|
|
141
|
+
schema: string;
|
|
142
|
+
/** The SQL query */
|
|
143
|
+
query: string;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// IntVar event (for statement-based replication)
|
|
147
|
+
export interface IntVarEvent extends BinlogEvent {
|
|
148
|
+
/** Variable type: 1=LAST_INSERT_ID, 2=INSERT_ID */
|
|
149
|
+
type: number;
|
|
150
|
+
/** The integer value */
|
|
151
|
+
value: number | string;
|
|
152
|
+
/** Get the variable type name */
|
|
153
|
+
getIntTypeName(): string;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// TableMap event
|
|
157
|
+
export interface TableMapEvent extends BinlogEvent {
|
|
158
|
+
/** Internal table ID */
|
|
159
|
+
tableId: number;
|
|
160
|
+
/** Table flags */
|
|
161
|
+
flags: number;
|
|
162
|
+
/** Database/schema name */
|
|
163
|
+
schemaName: string;
|
|
164
|
+
/** Table name */
|
|
165
|
+
tableName: string;
|
|
166
|
+
/** Number of columns */
|
|
167
|
+
columnCount: number;
|
|
168
|
+
/** Array of MySQL type codes for each column */
|
|
169
|
+
columnTypes: number[];
|
|
170
|
+
/** Column metadata */
|
|
171
|
+
columnsMetadata: Record<string, unknown>[];
|
|
172
|
+
/** Reference to the tableMap cache */
|
|
173
|
+
tableMap: Record<number, TableMapEntry>;
|
|
174
|
+
/** Update column info after fetching from INFORMATION_SCHEMA */
|
|
175
|
+
updateColumnInfo(): void;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Row data type - key is column name, value is column value
|
|
179
|
+
export type RowData = Record<string, unknown>;
|
|
180
|
+
|
|
181
|
+
// Update row with before/after values
|
|
182
|
+
export interface UpdateRowData {
|
|
183
|
+
before: RowData;
|
|
184
|
+
after: RowData;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Base rows event
|
|
188
|
+
export interface RowsEvent extends BinlogEvent {
|
|
189
|
+
/** Internal table ID */
|
|
190
|
+
tableId: number;
|
|
191
|
+
/** Event flags */
|
|
192
|
+
flags: number;
|
|
193
|
+
/** Number of columns */
|
|
194
|
+
numberOfColumns: number;
|
|
195
|
+
/** Reference to the tableMap cache */
|
|
196
|
+
tableMap: Record<number, TableMapEntry>;
|
|
197
|
+
/** Whether checksum is enabled */
|
|
198
|
+
useChecksum: boolean;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// WriteRows event (INSERT)
|
|
202
|
+
export interface WriteRowsEvent extends RowsEvent {
|
|
203
|
+
/** Array of inserted rows */
|
|
204
|
+
rows: RowData[];
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// DeleteRows event (DELETE)
|
|
208
|
+
export interface DeleteRowsEvent extends RowsEvent {
|
|
209
|
+
/** Array of deleted rows */
|
|
210
|
+
rows: RowData[];
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// UpdateRows event (UPDATE)
|
|
214
|
+
export interface UpdateRowsEvent extends RowsEvent {
|
|
215
|
+
/** Array of updated rows with before/after values */
|
|
216
|
+
rows: UpdateRowData[];
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// Unknown event type
|
|
220
|
+
export interface UnknownEvent extends BinlogEvent {}
|
|
221
|
+
|
|
222
|
+
// Union type of all event types
|
|
223
|
+
export type AnyBinlogEvent =
|
|
224
|
+
| RotateEvent
|
|
225
|
+
| FormatEvent
|
|
226
|
+
| GtidEvent
|
|
227
|
+
| AnonymousGtidEvent
|
|
228
|
+
| PreviousGtidsEvent
|
|
229
|
+
| XidEvent
|
|
230
|
+
| QueryEvent
|
|
231
|
+
| IntVarEvent
|
|
232
|
+
| TableMapEvent
|
|
233
|
+
| WriteRowsEvent
|
|
234
|
+
| DeleteRowsEvent
|
|
235
|
+
| UpdateRowsEvent
|
|
236
|
+
| UnknownEvent;
|
|
237
|
+
|
|
238
|
+
// Connection options - can be mysql2 options, Connection, or Pool
|
|
239
|
+
export type ZongJiDsn = string | ConnectionOptions | PoolOptions | Connection | Pool;
|
|
240
|
+
|
|
241
|
+
// Main ZongJi class
|
|
242
|
+
declare class ZongJi extends EventEmitter {
|
|
243
|
+
/** Cached table metadata */
|
|
244
|
+
tableMap: Record<number, TableMapEntry>;
|
|
245
|
+
/** Whether ZongJi is ready to receive events */
|
|
246
|
+
ready: boolean;
|
|
247
|
+
/** Whether ZongJi has been stopped */
|
|
248
|
+
stopped: boolean;
|
|
249
|
+
/** Whether binlog checksum is enabled */
|
|
250
|
+
useChecksum: boolean;
|
|
251
|
+
/** Current binlog options */
|
|
252
|
+
options: {
|
|
253
|
+
serverId?: number;
|
|
254
|
+
filename?: string;
|
|
255
|
+
position?: number;
|
|
256
|
+
startAtEnd?: boolean;
|
|
257
|
+
};
|
|
258
|
+
/** Current filter settings */
|
|
259
|
+
filters: {
|
|
260
|
+
includeEvents?: string[];
|
|
261
|
+
excludeEvents?: string[];
|
|
262
|
+
includeSchema?: Record<string, string[] | true>;
|
|
263
|
+
excludeSchema?: Record<string, string[] | true>;
|
|
264
|
+
};
|
|
265
|
+
/** The control connection (for metadata queries) */
|
|
266
|
+
ctrlConnection: Connection | null;
|
|
267
|
+
/** The binlog streaming connection */
|
|
268
|
+
connection: Connection | null;
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Create a new ZongJi instance
|
|
272
|
+
* @param dsn - Connection string, options object, or existing Connection/Pool
|
|
273
|
+
*/
|
|
274
|
+
constructor(dsn: ZongJiDsn);
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Start listening to the binlog
|
|
278
|
+
* @param options - Configuration options
|
|
279
|
+
*/
|
|
280
|
+
start(options?: ZongJiOptions): void;
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Stop listening to the binlog
|
|
284
|
+
*/
|
|
285
|
+
stop(): void;
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Get current option value(s)
|
|
289
|
+
* @param name - Option name or array of names
|
|
290
|
+
*/
|
|
291
|
+
get(name: string): unknown;
|
|
292
|
+
get(name: string[]): Record<string, unknown>;
|
|
293
|
+
|
|
294
|
+
// Event emitter overloads for type safety
|
|
295
|
+
on(event: 'binlog', listener: (event: AnyBinlogEvent) => void): this;
|
|
296
|
+
on(event: 'ready', listener: () => void): this;
|
|
297
|
+
on(event: 'stopped', listener: () => void): this;
|
|
298
|
+
on(event: 'error', listener: (error: Error) => void): this;
|
|
299
|
+
on(event: string, listener: (...args: unknown[]) => void): this;
|
|
300
|
+
|
|
301
|
+
once(event: 'binlog', listener: (event: AnyBinlogEvent) => void): this;
|
|
302
|
+
once(event: 'ready', listener: () => void): this;
|
|
303
|
+
once(event: 'stopped', listener: () => void): this;
|
|
304
|
+
once(event: 'error', listener: (error: Error) => void): this;
|
|
305
|
+
once(event: string, listener: (...args: unknown[]) => void): this;
|
|
306
|
+
|
|
307
|
+
emit(event: 'binlog', binlogEvent: AnyBinlogEvent): boolean;
|
|
308
|
+
emit(event: 'ready'): boolean;
|
|
309
|
+
emit(event: 'stopped'): boolean;
|
|
310
|
+
emit(event: 'error', error: Error): boolean;
|
|
311
|
+
emit(event: string, ...args: unknown[]): boolean;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
export default ZongJi;
|