monsqlize 1.3.1 → 2.0.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 +506 -235
- package/LICENSE +201 -21
- package/README.md +542 -928
- package/changelogs/README.md +163 -0
- package/changelogs/v2.0.0.md +222 -0
- package/changelogs/v2.0.1.md +39 -0
- package/dist/cjs/index.cjs +10788 -0
- package/dist/cjs/mongodb/common/transaction-aware.cjs +10 -0
- package/dist/cjs/transaction/CacheLockManager.cjs +100 -0
- package/dist/cjs/transaction/Transaction.cjs +158 -0
- package/dist/cjs/transaction/TransactionManager.cjs +298 -0
- package/dist/esm/index.mjs +10838 -0
- package/dist/types/base.d.ts +81 -0
- package/dist/types/collection.d.ts +1031 -0
- package/dist/types/expression.d.ts +115 -0
- package/dist/types/index.d.ts +23 -0
- package/dist/types/lock.d.ts +74 -0
- package/dist/types/model.d.ts +530 -0
- package/dist/types/mongodb.d.ts +49 -0
- package/dist/types/monsqlize.d.ts +491 -0
- package/dist/types/pool.d.ts +84 -0
- package/dist/types/runtime.d.ts +362 -0
- package/dist/types/saga.d.ts +143 -0
- package/dist/types/slow-query-log.d.ts +126 -0
- package/dist/types/sync.d.ts +103 -0
- package/dist/types/transaction.d.ts +132 -0
- package/package.json +120 -117
- package/index.d.ts +0 -1289
- package/lib/cache.js +0 -491
- package/lib/common/cursor.js +0 -58
- package/lib/common/docs-urls.js +0 -72
- package/lib/common/index-options.js +0 -222
- package/lib/common/log.js +0 -60
- package/lib/common/namespace.js +0 -21
- package/lib/common/normalize.js +0 -33
- package/lib/common/page-result.js +0 -42
- package/lib/common/runner.js +0 -56
- package/lib/common/server-features.js +0 -231
- package/lib/common/shape-builders.js +0 -26
- package/lib/common/validation.js +0 -112
- package/lib/connect.js +0 -76
- package/lib/constants.js +0 -54
- package/lib/count-queue.js +0 -187
- package/lib/distributed-cache-invalidator.js +0 -259
- package/lib/errors.js +0 -167
- package/lib/index.js +0 -461
- package/lib/infrastructure/ssh-tunnel-ssh2.js +0 -211
- package/lib/infrastructure/ssh-tunnel.js +0 -40
- package/lib/infrastructure/uri-parser.js +0 -35
- package/lib/lock/Lock.js +0 -66
- package/lib/lock/errors.js +0 -27
- package/lib/lock/index.js +0 -12
- package/lib/logger.js +0 -224
- package/lib/model/examples/test.js +0 -114
- package/lib/mongodb/common/accessor-helpers.js +0 -58
- package/lib/mongodb/common/agg-pipeline.js +0 -32
- package/lib/mongodb/common/iid.js +0 -27
- package/lib/mongodb/common/lexicographic-expr.js +0 -52
- package/lib/mongodb/common/shape.js +0 -31
- package/lib/mongodb/common/sort.js +0 -38
- package/lib/mongodb/common/transaction-aware.js +0 -24
- package/lib/mongodb/connect.js +0 -233
- package/lib/mongodb/index.js +0 -591
- package/lib/mongodb/management/admin-ops.js +0 -199
- package/lib/mongodb/management/bookmark-ops.js +0 -166
- package/lib/mongodb/management/cache-ops.js +0 -49
- package/lib/mongodb/management/collection-ops.js +0 -386
- package/lib/mongodb/management/database-ops.js +0 -201
- package/lib/mongodb/management/index-ops.js +0 -474
- package/lib/mongodb/management/index.js +0 -16
- package/lib/mongodb/management/namespace.js +0 -30
- package/lib/mongodb/management/validation-ops.js +0 -267
- package/lib/mongodb/queries/aggregate.js +0 -142
- package/lib/mongodb/queries/chain.js +0 -630
- package/lib/mongodb/queries/count.js +0 -98
- package/lib/mongodb/queries/distinct.js +0 -77
- package/lib/mongodb/queries/find-and-count.js +0 -192
- package/lib/mongodb/queries/find-by-ids.js +0 -235
- package/lib/mongodb/queries/find-one-by-id.js +0 -170
- package/lib/mongodb/queries/find-one.js +0 -70
- package/lib/mongodb/queries/find-page.js +0 -577
- package/lib/mongodb/queries/find.js +0 -170
- package/lib/mongodb/queries/index.js +0 -50
- package/lib/mongodb/queries/watch.js +0 -537
- package/lib/mongodb/writes/delete-many.js +0 -190
- package/lib/mongodb/writes/delete-one.js +0 -182
- package/lib/mongodb/writes/find-one-and-delete.js +0 -202
- package/lib/mongodb/writes/find-one-and-replace.js +0 -238
- package/lib/mongodb/writes/find-one-and-update.js +0 -239
- package/lib/mongodb/writes/increment-one.js +0 -252
- package/lib/mongodb/writes/index.js +0 -41
- package/lib/mongodb/writes/insert-batch.js +0 -507
- package/lib/mongodb/writes/insert-many.js +0 -227
- package/lib/mongodb/writes/insert-one.js +0 -180
- package/lib/mongodb/writes/replace-one.js +0 -215
- package/lib/mongodb/writes/result-handler.js +0 -236
- package/lib/mongodb/writes/update-many.js +0 -221
- package/lib/mongodb/writes/update-one.js +0 -223
- package/lib/mongodb/writes/upsert-one.js +0 -206
- package/lib/multi-level-cache.js +0 -189
- package/lib/operators.js +0 -330
- package/lib/redis-cache-adapter.js +0 -237
- package/lib/slow-query-log/base-storage.js +0 -69
- package/lib/slow-query-log/batch-queue.js +0 -96
- package/lib/slow-query-log/config-manager.js +0 -195
- package/lib/slow-query-log/index.js +0 -237
- package/lib/slow-query-log/mongodb-storage.js +0 -323
- package/lib/slow-query-log/query-hash.js +0 -38
- package/lib/transaction/CacheLockManager.js +0 -161
- package/lib/transaction/DistributedCacheLockManager.js +0 -474
- package/lib/transaction/Transaction.js +0 -314
- package/lib/transaction/TransactionManager.js +0 -266
- package/lib/transaction/index.js +0 -10
- package/lib/utils/objectid-converter.js +0 -566
|
@@ -1,211 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* SSH隧道管理器 - ssh2实现
|
|
3
|
-
* 支持密码认证和私钥认证
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
const { Client } = require('ssh2');
|
|
7
|
-
const net = require('net');
|
|
8
|
-
const fs = require('fs');
|
|
9
|
-
const path = require('path');
|
|
10
|
-
const os = require('os');
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* 基于ssh2的SSH隧道管理器
|
|
14
|
-
* 支持密码认证和私钥认证
|
|
15
|
-
*/
|
|
16
|
-
class SSHTunnelSSH2 {
|
|
17
|
-
/**
|
|
18
|
-
* @param {Object} sshConfig - SSH配置
|
|
19
|
-
* @param {string} sshConfig.host - SSH服务器地址
|
|
20
|
-
* @param {number} [sshConfig.port=22] - SSH端口
|
|
21
|
-
* @param {string} sshConfig.username - SSH用户名
|
|
22
|
-
* @param {string} [sshConfig.password] - SSH密码
|
|
23
|
-
* @param {string} [sshConfig.privateKey] - 私钥内容
|
|
24
|
-
* @param {string} [sshConfig.privateKeyPath] - 私钥路径
|
|
25
|
-
* @param {string} [sshConfig.passphrase] - 私钥密码
|
|
26
|
-
* @param {number} [sshConfig.localPort] - 本地监听端口(可选,默认随机)
|
|
27
|
-
* @param {number} [sshConfig.readyTimeout=20000] - 连接超时(毫秒)
|
|
28
|
-
* @param {number} [sshConfig.keepaliveInterval=30000] - 心跳间隔(毫秒)
|
|
29
|
-
* @param {string} remoteHost - 远程主机(数据库服务器地址)
|
|
30
|
-
* @param {number} remotePort - 远程端口(数据库端口)
|
|
31
|
-
* @param {Object} options - 可选配置
|
|
32
|
-
* @param {Object} options.logger - 日志记录器
|
|
33
|
-
* @param {string} options.name - 隧道名称(用于日志)
|
|
34
|
-
*/
|
|
35
|
-
constructor(sshConfig, remoteHost, remotePort, options = {}) {
|
|
36
|
-
this.sshConfig = sshConfig;
|
|
37
|
-
this.remoteHost = remoteHost;
|
|
38
|
-
this.remotePort = remotePort;
|
|
39
|
-
this.logger = options.logger;
|
|
40
|
-
this.name = options.name || `${remoteHost}:${remotePort}`;
|
|
41
|
-
|
|
42
|
-
this.sshClient = null;
|
|
43
|
-
this.server = null;
|
|
44
|
-
this.localPort = null;
|
|
45
|
-
this.isConnected = false;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* 建立SSH隧道
|
|
50
|
-
* @returns {Promise<number>} 本地监听端口
|
|
51
|
-
*/
|
|
52
|
-
async connect() {
|
|
53
|
-
if (this.isConnected) {
|
|
54
|
-
this.logger?.warn?.(`SSH tunnel [${this.name}] already connected`);
|
|
55
|
-
return this.localPort;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
return new Promise((resolve, reject) => {
|
|
59
|
-
this.sshClient = new Client();
|
|
60
|
-
|
|
61
|
-
this.sshClient.on('ready', () => {
|
|
62
|
-
this.logger?.info?.(`✅ SSH connection established [${this.name}]`);
|
|
63
|
-
|
|
64
|
-
// 创建本地TCP服务器(端口转发)
|
|
65
|
-
this.server = net.createServer((sock) => {
|
|
66
|
-
this.sshClient.forwardOut(
|
|
67
|
-
sock.remoteAddress,
|
|
68
|
-
sock.remotePort,
|
|
69
|
-
this.remoteHost,
|
|
70
|
-
this.remotePort,
|
|
71
|
-
(err, stream) => {
|
|
72
|
-
if (err) {
|
|
73
|
-
this.logger?.error?.(`SSH forward error [${this.name}]`, err);
|
|
74
|
-
return sock.end();
|
|
75
|
-
}
|
|
76
|
-
sock.pipe(stream).pipe(sock);
|
|
77
|
-
}
|
|
78
|
-
);
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
// 监听本地端口(0 = 随机端口)
|
|
82
|
-
const port = this.sshConfig.localPort || 0;
|
|
83
|
-
this.server.listen(port, 'localhost', () => {
|
|
84
|
-
this.localPort = this.server.address().port;
|
|
85
|
-
this.isConnected = true;
|
|
86
|
-
|
|
87
|
-
this.logger?.info?.(`✅ SSH tunnel ready [${this.name}]`, {
|
|
88
|
-
localPort: this.localPort,
|
|
89
|
-
remote: `${this.remoteHost}:${this.remotePort}`
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
resolve(this.localPort);
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
this.server.on('error', (err) => {
|
|
96
|
-
this.logger?.error?.(`Local server error [${this.name}]`, err);
|
|
97
|
-
reject(err);
|
|
98
|
-
});
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
this.sshClient.on('error', (err) => {
|
|
102
|
-
this.logger?.error?.(`SSH connection error [${this.name}]`, err);
|
|
103
|
-
reject(err);
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
this.sshClient.on('end', () => {
|
|
107
|
-
this.logger?.info?.(`SSH connection ended [${this.name}]`);
|
|
108
|
-
this.isConnected = false;
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
// 构建认证配置并连接
|
|
112
|
-
try {
|
|
113
|
-
const authConfig = this._buildAuthConfig();
|
|
114
|
-
this.sshClient.connect(authConfig);
|
|
115
|
-
} catch (err) {
|
|
116
|
-
reject(err);
|
|
117
|
-
}
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
/**
|
|
122
|
-
* 关闭SSH隧道
|
|
123
|
-
*/
|
|
124
|
-
async close() {
|
|
125
|
-
if (this.server) {
|
|
126
|
-
this.server.close();
|
|
127
|
-
this.server = null;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
if (this.sshClient) {
|
|
131
|
-
this.sshClient.end();
|
|
132
|
-
this.sshClient = null;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
this.isConnected = false;
|
|
136
|
-
this.localPort = null;
|
|
137
|
-
|
|
138
|
-
this.logger?.info?.(`✅ SSH tunnel closed [${this.name}]`);
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
/**
|
|
142
|
-
* 获取隧道连接URI
|
|
143
|
-
* @param {string} protocol - 数据库协议(mongodb/postgresql/mysql/redis)
|
|
144
|
-
* @param {string} originalUri - 原始URI
|
|
145
|
-
* @returns {string} 替换后的本地URI
|
|
146
|
-
*/
|
|
147
|
-
getTunnelUri(protocol, originalUri) {
|
|
148
|
-
if (!this.isConnected) {
|
|
149
|
-
throw new Error(`SSH tunnel [${this.name}] not connected`);
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
// 替换主机:端口为 localhost:本地端口
|
|
153
|
-
const pattern = new RegExp(`${protocol}://([^@]*@)?([^:/]+):(\\d+)`);
|
|
154
|
-
const replacement = `${protocol}://$1localhost:${this.localPort}`;
|
|
155
|
-
|
|
156
|
-
return originalUri.replace(pattern, replacement);
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
/**
|
|
160
|
-
* 获取本地连接地址
|
|
161
|
-
* @returns {string} localhost:端口
|
|
162
|
-
*/
|
|
163
|
-
getLocalAddress() {
|
|
164
|
-
if (!this.isConnected) {
|
|
165
|
-
throw new Error(`SSH tunnel [${this.name}] not connected`);
|
|
166
|
-
}
|
|
167
|
-
return `localhost:${this.localPort}`;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
/**
|
|
171
|
-
* 构建SSH认证配置
|
|
172
|
-
* @private
|
|
173
|
-
*/
|
|
174
|
-
_buildAuthConfig() {
|
|
175
|
-
const { host, port, username, password, privateKey, privateKeyPath, passphrase } = this.sshConfig;
|
|
176
|
-
|
|
177
|
-
if (!host || !username) {
|
|
178
|
-
throw new Error('SSH config requires: host, username');
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
const config = {
|
|
182
|
-
host,
|
|
183
|
-
port: port || 22,
|
|
184
|
-
username,
|
|
185
|
-
readyTimeout: this.sshConfig.readyTimeout || 20000,
|
|
186
|
-
keepaliveInterval: this.sshConfig.keepaliveInterval || 30000,
|
|
187
|
-
};
|
|
188
|
-
|
|
189
|
-
// 优先使用私钥认证
|
|
190
|
-
if (privateKey) {
|
|
191
|
-
config.privateKey = privateKey;
|
|
192
|
-
if (passphrase) config.passphrase = passphrase;
|
|
193
|
-
} else if (privateKeyPath) {
|
|
194
|
-
const resolvedPath = privateKeyPath.startsWith('~')
|
|
195
|
-
? path.join(os.homedir(), privateKeyPath.slice(1))
|
|
196
|
-
: privateKeyPath;
|
|
197
|
-
config.privateKey = fs.readFileSync(resolvedPath);
|
|
198
|
-
if (passphrase) config.passphrase = passphrase;
|
|
199
|
-
} else if (password) {
|
|
200
|
-
// 密码认证
|
|
201
|
-
config.password = password;
|
|
202
|
-
} else {
|
|
203
|
-
throw new Error('SSH authentication required: privateKey, privateKeyPath, or password');
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
return config;
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
module.exports = { SSHTunnelSSH2 };
|
|
211
|
-
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* SSH隧道管理器 - 统一入口
|
|
3
|
-
* 使用ssh2库实现,支持密码认证和私钥认证
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
const { SSHTunnelSSH2 } = require('./ssh-tunnel-ssh2');
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* SSH隧道管理器
|
|
10
|
-
* 直接使用ssh2实现
|
|
11
|
-
*/
|
|
12
|
-
class SSHTunnelManager {
|
|
13
|
-
/**
|
|
14
|
-
* 创建SSH隧道实例
|
|
15
|
-
* @param {Object} sshConfig - SSH配置
|
|
16
|
-
* @param {string} remoteHost - 远程主机
|
|
17
|
-
* @param {number} remotePort - 远程端口
|
|
18
|
-
* @param {Object} options - 可选配置
|
|
19
|
-
* @returns {Object} SSH隧道实例
|
|
20
|
-
*/
|
|
21
|
-
static create(sshConfig, remoteHost, remotePort, options = {}) {
|
|
22
|
-
return new SSHTunnelSSH2(sshConfig, remoteHost, remotePort, options);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* 获取当前实现信息
|
|
27
|
-
* @returns {Object}
|
|
28
|
-
*/
|
|
29
|
-
static getInfo() {
|
|
30
|
-
return {
|
|
31
|
-
implementation: 'ssh2',
|
|
32
|
-
supportsPassword: true,
|
|
33
|
-
supportsPrivateKey: true,
|
|
34
|
-
dependencies: ['ssh2']
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
module.exports = { SSHTunnelManager };
|
|
40
|
-
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 通用URI解析器
|
|
3
|
-
* 支持:mongodb://、postgresql://、mysql://、redis://
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* 解析数据库连接URI
|
|
8
|
-
* @param {string} uri - 数据库连接URI
|
|
9
|
-
* @returns {{protocol: string, auth: string|null, host: string, port: number}} 解析结果
|
|
10
|
-
*/
|
|
11
|
-
function parseUri(uri) {
|
|
12
|
-
const patterns = {
|
|
13
|
-
mongodb: /mongodb:\/\/([^@]*@)?([^:/]+):(\d+)/,
|
|
14
|
-
postgresql: /postgresql:\/\/([^@]*@)?([^:/]+):(\d+)/,
|
|
15
|
-
mysql: /mysql:\/\/([^@]*@)?([^:/]+):(\d+)/,
|
|
16
|
-
redis: /redis:\/\/([^@]*@)?([^:/]+):(\d+)/
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
for (const [protocol, pattern] of Object.entries(patterns)) {
|
|
20
|
-
const match = uri.match(pattern);
|
|
21
|
-
if (match) {
|
|
22
|
-
return {
|
|
23
|
-
protocol,
|
|
24
|
-
auth: match[1] ? match[1].slice(0, -1) : null, // 去掉末尾的@
|
|
25
|
-
host: match[2],
|
|
26
|
-
port: parseInt(match[3], 10)
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
throw new Error(`Unsupported URI format: ${uri}`);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
module.exports = { parseUri };
|
|
35
|
-
|
package/lib/lock/Lock.js
DELETED
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 业务锁对象
|
|
3
|
-
* 表示一个已获取的锁,提供释放和续期方法
|
|
4
|
-
*/
|
|
5
|
-
class Lock {
|
|
6
|
-
/**
|
|
7
|
-
* @param {string} key - 锁的标识
|
|
8
|
-
* @param {string} lockId - 锁的唯一ID
|
|
9
|
-
* @param {Object} manager - 锁管理器实例
|
|
10
|
-
* @param {number} ttl - 锁的过期时间(毫秒)
|
|
11
|
-
*/
|
|
12
|
-
constructor(key, lockId, manager, ttl) {
|
|
13
|
-
this.key = key;
|
|
14
|
-
this.lockId = lockId;
|
|
15
|
-
this.manager = manager;
|
|
16
|
-
this.ttl = ttl;
|
|
17
|
-
this.released = false;
|
|
18
|
-
this.acquiredAt = Date.now();
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* 释放锁
|
|
23
|
-
* @returns {Promise<boolean>}
|
|
24
|
-
*/
|
|
25
|
-
async release() {
|
|
26
|
-
if (this.released) {
|
|
27
|
-
return false;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
const result = await this.manager.releaseLock(this.key, this.lockId);
|
|
31
|
-
this.released = true;
|
|
32
|
-
return result;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* 续期(延长锁的过期时间)
|
|
37
|
-
* @param {number} [ttl] - 新的过期时间,默认使用原TTL
|
|
38
|
-
* @returns {Promise<boolean>}
|
|
39
|
-
*/
|
|
40
|
-
async renew(ttl) {
|
|
41
|
-
if (this.released) {
|
|
42
|
-
return false;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
return this.manager.renewLock(this.key, this.lockId, ttl || this.ttl);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* 检查锁是否仍被持有
|
|
50
|
-
* @returns {boolean}
|
|
51
|
-
*/
|
|
52
|
-
isHeld() {
|
|
53
|
-
return !this.released;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* 获取锁持有时间
|
|
58
|
-
* @returns {number} 毫秒
|
|
59
|
-
*/
|
|
60
|
-
getHoldTime() {
|
|
61
|
-
return Date.now() - this.acquiredAt;
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
module.exports = Lock;
|
|
66
|
-
|
package/lib/lock/errors.js
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 锁获取失败错误
|
|
3
|
-
*/
|
|
4
|
-
class LockAcquireError extends Error {
|
|
5
|
-
constructor(message) {
|
|
6
|
-
super(message);
|
|
7
|
-
this.name = 'LockAcquireError';
|
|
8
|
-
this.code = 'LOCK_ACQUIRE_FAILED';
|
|
9
|
-
}
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* 锁超时错误
|
|
14
|
-
*/
|
|
15
|
-
class LockTimeoutError extends Error {
|
|
16
|
-
constructor(message) {
|
|
17
|
-
super(message);
|
|
18
|
-
this.name = 'LockTimeoutError';
|
|
19
|
-
this.code = 'LOCK_TIMEOUT';
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
module.exports = {
|
|
24
|
-
LockAcquireError,
|
|
25
|
-
LockTimeoutError
|
|
26
|
-
};
|
|
27
|
-
|
package/lib/lock/index.js
DELETED
package/lib/logger.js
DELETED
|
@@ -1,224 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 默认日志记录器工具类
|
|
3
|
-
* 提供标准的日志记录功能,支持不同级别的日志输出
|
|
4
|
-
*
|
|
5
|
-
* v2.0 新增功能:
|
|
6
|
-
* - traceId 支持(用于分布式追踪)
|
|
7
|
-
* - 结构化日志输出(JSON 格式)
|
|
8
|
-
* - 上下文信息(数据库、集合、操作等)
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
const crypto = require('crypto');
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* 生成唯一的 traceId
|
|
15
|
-
* @returns {string} 16 字符的唯一 ID
|
|
16
|
-
*/
|
|
17
|
-
function generateTraceId() {
|
|
18
|
-
return crypto.randomBytes(8).toString('hex');
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* 异步本地存储(用于在异步调用链中传递 traceId)
|
|
23
|
-
*/
|
|
24
|
-
let AsyncLocalStorage;
|
|
25
|
-
try {
|
|
26
|
-
AsyncLocalStorage = require('async_hooks').AsyncLocalStorage;
|
|
27
|
-
} catch (e) {
|
|
28
|
-
// Node.js < 12.17.0 不支持 AsyncLocalStorage
|
|
29
|
-
AsyncLocalStorage = null;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const traceStorage = AsyncLocalStorage ? new AsyncLocalStorage() : null;
|
|
33
|
-
|
|
34
|
-
module.exports = class Logger {
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* 创建日志记录器实例
|
|
38
|
-
* @param {Object} [customLogger] - 自定义日志记录器
|
|
39
|
-
* @param {Function} customLogger.debug - debug级别日志方法
|
|
40
|
-
* @param {Function} customLogger.info - info级别日志方法
|
|
41
|
-
* @param {Function} customLogger.warn - warn级别日志方法
|
|
42
|
-
* @param {Function} customLogger.error - error级别日志方法
|
|
43
|
-
* @param {Object} [options] - 日志选项
|
|
44
|
-
* @param {boolean} [options.structured=false] - 是否使用结构化日志(JSON)
|
|
45
|
-
* @param {boolean} [options.enableTraceId=false] - 是否启用 traceId
|
|
46
|
-
* @returns {Object} 日志记录器对象
|
|
47
|
-
*/
|
|
48
|
-
static create(customLogger, options = {}) {
|
|
49
|
-
if (customLogger && this.isValidLogger(customLogger)) {
|
|
50
|
-
// 如果提供自定义 logger,包装它以支持新特性
|
|
51
|
-
return this.wrapLogger(customLogger, options);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
return this.createDefaultLogger(options);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* 验证自定义日志记录器是否有效
|
|
59
|
-
* @param {Object} logger - 待验证的日志记录器
|
|
60
|
-
* @returns {boolean} 是否为有效的日志记录器
|
|
61
|
-
*/
|
|
62
|
-
static isValidLogger(logger) {
|
|
63
|
-
const requiredMethods = ['debug', 'info', 'warn', 'error'];
|
|
64
|
-
return requiredMethods.every(method =>
|
|
65
|
-
typeof logger[method] === 'function'
|
|
66
|
-
);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* 包装自定义 logger 以支持新特性
|
|
71
|
-
* @param {Object} baseLogger - 基础 logger
|
|
72
|
-
* @param {Object} options - 选项
|
|
73
|
-
* @returns {Object} 包装后的 logger
|
|
74
|
-
*/
|
|
75
|
-
static wrapLogger(baseLogger, options = {}) {
|
|
76
|
-
const { structured = false, enableTraceId = false } = options;
|
|
77
|
-
|
|
78
|
-
const wrap = (level) => (msg, ...args) => {
|
|
79
|
-
const logData = this._prepareLogData(level, msg, args, { structured, enableTraceId });
|
|
80
|
-
|
|
81
|
-
if (structured) {
|
|
82
|
-
baseLogger[level](JSON.stringify(logData));
|
|
83
|
-
} else {
|
|
84
|
-
const prefix = enableTraceId && logData.traceId ? `[${logData.traceId}] ` : '';
|
|
85
|
-
baseLogger[level](`${prefix}${msg}`, ...args);
|
|
86
|
-
}
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
return {
|
|
90
|
-
debug: wrap('debug'),
|
|
91
|
-
info: wrap('info'),
|
|
92
|
-
warn: wrap('warn'),
|
|
93
|
-
error: wrap('error'),
|
|
94
|
-
// 暴露 traceId 管理方法
|
|
95
|
-
withTraceId: enableTraceId ? this.withTraceId : undefined,
|
|
96
|
-
getTraceId: enableTraceId ? this.getTraceId : undefined,
|
|
97
|
-
};
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* 准备日志数据
|
|
102
|
-
* @private
|
|
103
|
-
*/
|
|
104
|
-
static _prepareLogData(level, msg, args, options) {
|
|
105
|
-
const logData = {
|
|
106
|
-
timestamp: new Date().toISOString(),
|
|
107
|
-
level: level.toUpperCase(),
|
|
108
|
-
message: msg,
|
|
109
|
-
};
|
|
110
|
-
|
|
111
|
-
// 添加 traceId
|
|
112
|
-
if (options.enableTraceId) {
|
|
113
|
-
const traceId = this.getTraceId();
|
|
114
|
-
if (traceId) logData.traceId = traceId;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
// 处理额外参数(上下文信息)
|
|
118
|
-
if (args.length > 0) {
|
|
119
|
-
const context = args[0];
|
|
120
|
-
if (context && typeof context === 'object') {
|
|
121
|
-
logData.context = context;
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
return logData;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
/**
|
|
129
|
-
* 创建默认的控制台日志记录器
|
|
130
|
-
* @param {Object} [options] - 日志选项
|
|
131
|
-
* @returns {Object} 默认日志记录器对象
|
|
132
|
-
*/
|
|
133
|
-
static createDefaultLogger(options = {}) {
|
|
134
|
-
const { structured = false, enableTraceId = false } = options;
|
|
135
|
-
|
|
136
|
-
const createLogFn = (level, consoleFn) => {
|
|
137
|
-
return (msg, ...args) => {
|
|
138
|
-
const logData = this._prepareLogData(level, msg, args, { structured, enableTraceId });
|
|
139
|
-
|
|
140
|
-
if (structured) {
|
|
141
|
-
consoleFn(JSON.stringify(logData));
|
|
142
|
-
} else {
|
|
143
|
-
const prefix = enableTraceId && logData.traceId ? `[${logData.traceId}] ` : '';
|
|
144
|
-
consoleFn(`[${level.toUpperCase()}] ${prefix}${msg}`, ...args);
|
|
145
|
-
}
|
|
146
|
-
};
|
|
147
|
-
};
|
|
148
|
-
|
|
149
|
-
return {
|
|
150
|
-
debug: createLogFn('debug', console.debug),
|
|
151
|
-
info: createLogFn('info', console.log),
|
|
152
|
-
warn: createLogFn('warn', console.warn),
|
|
153
|
-
error: createLogFn('error', console.error),
|
|
154
|
-
// 暴露 traceId 管理方法
|
|
155
|
-
withTraceId: enableTraceId ? this.withTraceId.bind(this) : undefined,
|
|
156
|
-
getTraceId: enableTraceId ? this.getTraceId.bind(this) : undefined,
|
|
157
|
-
};
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
/**
|
|
161
|
-
* 创建带时间戳的日志记录器
|
|
162
|
-
* @param {Object} [customLogger] - 自定义日志记录器
|
|
163
|
-
* @returns {Object} 带时间戳的日志记录器
|
|
164
|
-
*/
|
|
165
|
-
static createWithTimestamp(customLogger) {
|
|
166
|
-
const baseLogger = this.create(customLogger);
|
|
167
|
-
const getTimestamp = () => new Date().toISOString();
|
|
168
|
-
|
|
169
|
-
return {
|
|
170
|
-
debug: (msg, ...args) => baseLogger.debug(`${getTimestamp()} ${msg}`, ...args),
|
|
171
|
-
info: (msg, ...args) => baseLogger.info(`${getTimestamp()} ${msg}`, ...args),
|
|
172
|
-
warn: (msg, ...args) => baseLogger.warn(`${getTimestamp()} ${msg}`, ...args),
|
|
173
|
-
error: (msg, ...args) => baseLogger.error(`${getTimestamp()} ${msg}`, ...args)
|
|
174
|
-
};
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
/**
|
|
178
|
-
* 创建静默日志记录器(不输出任何内容)
|
|
179
|
-
* @returns {Object} 静默日志记录器
|
|
180
|
-
*/
|
|
181
|
-
static createSilent() {
|
|
182
|
-
const noop = () => {};
|
|
183
|
-
return {
|
|
184
|
-
debug: noop,
|
|
185
|
-
info: noop,
|
|
186
|
-
warn: noop,
|
|
187
|
-
error: noop
|
|
188
|
-
};
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
/**
|
|
192
|
-
* 在指定的 traceId 上下文中运行函数
|
|
193
|
-
* @param {Function} fn - 要执行的函数
|
|
194
|
-
* @param {string} [traceId] - 可选的 traceId,不提供则自动生成
|
|
195
|
-
* @returns {*} 函数执行结果
|
|
196
|
-
*/
|
|
197
|
-
static withTraceId(fn, traceId = null) {
|
|
198
|
-
if (!traceStorage) {
|
|
199
|
-
// 不支持 AsyncLocalStorage,直接执行
|
|
200
|
-
return fn();
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
const id = traceId || generateTraceId();
|
|
204
|
-
return traceStorage.run(id, fn);
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
/**
|
|
208
|
-
* 获取当前上下文的 traceId
|
|
209
|
-
* @returns {string|null} traceId 或 null
|
|
210
|
-
*/
|
|
211
|
-
static getTraceId() {
|
|
212
|
-
if (!traceStorage) return null;
|
|
213
|
-
return traceStorage.getStore() || null;
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
/**
|
|
217
|
-
* 生成新的 traceId
|
|
218
|
-
* @returns {string} 新的 traceId
|
|
219
|
-
*/
|
|
220
|
-
static generateTraceId() {
|
|
221
|
-
return generateTraceId();
|
|
222
|
-
}
|
|
223
|
-
};
|
|
224
|
-
|