@heyhru/app-dms-server 0.7.0 → 0.9.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.
- package/dist/index.js +55 -27
- package/package.json +7 -6
package/dist/index.js
CHANGED
|
@@ -1,3 +1,33 @@
|
|
|
1
|
+
// src/otel.ts
|
|
2
|
+
import { initOtel } from "@heyhru/server-plugin-otel";
|
|
3
|
+
|
|
4
|
+
// src/config.ts
|
|
5
|
+
if (!process.env.DATABASE_URL) {
|
|
6
|
+
throw new Error("DATABASE_URL environment variable is required");
|
|
7
|
+
}
|
|
8
|
+
var config = {
|
|
9
|
+
port: Number(process.env.PORT) || 3001,
|
|
10
|
+
jwtSecret: process.env.JWT_SECRET || "dev-secret-change-in-production",
|
|
11
|
+
jwtExpiresIn: "24h",
|
|
12
|
+
encryptionKey: process.env.ENCRYPTION_KEY || "dev-encryption-key-32-bytes-long!",
|
|
13
|
+
dbUrl: process.env.DATABASE_URL,
|
|
14
|
+
dbSsl: process.env.DATABASE_SSL === "true",
|
|
15
|
+
dbPoolMin: Number(process.env.DATABASE_POOL_MIN) || 2,
|
|
16
|
+
dbPoolMax: Number(process.env.DATABASE_POOL_MAX) || 10,
|
|
17
|
+
dbIdleTimeoutMs: Number(process.env.DATABASE_IDLE_TIMEOUT) || 1e4,
|
|
18
|
+
nodeEnv: process.env.NODE_ENV || "development",
|
|
19
|
+
logDir: process.env.LOG_DIR || "",
|
|
20
|
+
otelEndpoint: process.env.OTEL_EXPORTER_OTLP_ENDPOINT || "http://localhost:4317",
|
|
21
|
+
otelEnabled: process.env.OTEL_ENABLED === "true"
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
// src/otel.ts
|
|
25
|
+
initOtel({
|
|
26
|
+
serviceName: "app-dms-server",
|
|
27
|
+
endpoint: config.otelEndpoint,
|
|
28
|
+
enabled: config.otelEnabled
|
|
29
|
+
});
|
|
30
|
+
|
|
1
31
|
// src/index.ts
|
|
2
32
|
import { createPgDb } from "@heyhru/server-plugin-pg";
|
|
3
33
|
|
|
@@ -43,26 +73,6 @@ function refreshPoolMetrics() {
|
|
|
43
73
|
|
|
44
74
|
// src/auth/auth.middleware.ts
|
|
45
75
|
import { verifyToken as jwtVerify } from "@heyhru/server-plugin-jwt";
|
|
46
|
-
|
|
47
|
-
// src/config.ts
|
|
48
|
-
if (!process.env.DATABASE_URL) {
|
|
49
|
-
throw new Error("DATABASE_URL environment variable is required");
|
|
50
|
-
}
|
|
51
|
-
var config = {
|
|
52
|
-
port: Number(process.env.PORT) || 3001,
|
|
53
|
-
jwtSecret: process.env.JWT_SECRET || "dev-secret-change-in-production",
|
|
54
|
-
jwtExpiresIn: "24h",
|
|
55
|
-
encryptionKey: process.env.ENCRYPTION_KEY || "dev-encryption-key-32-bytes-long!",
|
|
56
|
-
dbUrl: process.env.DATABASE_URL,
|
|
57
|
-
dbSsl: process.env.DATABASE_SSL === "true",
|
|
58
|
-
dbPoolMin: Number(process.env.DATABASE_POOL_MIN) || 2,
|
|
59
|
-
dbPoolMax: Number(process.env.DATABASE_POOL_MAX) || 10,
|
|
60
|
-
dbIdleTimeoutMs: Number(process.env.DATABASE_IDLE_TIMEOUT) || 1e4,
|
|
61
|
-
nodeEnv: process.env.NODE_ENV || "development",
|
|
62
|
-
logDir: process.env.LOG_DIR || ""
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
// src/auth/auth.middleware.ts
|
|
66
76
|
function verifyToken(token) {
|
|
67
77
|
return jwtVerify(token, config.jwtSecret);
|
|
68
78
|
}
|
|
@@ -252,20 +262,28 @@ function postSqlParse(req, reply) {
|
|
|
252
262
|
return reply.send({ category: sqlParse(sql) });
|
|
253
263
|
}
|
|
254
264
|
async function postSqlExecute(req, reply) {
|
|
255
|
-
const
|
|
265
|
+
const body = req.body ?? {};
|
|
266
|
+
const { dataSourceId, database, sql } = body;
|
|
256
267
|
if (!dataSourceId || !sql) {
|
|
257
268
|
return reply.code(400).send({ error: "\u6570\u636E\u6E90 ID \u548C SQL \u4E0D\u80FD\u4E3A\u7A7A" });
|
|
258
269
|
}
|
|
270
|
+
const page = typeof body.page === "number" ? body.page : 1;
|
|
271
|
+
const pageSize = typeof body.pageSize === "number" ? body.pageSize : 50;
|
|
259
272
|
const ip = req.headers["x-forwarded-for"] ?? req.headers["x-real-ip"] ?? "unknown";
|
|
260
273
|
try {
|
|
261
|
-
const
|
|
262
|
-
return reply.send(
|
|
274
|
+
const result = await sqlExecute({ dataSourceId, database, sql, userId: req.user.id, ip, page, pageSize });
|
|
275
|
+
return reply.send(result);
|
|
263
276
|
} catch (err) {
|
|
264
277
|
req.log.error(err, "SQL execute failed (user=%s, ds=%s)", req.user.id, dataSourceId);
|
|
265
278
|
return reply.code(400).send({ error: err instanceof Error ? err.message : String(err) });
|
|
266
279
|
}
|
|
267
280
|
}
|
|
268
|
-
async function
|
|
281
|
+
async function fetchCountQuery(pool, sql) {
|
|
282
|
+
const countSql = `SELECT COUNT(*) AS total FROM (${sql}) AS _count_t`;
|
|
283
|
+
const rows = await pool.execute(countSql);
|
|
284
|
+
return Number(rows[0]?.total ?? 0);
|
|
285
|
+
}
|
|
286
|
+
async function sqlExecute({ dataSourceId, database, sql, userId, ip, page, pageSize }) {
|
|
269
287
|
const category = sqlParse(sql);
|
|
270
288
|
if (category !== "select") {
|
|
271
289
|
throw new Error("\u4EC5\u5141\u8BB8\u76F4\u63A5\u6267\u884C SELECT \u8BED\u53E5");
|
|
@@ -275,10 +293,20 @@ async function sqlExecute({ dataSourceId, database, sql, userId, ip }) {
|
|
|
275
293
|
return ds ? getPool(ds) : null;
|
|
276
294
|
})();
|
|
277
295
|
if (!pool) throw new Error("\u6570\u636E\u6E90\u672A\u627E\u5230");
|
|
296
|
+
const hasLimit = /\bLIMIT\b/i.test(sql);
|
|
297
|
+
const dataSql = hasLimit ? sql : `${sql} LIMIT ${pageSize} OFFSET ${(page - 1) * pageSize}`;
|
|
278
298
|
const end = sqlDuration.startTimer({ data_source_id: dataSourceId, sql_type: category });
|
|
279
299
|
let rows;
|
|
300
|
+
let total;
|
|
280
301
|
try {
|
|
281
|
-
|
|
302
|
+
if (hasLimit) {
|
|
303
|
+
rows = await pool.execute(dataSql);
|
|
304
|
+
total = rows.length;
|
|
305
|
+
} else {
|
|
306
|
+
const [rawRows, count] = await Promise.all([pool.execute(dataSql), fetchCountQuery(pool, sql)]);
|
|
307
|
+
rows = rawRows;
|
|
308
|
+
total = count;
|
|
309
|
+
}
|
|
282
310
|
end({ status: "success" });
|
|
283
311
|
} catch (err) {
|
|
284
312
|
end({ status: "failed" });
|
|
@@ -289,10 +317,10 @@ async function sqlExecute({ dataSourceId, database, sql, userId, ip }) {
|
|
|
289
317
|
dataSourceId,
|
|
290
318
|
action: "SELECT",
|
|
291
319
|
sqlText: sql,
|
|
292
|
-
resultSummary: `${
|
|
320
|
+
resultSummary: `${total} total rows`,
|
|
293
321
|
ipAddress: ip
|
|
294
322
|
});
|
|
295
|
-
return rows;
|
|
323
|
+
return { rows, total, page, pageSize };
|
|
296
324
|
}
|
|
297
325
|
async function postSqlDatabases(req, reply) {
|
|
298
326
|
const { dataSourceId } = req.body ?? {};
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "0.
|
|
6
|
+
"version": "0.9.0",
|
|
7
7
|
"description": "DMS backend API server built on Fastify",
|
|
8
8
|
"type": "module",
|
|
9
9
|
"main": "./dist/index.mjs",
|
|
@@ -19,15 +19,16 @@
|
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|
|
21
21
|
"@fastify/cors": "^11.2.0",
|
|
22
|
-
"@heyhru/business-dms-approval": "0.6.
|
|
22
|
+
"@heyhru/business-dms-approval": "0.6.3",
|
|
23
23
|
"@heyhru/business-dms-audit": "0.6.1",
|
|
24
|
-
"@heyhru/business-dms-datasource": "0.7.
|
|
24
|
+
"@heyhru/business-dms-datasource": "0.7.2",
|
|
25
25
|
"@heyhru/business-dms-saved-sql": "0.6.1",
|
|
26
26
|
"@heyhru/business-dms-user": "0.6.1",
|
|
27
27
|
"@heyhru/common-util-logger": "0.6.0",
|
|
28
28
|
"@heyhru/server-plugin-jwt": "0.6.0",
|
|
29
|
-
"@heyhru/server-plugin-metrics": "0.7.
|
|
30
|
-
"@heyhru/server-plugin-mysql": "0.7.
|
|
29
|
+
"@heyhru/server-plugin-metrics": "0.7.1",
|
|
30
|
+
"@heyhru/server-plugin-mysql": "0.7.1",
|
|
31
|
+
"@heyhru/server-plugin-otel": "0.7.0",
|
|
31
32
|
"@heyhru/server-plugin-pg": "0.7.0",
|
|
32
33
|
"@heyhru/server-util-crypto": "0.6.0",
|
|
33
34
|
"fastify": "^5.8.4",
|
|
@@ -42,5 +43,5 @@
|
|
|
42
43
|
"typescript": "^6.0.2",
|
|
43
44
|
"vitest": "^4.1.4"
|
|
44
45
|
},
|
|
45
|
-
"gitHead": "
|
|
46
|
+
"gitHead": "c38ab5dee711b502d5811978ddb1329289bd9d25"
|
|
46
47
|
}
|