@vlasky/zongji 0.5.8 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/.claude/settings.local.json +16 -0
  2. package/.mcp.json +17 -0
  3. package/.tap/processinfo/84de694d-068b-4ac7-b4d8-f835c2122b2d.json +892 -0
  4. package/.tap/processinfo/a1e9627e-66eb-412c-aaa5-079a2eb9f385.json +891 -0
  5. package/.tap/processinfo/abc34c6f-f4aa-4405-8f9a-947048be1df2.json +892 -0
  6. package/.tap/processinfo/affe6c5b-a34d-41b9-bb73-4b14d35138de.json +891 -0
  7. package/.tap/processinfo/bf82449d-cdeb-478b-9506-b939a9506bf2.json +883 -0
  8. package/.tap/processinfo/dd98c508-7067-4342-bdf5-63664b630701.json +892 -0
  9. package/.tap/test-results/test_await_end.js.tap +19 -0
  10. package/.tap/test-results/test_await_end2.js.tap +27 -0
  11. package/.tap/test-results/test_debug_init.js.tap +23 -0
  12. package/.tap/test-results/test_debug_init2.js.tap +35 -0
  13. package/.tap/test-results/test_invalid_host.js.tap +34 -0
  14. package/.tap/test-results/test_minimal.js.tap +26 -0
  15. package/.tap/test-results/test_queryseq.js.tap +14 -0
  16. package/.tap/test-results/test_timing.js.tap +17 -0
  17. package/.tap/test-results/test_unref.js.tap +15 -0
  18. package/CHANGELOG.md +55 -0
  19. package/CLAUDE.md +99 -0
  20. package/GTID.md +54 -0
  21. package/README.md +44 -21
  22. package/TODO.md +43 -0
  23. package/docker-compose.yml +14 -13
  24. package/docker-test.sh +7 -7
  25. package/eslint.config.js +35 -0
  26. package/example.js +1 -1
  27. package/index.d.ts +314 -0
  28. package/index.js +444 -272
  29. package/jsconfig.json +15 -0
  30. package/lib/binlog_event.js +296 -217
  31. package/lib/code_map.js +7 -4
  32. package/lib/common.js +46 -24
  33. package/lib/datetime_decode.js +147 -34
  34. package/lib/json_decode.js +12 -6
  35. package/lib/packet/binlog.js +3 -3
  36. package/lib/packet/combinlog.js +22 -20
  37. package/lib/packet/index.js +50 -50
  38. package/lib/reader.js +215 -109
  39. package/lib/rows_event.js +98 -102
  40. package/lib/sequence/binlog.js +142 -39
  41. package/notes.md +77 -0
  42. package/package.json +17 -11
  43. package/scripts/start-mysql.sh +28 -0
  44. package/workerthreads.md +173 -0
  45. package/.eslintrc +0 -19
package/docker-test.sh CHANGED
@@ -1,11 +1,11 @@
1
1
  #!/bin/bash
2
- MYSQL_HOSTS="mysql55 mysql56 mysql57"
2
+ MYSQL_HOSTS="mysql57 mysql80 mysql84"
3
3
 
4
4
  for hostname in ${MYSQL_HOSTS}; do
5
- echo $hostname + node 8
6
- docker run -it --network=zongji_default -e MYSQL_HOST=$hostname -w /build -v $PWD:/build node:8 npm test
7
- echo $hostname + node 10
8
- docker run -it --network=zongji_default -e MYSQL_HOST=$hostname -w /build -v $PWD:/build node:10 npm test
9
- echo $hostname + node 12
10
- docker run -it --network=zongji_default -e MYSQL_HOST=$hostname -w /build -v $PWD:/build node:12 npm test
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
@@ -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
@@ -1,5 +1,5 @@
1
1
  // Client code
2
- const ZongJi = require('./');
2
+ import ZongJi from './index.js';
3
3
 
4
4
  const zongji = new ZongJi({
5
5
  host : 'localhost',
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;