@heyhru/app-dms-server 0.1.4 → 0.1.5

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 CHANGED
@@ -1,31 +1,5 @@
1
- import "./chunk-QGM4M3NI.js";
2
-
3
- // src/db/index.ts
4
- var _db = null;
5
- var _driver = "sqlite";
6
- function parseDbDriver(url) {
7
- if (url.startsWith("postgres://") || url.startsWith("postgresql://")) return "postgres";
8
- return "sqlite";
9
- }
10
- async function createDmsDb(url) {
11
- if (_db) throw new Error("DmsDb already initialized. Call close() first.");
12
- _driver = parseDbDriver(url);
13
- if (_driver === "postgres") {
14
- const { createPgAdapter } = await import("./pg.adapter-BNI42SHT.js");
15
- _db = createPgAdapter(url);
16
- } else {
17
- const { createSqliteAdapter } = await import("./sqlite.adapter-ARBIRN6Z.js");
18
- _db = createSqliteAdapter(url.replace("sqlite://", ""));
19
- }
20
- return _db;
21
- }
22
- function getDb() {
23
- if (!_db) throw new Error("DmsDb not initialized. Call createDmsDb() first.");
24
- return _db;
25
- }
26
- function getDriver() {
27
- return _driver;
28
- }
1
+ // src/index.ts
2
+ import { createSqlite } from "@heyhru/server-util-sqlite";
29
3
 
30
4
  // src/app.ts
31
5
  import Fastify from "fastify";
@@ -111,10 +85,8 @@ import { hashPassword as hashPassword2, verifyPassword } from "@heyhru/server-ut
111
85
  // src/users/users.service.ts
112
86
  import { hashPassword } from "@heyhru/server-util-crypto";
113
87
 
114
- // src/db/dialect.ts
115
- function nowExpr() {
116
- return getDriver() === "postgres" ? "NOW()" : "datetime('now')";
117
- }
88
+ // src/users/users.model.ts
89
+ import { getSqlite as getDb } from "@heyhru/server-util-sqlite";
118
90
 
119
91
  // src/users/users.sql.ts
120
92
  var LIST = `
@@ -133,9 +105,9 @@ var CREATE = `
133
105
  INSERT INTO users (username, email, password_hash, role)
134
106
  VALUES (?, ?, ?, ?)
135
107
  RETURNING id, username, email, role, created_at`;
136
- var UPDATE_PASSWORD = () => `
108
+ var UPDATE_PASSWORD = `
137
109
  UPDATE users
138
- SET password_hash = ?, updated_at = ${nowExpr()}
110
+ SET password_hash = ?, updated_at = datetime('now')
139
111
  WHERE id = ?`;
140
112
  var DELETE = `
141
113
  DELETE FROM users
@@ -143,18 +115,18 @@ WHERE id = ?`;
143
115
 
144
116
  // src/users/users.model.ts
145
117
  function listUsers() {
146
- return getDb().query(LIST);
118
+ return getDb().prepare(LIST).all();
147
119
  }
148
120
  function getUserById(id) {
149
- return getDb().queryOne(FIND_BY_ID, [id]);
121
+ return getDb().prepare(FIND_BY_ID).get(id);
150
122
  }
151
123
  function getUserByUsername(username) {
152
- return getDb().queryOne(FIND_BY_USERNAME, [username]);
124
+ return getDb().prepare(FIND_BY_USERNAME).get(username);
153
125
  }
154
126
  function createUserRow(username, email, hash, role) {
155
- return getDb().queryOne(CREATE, [username, email, hash, role]);
127
+ return getDb().prepare(CREATE).get(username, email, hash, role);
156
128
  }
157
- async function updateUserRow(id, data) {
129
+ function updateUserRow(id, data) {
158
130
  const fields = [];
159
131
  const values = [];
160
132
  if (data.email) {
@@ -166,18 +138,18 @@ async function updateUserRow(id, data) {
166
138
  values.push(data.role);
167
139
  }
168
140
  if (!fields.length) return getUserById(id);
169
- fields.push(`updated_at = ${nowExpr()}`);
141
+ fields.push("updated_at = datetime('now')");
170
142
  values.push(id);
171
- return getDb().queryOne(
172
- `UPDATE users SET ${fields.join(", ")} WHERE id = ? RETURNING id, username, email, role, created_at`,
173
- values
174
- );
143
+ const bound = values;
144
+ return getDb().prepare(
145
+ `UPDATE users SET ${fields.join(", ")} WHERE id = ? RETURNING id, username, email, role, created_at`
146
+ ).get(...bound);
175
147
  }
176
148
  function deleteUser(id) {
177
- return getDb().run(DELETE, [id]);
149
+ return getDb().prepare(DELETE).run(id);
178
150
  }
179
151
  function updatePasswordHash(id, hash) {
180
- return getDb().run(UPDATE_PASSWORD(), [hash, id]);
152
+ return getDb().prepare(UPDATE_PASSWORD).run(hash, id);
181
153
  }
182
154
 
183
155
  // src/users/users.service.ts
@@ -187,30 +159,30 @@ function getUserByUsername2(username) {
187
159
  function updateUserPassword(id, hash) {
188
160
  return updatePasswordHash(id, hash);
189
161
  }
190
- async function userList(_req, reply) {
191
- return reply.send(await listUsers());
162
+ function userList(_req, reply) {
163
+ return reply.send(listUsers());
192
164
  }
193
- async function userGet(req, reply) {
165
+ function userGet(req, reply) {
194
166
  const { id } = req.body ?? {};
195
- const user = await getUserById(id);
167
+ const user = getUserById(id);
196
168
  if (!user) return reply.code(404).send({ error: "\u672A\u627E\u5230" });
197
169
  return reply.send(user);
198
170
  }
199
171
  async function userCreate(req, reply) {
200
172
  const body = req.body ?? {};
201
173
  const hash = await hashPassword(body.password);
202
- const user = await createUserRow(body.username, body.email, hash, body.role);
174
+ const user = createUserRow(body.username, body.email, hash, body.role);
203
175
  return reply.code(201).send(user);
204
176
  }
205
- async function userUpdate(req, reply) {
177
+ function userUpdate(req, reply) {
206
178
  const { id, ...rest } = req.body ?? {};
207
- const user = await updateUserRow(id, rest);
179
+ const user = updateUserRow(id, rest);
208
180
  if (!user) return reply.code(404).send({ error: "\u672A\u627E\u5230" });
209
181
  return reply.send(user);
210
182
  }
211
- async function userDelete(req, reply) {
183
+ function userDelete(req, reply) {
212
184
  const { id } = req.body ?? {};
213
- await deleteUser(id);
185
+ deleteUser(id);
214
186
  return reply.code(204).send();
215
187
  }
216
188
 
@@ -220,7 +192,7 @@ async function authLogin(req, reply) {
220
192
  if (!username || !password) {
221
193
  return reply.code(400).send({ error: "\u7528\u6237\u540D\u548C\u5BC6\u7801\u4E0D\u80FD\u4E3A\u7A7A" });
222
194
  }
223
- const user = await getUserByUsername2(username);
195
+ const user = getUserByUsername2(username);
224
196
  if (!user || !await verifyPassword(password, user.password_hash)) {
225
197
  logger.warn("Login failed for user: %s", username);
226
198
  return reply.code(401).send({ error: "\u7528\u6237\u540D\u6216\u5BC6\u7801\u9519\u8BEF" });
@@ -242,12 +214,12 @@ async function authChangePassword(req, reply) {
242
214
  if (!currentPassword || !newPassword) {
243
215
  return reply.code(400).send({ error: "\u5F53\u524D\u5BC6\u7801\u548C\u65B0\u5BC6\u7801\u4E0D\u80FD\u4E3A\u7A7A" });
244
216
  }
245
- const user = await getUserByUsername2(req.user.username);
217
+ const user = getUserByUsername2(req.user.username);
246
218
  if (!user || !await verifyPassword(currentPassword, user.password_hash)) {
247
219
  return reply.code(400).send({ error: "\u5F53\u524D\u5BC6\u7801\u4E0D\u6B63\u786E" });
248
220
  }
249
221
  const hash = await hashPassword2(newPassword);
250
- await updateUserPassword(user.id, hash);
222
+ updateUserPassword(user.id, hash);
251
223
  logger.info("Password changed for user: %s", req.user.username);
252
224
  return reply.send({ ok: true });
253
225
  }
@@ -274,13 +246,16 @@ import { encrypt, decrypt } from "@heyhru/server-util-crypto";
274
246
  import { createPool as createMysqlPool } from "@heyhru/server-util-mysql";
275
247
  import { createPool as createPgPool } from "@heyhru/server-util-pg";
276
248
 
249
+ // src/datasources/datasources.model.ts
250
+ import { getSqlite as getDb2 } from "@heyhru/server-util-sqlite";
251
+
277
252
  // src/datasources/datasources.sql.ts
278
253
  var LIST2 = `
279
- SELECT id, name, type, host, port, database, username, ssl, pool_min, pool_max, created_by, created_at
254
+ SELECT id, name, type, host, port, database, username, pool_min, pool_max, created_by, created_at
280
255
  FROM data_sources
281
256
  ORDER BY created_at DESC`;
282
257
  var FIND_BY_ID2 = `
283
- SELECT id, name, type, host, port, database, username, ssl, pool_min, pool_max, created_by, created_at
258
+ SELECT id, name, type, host, port, database, username, pool_min, pool_max, created_by, created_at
284
259
  FROM data_sources
285
260
  WHERE id = ?`;
286
261
  var FIND_WITH_PASSWORD = `
@@ -288,26 +263,26 @@ SELECT *
288
263
  FROM data_sources
289
264
  WHERE id = ?`;
290
265
  var CREATE2 = `
291
- INSERT INTO data_sources (name, type, host, port, database, username, password_encrypted, ssl, pool_min, pool_max, created_by)
292
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
293
- RETURNING id, name, type, host, port, database, username, ssl, pool_min, pool_max, created_by, created_at`;
294
- var UPDATE_FIELDS = ["name", "type", "host", "port", "database", "username", "ssl", "pool_min", "pool_max"];
266
+ INSERT INTO data_sources (name, type, host, port, database, username, password_encrypted, pool_min, pool_max, created_by)
267
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
268
+ RETURNING id, name, type, host, port, database, username, pool_min, pool_max, created_by, created_at`;
269
+ var UPDATE_FIELDS = ["name", "type", "host", "port", "database", "username", "pool_min", "pool_max"];
295
270
  var DELETE2 = `
296
271
  DELETE FROM data_sources
297
272
  WHERE id = ?`;
298
273
 
299
274
  // src/datasources/datasources.model.ts
300
275
  function listDataSources() {
301
- return getDb().query(LIST2);
276
+ return getDb2().prepare(LIST2).all();
302
277
  }
303
278
  function getDataSourceById(id) {
304
- return getDb().queryOne(FIND_BY_ID2, [id]);
279
+ return getDb2().prepare(FIND_BY_ID2).get(id);
305
280
  }
306
281
  function getDataSourceRow(id) {
307
- return getDb().queryOne(FIND_WITH_PASSWORD, [id]);
282
+ return getDb2().prepare(FIND_WITH_PASSWORD).get(id);
308
283
  }
309
284
  function insertDataSource(data, encryptedPassword, createdBy) {
310
- return getDb().queryOne(CREATE2, [
285
+ return getDb2().prepare(CREATE2).get(
311
286
  data.name,
312
287
  data.type,
313
288
  data.host,
@@ -315,13 +290,12 @@ function insertDataSource(data, encryptedPassword, createdBy) {
315
290
  data.database,
316
291
  data.username,
317
292
  encryptedPassword,
318
- data.ssl,
319
293
  data.pool_min,
320
294
  data.pool_max,
321
295
  createdBy
322
- ]);
296
+ );
323
297
  }
324
- async function updateDataSource(id, data, encryptedPassword) {
298
+ function updateDataSource(id, data, encryptedPassword) {
325
299
  const fields = [];
326
300
  const values = [];
327
301
  for (const key of UPDATE_FIELDS) {
@@ -336,13 +310,13 @@ async function updateDataSource(id, data, encryptedPassword) {
336
310
  }
337
311
  if (!fields.length) return getDataSourceById(id);
338
312
  values.push(id);
339
- return getDb().queryOne(
340
- `UPDATE data_sources SET ${fields.join(", ")} WHERE id = ? RETURNING id, name, type, host, port, database, username, ssl, pool_min, pool_max, created_by, created_at`,
341
- values
342
- );
313
+ const bound = values;
314
+ return getDb2().prepare(
315
+ `UPDATE data_sources SET ${fields.join(", ")} WHERE id = ? RETURNING id, name, type, host, port, database, username, pool_min, pool_max, created_by, created_at`
316
+ ).get(...bound);
343
317
  }
344
318
  function removeDataSource(id) {
345
- return getDb().run(DELETE2, [id]);
319
+ return getDb2().prepare(DELETE2).run(id);
346
320
  }
347
321
 
348
322
  // src/datasources/datasources.service.ts
@@ -367,15 +341,14 @@ function getPool(ds) {
367
341
  username: ds.username,
368
342
  password: ds.password,
369
343
  poolMin: ds.pool_min,
370
- poolMax: ds.pool_max,
371
- ssl: ds.ssl
344
+ poolMax: ds.pool_max
372
345
  });
373
346
  pools.set(key, pool);
374
347
  logger.info("Connection pool created (ds=%s, db=%s, type=%s)", ds.id, ds.database, ds.type);
375
348
  return pool;
376
349
  }
377
- async function getPoolForDatabase(dataSourceId, database) {
378
- const ds = await getDataSourceWithPassword(dataSourceId);
350
+ function getPoolForDatabase(dataSourceId, database) {
351
+ const ds = getDataSourceWithPassword(dataSourceId);
379
352
  if (!ds) return null;
380
353
  return getPool({ ...ds, database });
381
354
  }
@@ -389,8 +362,8 @@ async function destroyPool(id) {
389
362
  }
390
363
  }
391
364
  }
392
- async function getDataSourceWithPassword(id) {
393
- const row = await getDataSourceRow(id);
365
+ function getDataSourceWithPassword(id) {
366
+ const row = getDataSourceRow(id);
394
367
  if (!row) return null;
395
368
  return {
396
369
  id: row.id,
@@ -400,24 +373,23 @@ async function getDataSourceWithPassword(id) {
400
373
  database: row.database ?? null,
401
374
  username: row.username,
402
375
  password: decrypt(row.password_encrypted, config.encryptionKey),
403
- ssl: row.ssl,
404
376
  pool_min: row.pool_min,
405
377
  pool_max: row.pool_max
406
378
  };
407
379
  }
408
- async function datasourceList(_req, reply) {
409
- return reply.send(await listDataSources());
380
+ function datasourceList(_req, reply) {
381
+ return reply.send(listDataSources());
410
382
  }
411
- async function datasourceGet(req, reply) {
383
+ function datasourceGet(req, reply) {
412
384
  const { id } = req.body ?? {};
413
- const ds = await getDataSourceById(id);
385
+ const ds = getDataSourceById(id);
414
386
  if (!ds) return reply.code(404).send({ error: "\u672A\u627E\u5230" });
415
387
  return reply.send(ds);
416
388
  }
417
- async function datasourceCreate(req, reply) {
389
+ function datasourceCreate(req, reply) {
418
390
  const body = req.body ?? {};
419
- const ds = await insertDataSource(
420
- { ...body, ssl: body.ssl ?? false, pool_min: body.pool_min ?? 1, pool_max: body.pool_max ?? 10 },
391
+ const ds = insertDataSource(
392
+ { ...body, pool_min: body.pool_min ?? 1, pool_max: body.pool_max ?? 10 },
421
393
  encrypt(body.password, config.encryptionKey),
422
394
  req.user.id
423
395
  );
@@ -425,17 +397,17 @@ async function datasourceCreate(req, reply) {
425
397
  }
426
398
  async function datasourceUpdate(req, reply) {
427
399
  const { id, password, ...rest } = req.body ?? {};
428
- const existing = await getDataSourceById(id);
400
+ const existing = getDataSourceById(id);
429
401
  if (!existing) return reply.code(404).send({ error: "\u672A\u627E\u5230" });
430
402
  const encryptedPassword = password ? encrypt(password, config.encryptionKey) : void 0;
431
403
  await destroyPool(id);
432
- const ds = await updateDataSource(id, rest, encryptedPassword);
404
+ const ds = updateDataSource(id, rest, encryptedPassword);
433
405
  return reply.send(ds);
434
406
  }
435
407
  async function datasourceDelete(req, reply) {
436
408
  const { id } = req.body ?? {};
437
409
  await destroyPool(id);
438
- await removeDataSource(id);
410
+ removeDataSource(id);
439
411
  return reply.code(204).send();
440
412
  }
441
413
 
@@ -451,6 +423,9 @@ function datasourceController(app) {
451
423
  // src/sql/sql.service.ts
452
424
  import NodeSqlParser from "node-sql-parser";
453
425
 
426
+ // src/audit/audit.model.ts
427
+ import { getSqlite as getDb3 } from "@heyhru/server-util-sqlite";
428
+
454
429
  // src/audit/audit.sql.ts
455
430
  var INSERT = `
456
431
  INSERT INTO audit_logs (user_id, data_source_id, action, sql_text, result_summary, ip_address)
@@ -463,16 +438,16 @@ WHERE 1=1`;
463
438
 
464
439
  // src/audit/audit.model.ts
465
440
  function insertAuditLog(entry) {
466
- return getDb().run(INSERT, [
441
+ return getDb3().prepare(INSERT).run(
467
442
  entry.userId,
468
443
  entry.dataSourceId ?? null,
469
444
  entry.action,
470
445
  entry.sqlText ?? null,
471
446
  entry.resultSummary ?? null,
472
447
  entry.ipAddress ?? null
473
- ]);
448
+ );
474
449
  }
475
- async function queryAuditLogs(filters) {
450
+ function queryAuditLogs(filters) {
476
451
  let query = LIST3;
477
452
  const params = [];
478
453
  if (filters?.userId) {
@@ -485,7 +460,8 @@ async function queryAuditLogs(filters) {
485
460
  }
486
461
  query += " ORDER BY al.created_at DESC LIMIT ? OFFSET ?";
487
462
  params.push(filters?.limit ?? 50, filters?.offset ?? 0);
488
- return getDb().query(query, params);
463
+ const bound = params;
464
+ return getDb3().prepare(query).all(...bound);
489
465
  }
490
466
 
491
467
  // src/audit/audit.service.ts
@@ -540,8 +516,8 @@ async function sqlExecute({ dataSourceId, database, sql, userId, ip }) {
540
516
  if (category !== "select") {
541
517
  throw new Error("\u4EC5\u5141\u8BB8\u76F4\u63A5\u6267\u884C SELECT \u8BED\u53E5");
542
518
  }
543
- const pool = database ? await getPoolForDatabase(dataSourceId, database) : await (async () => {
544
- const ds = await getDataSourceWithPassword(dataSourceId);
519
+ const pool = database ? getPoolForDatabase(dataSourceId, database) : (() => {
520
+ const ds = getDataSourceWithPassword(dataSourceId);
545
521
  return ds ? getPool(ds) : null;
546
522
  })();
547
523
  if (!pool) throw new Error("\u6570\u636E\u6E90\u672A\u627E\u5230");
@@ -556,48 +532,46 @@ async function sqlExecute({ dataSourceId, database, sql, userId, ip }) {
556
532
  });
557
533
  return rows;
558
534
  }
559
- async function postSqlDatabases(req, reply) {
535
+ function postSqlDatabases(req, reply) {
560
536
  const { dataSourceId } = req.body ?? {};
561
537
  if (!dataSourceId) {
562
538
  return reply.code(400).send({ error: "\u6570\u636E\u6E90 ID \u4E0D\u80FD\u4E3A\u7A7A" });
563
539
  }
564
- const ds = await getDataSourceWithPassword(dataSourceId);
540
+ const ds = getDataSourceWithPassword(dataSourceId);
565
541
  if (!ds) return reply.code(404).send({ error: "\u6570\u636E\u6E90\u672A\u627E\u5230" });
566
542
  const pool = getPool({
567
543
  ...ds,
568
544
  database: ds.database ?? (ds.type === "postgres" ? "postgres" : "")
569
545
  });
570
546
  const sql = ds.type === "mysql" ? "SHOW DATABASES" : "SELECT datname FROM pg_database WHERE datistemplate = false ORDER BY datname";
571
- try {
572
- const rows = await pool.execute(sql);
547
+ return pool.execute(sql).then((rows) => {
573
548
  const names = rows.map(
574
549
  (r) => Object.values(r)[0]
575
550
  );
576
551
  return reply.send(names);
577
- } catch (err) {
552
+ }).catch((err) => {
578
553
  logger.error(err, "Failed to list databases (ds=%s)", dataSourceId);
579
554
  return reply.code(400).send({ error: err instanceof Error ? err.message : String(err) });
580
- }
555
+ });
581
556
  }
582
- async function postSqlTables(req, reply) {
557
+ function postSqlTables(req, reply) {
583
558
  const { dataSourceId, database } = req.body ?? {};
584
559
  if (!dataSourceId || !database) {
585
560
  return reply.code(400).send({ error: "\u6570\u636E\u6E90 ID \u548C\u6570\u636E\u5E93\u540D\u4E0D\u80FD\u4E3A\u7A7A" });
586
561
  }
587
- const pool = await getPoolForDatabase(dataSourceId, database);
562
+ const pool = getPoolForDatabase(dataSourceId, database);
588
563
  if (!pool) return reply.code(404).send({ error: "\u6570\u636E\u6E90\u672A\u627E\u5230" });
589
- const ds = await getDataSourceWithPassword(dataSourceId);
564
+ const ds = getDataSourceWithPassword(dataSourceId);
590
565
  const sql = ds.type === "mysql" ? `SELECT TABLE_NAME FROM information_schema.TABLES WHERE TABLE_SCHEMA = '${database}' ORDER BY TABLE_NAME` : "SELECT tablename FROM pg_tables WHERE schemaname = 'public' ORDER BY tablename";
591
- try {
592
- const rows = await pool.execute(sql);
566
+ return pool.execute(sql).then((rows) => {
593
567
  const names = rows.map(
594
568
  (r) => Object.values(r)[0]
595
569
  );
596
570
  return reply.send(names);
597
- } catch (err) {
571
+ }).catch((err) => {
598
572
  logger.error(err, "Failed to list tables (ds=%s, db=%s)", dataSourceId, database);
599
573
  return reply.code(400).send({ error: err instanceof Error ? err.message : String(err) });
600
- }
574
+ });
601
575
  }
602
576
 
603
577
  // src/sql/sql.controller.ts
@@ -608,6 +582,9 @@ function sqlController(app) {
608
582
  app.post("/sql/tables", postSqlTables);
609
583
  }
610
584
 
585
+ // src/approvals/approvals.model.ts
586
+ import { getSqlite as getDb4 } from "@heyhru/server-util-sqlite";
587
+
611
588
  // src/approvals/approvals.sql.ts
612
589
  var FIND_BY_ID3 = `
613
590
  SELECT *
@@ -617,22 +594,22 @@ var CREATE3 = `
617
594
  INSERT INTO approvals (data_source_id, sql_text, submitted_by)
618
595
  VALUES (?, ?, ?)
619
596
  RETURNING *`;
620
- var UPDATE_REVIEW = () => `
597
+ var UPDATE_REVIEW = `
621
598
  UPDATE approvals
622
- SET status = ?, reviewed_by = ?, reject_reason = ?, updated_at = ${nowExpr()}
599
+ SET status = ?, reviewed_by = ?, reject_reason = ?, updated_at = datetime('now')
623
600
  WHERE id = ?
624
601
  RETURNING *`;
625
- var UPDATE_EXECUTING = () => `
602
+ var UPDATE_EXECUTING = `
626
603
  UPDATE approvals
627
- SET status = 'executing', updated_at = ${nowExpr()}
604
+ SET status = 'executing', updated_at = datetime('now')
628
605
  WHERE id = ?`;
629
- var UPDATE_RESULT = () => `
606
+ var UPDATE_RESULT = `
630
607
  UPDATE approvals
631
- SET status = ?, execute_result = ?, updated_at = ${nowExpr()}
608
+ SET status = ?, execute_result = ?, updated_at = datetime('now')
632
609
  WHERE id = ?`;
633
610
 
634
611
  // src/approvals/approvals.model.ts
635
- async function listApprovals(filters) {
612
+ function listApprovals(filters) {
636
613
  let query = "SELECT * FROM approvals WHERE 1=1";
637
614
  const params = [];
638
615
  if (filters?.status) {
@@ -644,51 +621,52 @@ async function listApprovals(filters) {
644
621
  params.push(filters.submittedBy);
645
622
  }
646
623
  query += " ORDER BY created_at DESC";
647
- return getDb().query(query, params);
624
+ const bound = params;
625
+ return getDb4().prepare(query).all(...bound);
648
626
  }
649
627
  function getApprovalById(id) {
650
- return getDb().queryOne(FIND_BY_ID3, [id]);
628
+ return getDb4().prepare(FIND_BY_ID3).get(id);
651
629
  }
652
630
  function insertApproval(dataSourceId, sqlText, submittedBy) {
653
- return getDb().queryOne(CREATE3, [dataSourceId, sqlText, submittedBy]);
631
+ return getDb4().prepare(CREATE3).get(dataSourceId, sqlText, submittedBy);
654
632
  }
655
633
  function updateReview(id, status, reviewedBy, rejectReason) {
656
- return getDb().queryOne(UPDATE_REVIEW(), [status, reviewedBy, rejectReason, id]);
634
+ return getDb4().prepare(UPDATE_REVIEW).get(status, reviewedBy, rejectReason, id);
657
635
  }
658
636
  function setExecuting(id) {
659
- return getDb().run(UPDATE_EXECUTING(), [id]);
637
+ return getDb4().prepare(UPDATE_EXECUTING).run(id);
660
638
  }
661
639
  function setExecuteResult(id, status, result) {
662
- return getDb().run(UPDATE_RESULT(), [status, result, id]);
640
+ return getDb4().prepare(UPDATE_RESULT).run(status, result, id);
663
641
  }
664
642
 
665
643
  // src/approvals/approvals.service.ts
666
- async function approvalList(req, reply) {
644
+ function approvalList(req, reply) {
667
645
  const { status, mine } = req.body ?? {};
668
646
  return reply.send(
669
- await listApprovals({
647
+ listApprovals({
670
648
  status,
671
649
  submittedBy: mine === "true" ? req.user.id : void 0
672
650
  })
673
651
  );
674
652
  }
675
- async function approvalGet(req, reply) {
653
+ function approvalGet(req, reply) {
676
654
  const { id } = req.body ?? {};
677
- const approval = await getApprovalById(id);
655
+ const approval = getApprovalById(id);
678
656
  if (!approval) return reply.code(404).send({ error: "\u672A\u627E\u5230" });
679
657
  return reply.send(approval);
680
658
  }
681
- async function approvalCreate(req, reply) {
659
+ function approvalCreate(req, reply) {
682
660
  const { dataSourceId, sql } = req.body ?? {};
683
661
  if (!dataSourceId || !sql) {
684
662
  return reply.code(400).send({ error: "\u6570\u636E\u6E90 ID \u548C SQL \u4E0D\u80FD\u4E3A\u7A7A" });
685
663
  }
686
- const approval = await insertApproval(dataSourceId, sql, req.user.id);
664
+ const approval = insertApproval(dataSourceId, sql, req.user.id);
687
665
  logger.info("Approval submitted (user=%s)", req.user.id);
688
666
  return reply.code(201).send(approval);
689
667
  }
690
- async function reviewApproval(id, reviewerId, decision, rejectReason) {
691
- const approval = await getApprovalById(id);
668
+ function reviewApproval(id, reviewerId, decision, rejectReason) {
669
+ const approval = getApprovalById(id);
692
670
  if (!approval || approval["status"] !== "pending") {
693
671
  throw new Error("\u5BA1\u6279\u8BB0\u5F55\u4E0D\u5B58\u5728\u6216\u4E0D\u5728\u5F85\u5BA1\u6279\u72B6\u6001");
694
672
  }
@@ -697,10 +675,10 @@ async function reviewApproval(id, reviewerId, decision, rejectReason) {
697
675
  }
698
676
  return updateReview(id, decision, reviewerId, rejectReason ?? null);
699
677
  }
700
- async function approvalApprove(req, reply) {
678
+ function approvalApprove(req, reply) {
701
679
  const { id } = req.body ?? {};
702
680
  try {
703
- const result = await reviewApproval(id, req.user.id, "approved");
681
+ const result = reviewApproval(id, req.user.id, "approved");
704
682
  logger.info("Approval approved (id=%s, reviewer=%s)", id, req.user.id);
705
683
  return reply.send(result);
706
684
  } catch (err) {
@@ -708,10 +686,10 @@ async function approvalApprove(req, reply) {
708
686
  return reply.code(400).send({ error: err instanceof Error ? err.message : String(err) });
709
687
  }
710
688
  }
711
- async function approvalReject(req, reply) {
689
+ function approvalReject(req, reply) {
712
690
  const { id, reason } = req.body ?? {};
713
691
  try {
714
- const result = await reviewApproval(id, req.user.id, "rejected", reason);
692
+ const result = reviewApproval(id, req.user.id, "rejected", reason);
715
693
  logger.info("Approval rejected (id=%s, reviewer=%s)", id, req.user.id);
716
694
  return reply.send(result);
717
695
  } catch (err) {
@@ -731,18 +709,18 @@ async function approvalExecute(req, reply) {
731
709
  }
732
710
  }
733
711
  async function doExecuteApproval(id, userId, ip) {
734
- const approval = await getApprovalById(id);
712
+ const approval = getApprovalById(id);
735
713
  if (!approval || approval["status"] !== "approved") {
736
714
  throw new Error("\u5BA1\u6279\u8BB0\u5F55\u4E0D\u5B58\u5728\u6216\u672A\u901A\u8FC7\u5BA1\u6279");
737
715
  }
738
- await setExecuting(id);
716
+ setExecuting(id);
739
717
  try {
740
- const ds = await getDataSourceWithPassword(approval["data_source_id"]);
718
+ const ds = getDataSourceWithPassword(approval["data_source_id"]);
741
719
  if (!ds) throw new Error("\u6570\u636E\u6E90\u672A\u627E\u5230");
742
720
  const pool = getPool(ds);
743
721
  const rows = await pool.execute(approval["sql_text"]);
744
722
  const result = `${rows.length} rows affected`;
745
- await setExecuteResult(id, "executed", result);
723
+ setExecuteResult(id, "executed", result);
746
724
  logger.info("Approval executed (id=%s, user=%s)", id, userId);
747
725
  await writeAuditLog({
748
726
  userId,
@@ -755,7 +733,7 @@ async function doExecuteApproval(id, userId, ip) {
755
733
  return getApprovalById(id);
756
734
  } catch (err) {
757
735
  const message = err instanceof Error ? err.message : String(err);
758
- await setExecuteResult(id, "execute_failed", message);
736
+ setExecuteResult(id, "execute_failed", message);
759
737
  logger.error(err, "Approval execute_failed (id=%s)", id);
760
738
  throw err;
761
739
  }
@@ -796,39 +774,38 @@ async function buildApp() {
796
774
  return app;
797
775
  }
798
776
 
777
+ // src/migrate/runner.ts
778
+ import { getSqlite as getDb5 } from "@heyhru/server-util-sqlite";
779
+
799
780
  // src/migrate/migrations.ts
800
- var idCol = (driver) => driver === "postgres" ? "id UUID PRIMARY KEY DEFAULT gen_random_uuid()" : "id TEXT PRIMARY KEY DEFAULT (lower(hex(randomblob(16))))";
801
- var tsCol = (name, driver) => driver === "postgres" ? `${name} TIMESTAMPTZ NOT NULL DEFAULT NOW()` : `${name} TEXT NOT NULL DEFAULT (datetime('now'))`;
802
- var fkNotNull = (name, ref, driver) => driver === "postgres" ? `${name} UUID NOT NULL REFERENCES ${ref}(id)` : `${name} TEXT NOT NULL REFERENCES ${ref}(id)`;
803
- var fkNullable = (name, ref, driver) => driver === "postgres" ? `${name} UUID REFERENCES ${ref}(id)` : `${name} TEXT REFERENCES ${ref}(id)`;
804
781
  var migrations = [
805
782
  {
806
783
  name: "001_users.sql",
807
- sql: (d) => `
784
+ sql: `
808
785
  CREATE TABLE IF NOT EXISTS users (
809
- ${idCol(d)},
786
+ id TEXT PRIMARY KEY DEFAULT (lower(hex(randomblob(16)))),
810
787
  username TEXT NOT NULL UNIQUE,
811
788
  email TEXT NOT NULL UNIQUE,
812
789
  password_hash TEXT NOT NULL,
813
790
  role TEXT NOT NULL CHECK (role IN ('admin', 'maintainer', 'developer', 'viewer')),
814
- ${tsCol("created_at", d)},
815
- ${tsCol("updated_at", d)}
791
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
792
+ updated_at TEXT NOT NULL DEFAULT (datetime('now'))
816
793
  );
817
794
 
818
- INSERT ${d === "postgres" ? "" : "OR IGNORE "}INTO users (id, username, email, password_hash, role)
795
+ INSERT OR IGNORE INTO users (id, username, email, password_hash, role)
819
796
  VALUES (
820
797
  'admin-seed-id-0000000000000000',
821
798
  'admin',
822
799
  'admin@example.com',
823
800
  '178c20236d9629bffcb301f57d1b8383:40c49d6500a8f322754ac0cd2d5c9dea019a4c14feef60e436d767cc2dd44bc1eeee7ef16f1bd768260aeec4025e06c479c4c367537899002ec89962382a3104',
824
801
  'admin'
825
- )${d === "postgres" ? " ON CONFLICT (id) DO NOTHING" : ""};`
802
+ );`
826
803
  },
827
804
  {
828
805
  name: "002_data_sources.sql",
829
- sql: (d) => `
806
+ sql: `
830
807
  CREATE TABLE IF NOT EXISTS data_sources (
831
- ${idCol(d)},
808
+ id TEXT PRIMARY KEY DEFAULT (lower(hex(randomblob(16)))),
832
809
  name TEXT NOT NULL UNIQUE,
833
810
  type TEXT NOT NULL CHECK (type IN ('mysql', 'postgres')),
834
811
  host TEXT NOT NULL,
@@ -836,84 +813,77 @@ CREATE TABLE IF NOT EXISTS data_sources (
836
813
  database TEXT,
837
814
  username TEXT NOT NULL,
838
815
  password_encrypted TEXT NOT NULL,
839
- ssl BOOLEAN NOT NULL DEFAULT FALSE,
840
816
  pool_min INTEGER NOT NULL DEFAULT 1,
841
817
  pool_max INTEGER NOT NULL DEFAULT 10,
842
- ${fkNotNull("created_by", "users", d)},
843
- ${tsCol("created_at", d)},
844
- ${tsCol("updated_at", d)}
818
+ created_by TEXT NOT NULL REFERENCES users(id),
819
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
820
+ updated_at TEXT NOT NULL DEFAULT (datetime('now'))
845
821
  );`
846
822
  },
847
823
  {
848
824
  name: "003_audit_logs.sql",
849
- sql: (d) => `
825
+ sql: `
850
826
  CREATE TABLE IF NOT EXISTS audit_logs (
851
- ${idCol(d)},
852
- ${fkNotNull("user_id", "users", d)},
853
- ${fkNullable("data_source_id", "data_sources", d)},
827
+ id TEXT PRIMARY KEY DEFAULT (lower(hex(randomblob(16)))),
828
+ user_id TEXT NOT NULL REFERENCES users(id),
829
+ data_source_id TEXT REFERENCES data_sources(id),
854
830
  action TEXT NOT NULL,
855
831
  sql_text TEXT,
856
832
  result_summary TEXT,
857
833
  ip_address TEXT,
858
- ${tsCol("created_at", d)}
834
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
859
835
  );
860
836
 
861
837
  CREATE INDEX IF NOT EXISTS idx_audit_logs_user_id ON audit_logs(user_id);
862
- CREATE INDEX IF NOT EXISTS idx_audit_logs_data_source_id ON audit_logs(data_source_id);
863
838
  CREATE INDEX IF NOT EXISTS idx_audit_logs_created_at ON audit_logs(created_at);`
864
839
  },
865
840
  {
866
841
  name: "004_approvals.sql",
867
- sql: (d) => `
842
+ sql: `
868
843
  CREATE TABLE IF NOT EXISTS approvals (
869
- ${idCol(d)},
870
- ${fkNotNull("data_source_id", "data_sources", d)},
871
- ${fkNotNull("submitted_by", "users", d)},
872
- ${fkNullable("reviewed_by", "users", d)},
844
+ id TEXT PRIMARY KEY DEFAULT (lower(hex(randomblob(16)))),
845
+ data_source_id TEXT NOT NULL REFERENCES data_sources(id),
846
+ submitted_by TEXT NOT NULL REFERENCES users(id),
847
+ reviewed_by TEXT REFERENCES users(id),
873
848
  sql_text TEXT NOT NULL,
874
849
  status TEXT NOT NULL DEFAULT 'pending'
875
850
  CHECK (status IN ('pending', 'approved', 'rejected', 'executing', 'executed', 'execute_failed')),
876
851
  reject_reason TEXT,
877
852
  execute_result TEXT,
878
- ${tsCol("created_at", d)},
879
- ${tsCol("updated_at", d)}
853
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
854
+ updated_at TEXT NOT NULL DEFAULT (datetime('now'))
880
855
  );
881
856
 
882
857
  CREATE INDEX IF NOT EXISTS idx_approvals_status ON approvals(status);
883
858
  CREATE INDEX IF NOT EXISTS idx_approvals_submitted_by ON approvals(submitted_by);`
884
- },
885
- {
886
- name: "005_data_sources_add_ssl.sql",
887
- sql: () => `
888
- ALTER TABLE data_sources ADD COLUMN ssl BOOLEAN NOT NULL DEFAULT FALSE;`
889
859
  }
890
860
  ];
891
861
 
892
862
  // src/migrate/runner.ts
893
- async function runMigrations() {
894
- const db = getDb();
895
- const driver = getDriver();
896
- const createMigrationTable = driver === "postgres" ? `CREATE TABLE IF NOT EXISTS _migrations (
897
- name TEXT PRIMARY KEY,
898
- applied_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
899
- )` : `CREATE TABLE IF NOT EXISTS _migrations (
900
- name TEXT PRIMARY KEY,
901
- applied_at TEXT NOT NULL DEFAULT (datetime('now'))
902
- )`;
903
- await db.exec(createMigrationTable);
904
- const rows = await db.query("SELECT name FROM _migrations");
905
- const applied = new Set(rows.map((r) => r.name));
863
+ function runMigrations() {
864
+ const db = getDb5();
865
+ db.exec(`
866
+ CREATE TABLE IF NOT EXISTS _migrations (
867
+ name TEXT PRIMARY KEY,
868
+ applied_at TEXT NOT NULL DEFAULT (datetime('now'))
869
+ )
870
+ `);
871
+ const applied = new Set(
872
+ db.prepare("SELECT name FROM _migrations").all().map((r) => r.name)
873
+ );
906
874
  for (const migration of migrations) {
907
875
  if (applied.has(migration.name)) continue;
908
- await db.exec(migration.sql(driver));
909
- await db.run("INSERT INTO _migrations (name) VALUES (?)", [migration.name]);
876
+ db.exec(migration.sql);
877
+ db.prepare("INSERT INTO _migrations (name) VALUES (?)").run(
878
+ migration.name
879
+ );
910
880
  logger.info("Migration applied: %s", migration.name);
911
881
  }
912
882
  }
913
883
 
914
884
  // src/index.ts
915
885
  async function main() {
916
- await createDmsDb(config.dbUrl);
886
+ createSqlite({ path: config.dbUrl.replace("sqlite://", "") });
917
887
  await runMigrations();
918
888
  const app = await buildApp();
919
889
  await app.listen({ port: config.port, host: "0.0.0.0" });