asaihost-nodejs 0.0.4 → 0.0.6

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 (59) hide show
  1. package/dist/{InterventionLog-PZT2CCN3.es.js → InterventionLog-OPQ6VOBV.es.js} +3 -3
  2. package/dist/InterventionLog-WNVDQFAH.cjs +30 -0
  3. package/dist/{InterventionLog-CRP6YJVM.cjs.map → InterventionLog-WNVDQFAH.cjs.map} +1 -1
  4. package/dist/LogStore-AP4T2CFD.cjs +54 -0
  5. package/dist/{LogStore-7MTUQA4G.cjs.map → LogStore-AP4T2CFD.cjs.map} +1 -1
  6. package/dist/{LogStore-Q35YFNAY.es.js → LogStore-DWIPPRCA.es.js} +2 -2
  7. package/dist/asaihost-nodejs.cjs +472 -484
  8. package/dist/asaihost-nodejs.cjs.map +1 -1
  9. package/dist/asaihost-nodejs.d.cts +18 -2
  10. package/dist/asaihost-nodejs.d.ts +18 -2
  11. package/dist/asaihost-nodejs.es.js +133 -145
  12. package/dist/asaihost-nodejs.es.js.map +1 -1
  13. package/dist/{chunk-A6VJPLDD.es.js → chunk-5WJQD4RZ.es.js} +3 -3
  14. package/dist/{chunk-RIRKIYET.cjs → chunk-ARHPHWT5.cjs} +12 -12
  15. package/dist/{chunk-RIRKIYET.cjs.map → chunk-ARHPHWT5.cjs.map} +1 -1
  16. package/dist/{chunk-A5CDJGJI.es.js → chunk-BOIRAQXE.es.js} +1 -1
  17. package/dist/chunk-BOIRAQXE.es.js.map +1 -0
  18. package/dist/{chunk-LTEP4XB2.es.js → chunk-EC67M7RR.es.js} +115 -21
  19. package/dist/chunk-EC67M7RR.es.js.map +1 -0
  20. package/dist/{chunk-SB23ESX2.es.js → chunk-GCR56QH7.es.js} +2 -2
  21. package/dist/{chunk-H3K33HBA.cjs → chunk-GXOFLFFW.cjs} +1 -1
  22. package/dist/{chunk-H3K33HBA.cjs.map → chunk-GXOFLFFW.cjs.map} +1 -1
  23. package/dist/{chunk-TKJAHTPO.cjs → chunk-HR5JKN7Y.cjs} +161 -67
  24. package/dist/chunk-HR5JKN7Y.cjs.map +1 -0
  25. package/dist/{chunk-VUZO7DCA.es.js → chunk-N6LBKGML.es.js} +2 -2
  26. package/dist/{chunk-57UQJKSL.es.js → chunk-OTL2B4WS.es.js} +2 -2
  27. package/dist/{chunk-4E7Z5K5U.cjs → chunk-U2YJH2RW.cjs} +4 -4
  28. package/dist/{chunk-4E7Z5K5U.cjs.map → chunk-U2YJH2RW.cjs.map} +1 -1
  29. package/dist/{chunk-K2QPSQEV.cjs → chunk-WXW5DYNU.cjs} +9 -9
  30. package/dist/{chunk-K2QPSQEV.cjs.map → chunk-WXW5DYNU.cjs.map} +1 -1
  31. package/dist/{chunk-LXJMGLKW.cjs → chunk-ZK4O4Z2O.cjs} +20 -20
  32. package/dist/{chunk-LXJMGLKW.cjs.map → chunk-ZK4O4Z2O.cjs.map} +1 -1
  33. package/dist/intervention-hooks-4NAAAZK3.cjs +21 -0
  34. package/dist/{intervention-hooks-KF3SNB5Q.cjs.map → intervention-hooks-4NAAAZK3.cjs.map} +1 -1
  35. package/dist/{intervention-hooks-TCGIC4IV.es.js → intervention-hooks-QNA4IZT7.es.js} +4 -4
  36. package/dist/{password-4BABWAG4.es.js → password-4P7IZUDQ.es.js} +3 -3
  37. package/dist/password-MDYRL6ZD.cjs +20 -0
  38. package/dist/{password-PJHJRGPE.cjs.map → password-MDYRL6ZD.cjs.map} +1 -1
  39. package/dist/user-store-55HOLHEM.cjs +12 -0
  40. package/dist/{user-store-6J2PSEIN.cjs.map → user-store-55HOLHEM.cjs.map} +1 -1
  41. package/dist/{user-store-UC5URX3C.es.js → user-store-FXD2N55G.es.js} +3 -3
  42. package/package.json +1 -1
  43. package/dist/InterventionLog-CRP6YJVM.cjs +0 -30
  44. package/dist/LogStore-7MTUQA4G.cjs +0 -54
  45. package/dist/chunk-A5CDJGJI.es.js.map +0 -1
  46. package/dist/chunk-LTEP4XB2.es.js.map +0 -1
  47. package/dist/chunk-TKJAHTPO.cjs.map +0 -1
  48. package/dist/intervention-hooks-KF3SNB5Q.cjs +0 -21
  49. package/dist/password-PJHJRGPE.cjs +0 -20
  50. package/dist/user-store-6J2PSEIN.cjs +0 -12
  51. /package/dist/{InterventionLog-PZT2CCN3.es.js.map → InterventionLog-OPQ6VOBV.es.js.map} +0 -0
  52. /package/dist/{LogStore-Q35YFNAY.es.js.map → LogStore-DWIPPRCA.es.js.map} +0 -0
  53. /package/dist/{chunk-A6VJPLDD.es.js.map → chunk-5WJQD4RZ.es.js.map} +0 -0
  54. /package/dist/{chunk-SB23ESX2.es.js.map → chunk-GCR56QH7.es.js.map} +0 -0
  55. /package/dist/{chunk-VUZO7DCA.es.js.map → chunk-N6LBKGML.es.js.map} +0 -0
  56. /package/dist/{chunk-57UQJKSL.es.js.map → chunk-OTL2B4WS.es.js.map} +0 -0
  57. /package/dist/{intervention-hooks-TCGIC4IV.es.js.map → intervention-hooks-QNA4IZT7.es.js.map} +0 -0
  58. /package/dist/{password-4BABWAG4.es.js.map → password-4P7IZUDQ.es.js.map} +0 -0
  59. /package/dist/{user-store-UC5URX3C.es.js.map → user-store-FXD2N55G.es.js.map} +0 -0
@@ -11,7 +11,7 @@ import {
11
11
  dbWriteSessions,
12
12
  ensureUserStoreTables,
13
13
  resolveRoleForLevel
14
- } from "./chunk-A5CDJGJI.es.js";
14
+ } from "./chunk-BOIRAQXE.es.js";
15
15
  import {
16
16
  __name
17
17
  } from "./chunk-6U2I5EON.es.js";
@@ -310,7 +310,7 @@ async function ensureBootstrapAdmin($asai) {
310
310
  await ensureUserStoreTables($asai);
311
311
  const users = await dbListUsers($asai);
312
312
  if (users.length > 0) return;
313
- const { hashPassword } = await import("./password-4BABWAG4.es.js");
313
+ const { hashPassword } = await import("./password-4P7IZUDQ.es.js");
314
314
  const pwd = $asai?.hostconfig?.password;
315
315
  if (!pwd) throw new Error("[user-store] ASAI_HOST_PASSWORD \u672A\u914D\u7F6E\uFF0C\u65E0\u6CD5\u521B\u5EFA bootstrap admin");
316
316
  const { passHash, passSalt } = hashPassword(pwd);
@@ -434,4 +434,4 @@ export {
434
434
  ensureBootstrapAdmin,
435
435
  createUserStore
436
436
  };
437
- //# sourceMappingURL=chunk-A6VJPLDD.es.js.map
437
+ //# sourceMappingURL=chunk-5WJQD4RZ.es.js.map
@@ -1,7 +1,7 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } }
2
2
 
3
3
 
4
- var _chunk4E7Z5K5Ucjs = require('./chunk-4E7Z5K5U.cjs');
4
+ var _chunkU2YJH2RWcjs = require('./chunk-U2YJH2RW.cjs');
5
5
 
6
6
 
7
7
 
@@ -17,8 +17,8 @@ _chunkSMVZ3ZDJcjs.__export.call(void 0, intervention_hooks_exports, {
17
17
  logUserRbacChange: () => logUserRbacChange
18
18
  });
19
19
  async function logUserRbacChange($asai, opts) {
20
- const identification = _chunk4E7Z5K5Ucjs.crc32.call(void 0, JSON.stringify({ us: opts.targetUs, ...opts.patch }));
21
- return _chunk4E7Z5K5Ucjs.logIntervention.call(void 0, $asai, {
20
+ const identification = _chunkU2YJH2RWcjs.crc32.call(void 0, JSON.stringify({ us: opts.targetUs, ...opts.patch }));
21
+ return _chunkU2YJH2RWcjs.logIntervention.call(void 0, $asai, {
22
22
  type: "SAFETY_PARAM",
23
23
  name: `User RBAC changed: ${opts.targetUs}`,
24
24
  category: "ConfigurationChanges",
@@ -33,8 +33,8 @@ async function logUserRbacChange($asai, opts) {
33
33
  }
34
34
  _chunkSMVZ3ZDJcjs.__name.call(void 0, logUserRbacChange, "logUserRbacChange");
35
35
  async function logProcessGuardEvent($asai, opts) {
36
- const identification = _chunk4E7Z5K5Ucjs.crc32.call(void 0, `${opts.action}|${opts.detail || ""}|${Date.now()}`);
37
- return _chunk4E7Z5K5Ucjs.logIntervention.call(void 0, $asai, {
36
+ const identification = _chunkU2YJH2RWcjs.crc32.call(void 0, `${opts.action}|${opts.detail || ""}|${Date.now()}`);
37
+ return _chunkU2YJH2RWcjs.logIntervention.call(void 0, $asai, {
38
38
  type: "PROCESS_GUARD",
39
39
  name: `Process guard: ${opts.action}`,
40
40
  category: "ControlSystemEvents",
@@ -46,8 +46,8 @@ async function logProcessGuardEvent($asai, opts) {
46
46
  }
47
47
  _chunkSMVZ3ZDJcjs.__name.call(void 0, logProcessGuardEvent, "logProcessGuardEvent");
48
48
  async function logSecurityConfigIntervention($asai, opts) {
49
- const identification = _chunk4E7Z5K5Ucjs.crc32.call(void 0, `${opts.section}|${opts.detail}`);
50
- return _chunk4E7Z5K5Ucjs.logIntervention.call(void 0, $asai, {
49
+ const identification = _chunkU2YJH2RWcjs.crc32.call(void 0, `${opts.section}|${opts.detail}`);
50
+ return _chunkU2YJH2RWcjs.logIntervention.call(void 0, $asai, {
51
51
  type: "SAFETY_PARAM",
52
52
  name: `Security config: ${opts.section}`,
53
53
  category: "ConfigurationChanges",
@@ -62,8 +62,8 @@ async function logSecurityConfigIntervention($asai, opts) {
62
62
  }
63
63
  _chunkSMVZ3ZDJcjs.__name.call(void 0, logSecurityConfigIntervention, "logSecurityConfigIntervention");
64
64
  async function logSessionTerminate($asai, opts) {
65
- const identification = _chunk4E7Z5K5Ucjs.crc32.call(void 0, `${opts.sessionId}|${opts.targetUs || ""}`);
66
- return _chunk4E7Z5K5Ucjs.logIntervention.call(void 0, $asai, {
65
+ const identification = _chunkU2YJH2RWcjs.crc32.call(void 0, `${opts.sessionId}|${opts.targetUs || ""}`);
66
+ return _chunkU2YJH2RWcjs.logIntervention.call(void 0, $asai, {
67
67
  type: "SAFETY_PARAM",
68
68
  name: `Session terminated: ${opts.sessionId}`,
69
69
  category: "AccessControl",
@@ -78,8 +78,8 @@ async function logSessionTerminate($asai, opts) {
78
78
  }
79
79
  _chunkSMVZ3ZDJcjs.__name.call(void 0, logSessionTerminate, "logSessionTerminate");
80
80
  async function logAccountPurge($asai, opts) {
81
- const identification = _chunk4E7Z5K5Ucjs.crc32.call(void 0, `purge|${opts.targetUs}`);
82
- return _chunk4E7Z5K5Ucjs.logIntervention.call(void 0, $asai, {
81
+ const identification = _chunkU2YJH2RWcjs.crc32.call(void 0, `purge|${opts.targetUs}`);
82
+ return _chunkU2YJH2RWcjs.logIntervention.call(void 0, $asai, {
83
83
  type: "SAFETY_PARAM",
84
84
  name: `Account purged: ${opts.targetUs}`,
85
85
  category: "ConfigurationChanges",
@@ -102,4 +102,4 @@ _chunkSMVZ3ZDJcjs.__name.call(void 0, logAccountPurge, "logAccountPurge");
102
102
 
103
103
 
104
104
  exports.logUserRbacChange = logUserRbacChange; exports.logProcessGuardEvent = logProcessGuardEvent; exports.logSecurityConfigIntervention = logSecurityConfigIntervention; exports.logSessionTerminate = logSessionTerminate; exports.logAccountPurge = logAccountPurge; exports.intervention_hooks_exports = intervention_hooks_exports;
105
- //# sourceMappingURL=chunk-RIRKIYET.cjs.map
105
+ //# sourceMappingURL=chunk-ARHPHWT5.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["d:\\Web\\Git\\asaicms-v1\\webserver\\src\\plugs\\asaihost-nodejs\\dist\\chunk-RIRKIYET.cjs"],"names":[],"mappings":"AAAA;AACE;AACA;AACF,wDAA6B;AAC7B;AACE;AACA;AACF,wDAA6B;AAC7B;AACA;AACA,IAAI,2BAA2B,EAAE,CAAC,CAAC;AACnC,wCAAQ,0BAA2B,EAAE;AACrC,EAAE,eAAe,EAAE,CAAC,EAAE,GAAG,eAAe;AACxC,EAAE,oBAAoB,EAAE,CAAC,EAAE,GAAG,oBAAoB;AAClD,EAAE,6BAA6B,EAAE,CAAC,EAAE,GAAG,6BAA6B;AACpE,EAAE,mBAAmB,EAAE,CAAC,EAAE,GAAG,mBAAmB;AAChD,EAAE,iBAAiB,EAAE,CAAC,EAAE,GAAG;AAC3B,CAAC,CAAC;AACF,MAAM,SAAS,iBAAiB,CAAC,KAAK,EAAE,IAAI,EAAE;AAC9C,EAAE,MAAM,eAAe,EAAE,qCAAK,IAAK,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,IAAI,CAAC,QAAQ,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;AACpF,EAAE,OAAO,+CAAe,KAAM,EAAE;AAChC,IAAI,IAAI,EAAE,cAAc;AACxB,IAAI,IAAI,EAAE,CAAC,mBAAmB,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,EAAA;AACA;AACA;AACA;AACA,EAAA;AACA,EAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,EAAA;AACA;AACA;AACA;AACA,EAAA;AACA,EAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,EAAA;AACA;AACA;AACA;AACA,EAAA;AACA,EAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,EAAA;AACA;AACA;AACA;AACA,EAAA;AACA,EAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,EAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","file":"D:\\Web\\Git\\asaicms-v1\\webserver\\src\\plugs\\asaihost-nodejs\\dist\\chunk-RIRKIYET.cjs","sourcesContent":[null]}
1
+ {"version":3,"sources":["d:\\Web\\Git\\asaicms-v1\\webserver\\src\\plugs\\asaihost-nodejs\\dist\\chunk-ARHPHWT5.cjs"],"names":[],"mappings":"AAAA;AACE;AACA;AACF,wDAA6B;AAC7B;AACE;AACA;AACF,wDAA6B;AAC7B;AACA;AACA,IAAI,2BAA2B,EAAE,CAAC,CAAC;AACnC,wCAAQ,0BAA2B,EAAE;AACrC,EAAE,eAAe,EAAE,CAAC,EAAE,GAAG,eAAe;AACxC,EAAE,oBAAoB,EAAE,CAAC,EAAE,GAAG,oBAAoB;AAClD,EAAE,6BAA6B,EAAE,CAAC,EAAE,GAAG,6BAA6B;AACpE,EAAE,mBAAmB,EAAE,CAAC,EAAE,GAAG,mBAAmB;AAChD,EAAE,iBAAiB,EAAE,CAAC,EAAE,GAAG;AAC3B,CAAC,CAAC;AACF,MAAM,SAAS,iBAAiB,CAAC,KAAK,EAAE,IAAI,EAAE;AAC9C,EAAE,MAAM,eAAe,EAAE,qCAAK,IAAK,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,IAAI,CAAC,QAAQ,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;AACpF,EAAE,OAAO,+CAAe,KAAM,EAAE;AAChC,IAAI,IAAI,EAAE,cAAc;AACxB,IAAI,IAAI,EAAE,CAAC,mBAAmB,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,EAAA;AACA;AACA;AACA;AACA,EAAA;AACA,EAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,EAAA;AACA;AACA;AACA;AACA,EAAA;AACA,EAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,EAAA;AACA;AACA;AACA;AACA,EAAA;AACA,EAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,EAAA;AACA;AACA;AACA;AACA,EAAA;AACA,EAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,EAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","file":"D:\\Web\\Git\\asaicms-v1\\webserver\\src\\plugs\\asaihost-nodejs\\dist\\chunk-ARHPHWT5.cjs","sourcesContent":[null]}
@@ -922,4 +922,4 @@ export {
922
922
  isPasswordExpired,
923
923
  getPublicSecurityConfig
924
924
  };
925
- //# sourceMappingURL=chunk-A5CDJGJI.es.js.map
925
+ //# sourceMappingURL=chunk-BOIRAQXE.es.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/sysserver/api/login/store/user-db.ts","../src/infra/security-policy.ts","../src/sysserver/api/login/service/user-level-config.ts","../src/sysserver/api/login/service/route-defaults.ts"],"sourcesContent":["import type Idb from '../../../db/src/type';\r\nimport type { DbType } from '../../../db/db';\r\nimport {\r\n\tasRows,\r\n\tgetDataServer,\r\n\tnormalizeStoreOpt,\r\n\tqNum,\r\n\tqStr,\r\n\treadJsonBlob,\r\n\tresolveStoreConfig,\r\n\twriteJsonBlob,\r\n} from '../../../db/data-store';\r\n\r\nexport const USER_FIELDS = [\r\n\t'id',\r\n\t'us',\r\n\t'email',\r\n\t'passHash',\r\n\t'passSalt',\r\n\t'lv',\r\n\t'role',\r\n\t'status',\r\n\t'failCount',\r\n\t'lockedUntil',\r\n\t'mustChangePassword',\r\n\t'passwordChangedAt',\r\n\t'passHistory',\r\n\t'createdAt',\r\n\t'updatedAt',\r\n] as const;\r\n\r\nexport const SESSION_FIELDS = ['id', 'us', 'ip', 'createdAt', 'expiresAt', 'lastActivityAt', 'pri', 'pub'] as const;\r\n\r\nconst FILE_USERS = 'users.json';\r\nconst FILE_SESSIONS = 'sessions.json';\r\nconst TABLE_USERS = 'auth_users';\r\nconst TABLE_SESSIONS = 'auth_sessions';\r\nconst SCHEMA_PROBE_ID = '__schema_probe__';\r\n\r\nconst STORE_TYPE_LABELS: Record<string, string> = {\r\n\tfile: 'File',\r\n\tsqlite: 'SQLite',\r\n\tmysql: 'MySQL',\r\n};\r\n\r\nconst USER_TABLE_ENSURED = '_userStoreTablesEnsured';\r\nlet ensureUserTablesPromise: Promise<void> | null = null;\r\n\r\nexport interface UserStoreDbConfig {\r\n\ttype: DbType;\r\n\topt: Record<string, unknown>;\r\n}\r\n\r\nexport function getUserStoreConfig($asai: any): UserStoreDbConfig {\r\n\tconst resolved = resolveStoreConfig($asai, 'user');\r\n\tconst type = resolved.type;\r\n\treturn { type, opt: normalizeStoreOpt('user', type, resolved.opt) };\r\n}\r\n\r\n/** 解析后的用户存储元信息(供 API / 测试 / 运维展示) */\r\nexport function getUserStoreMeta($asai: any): Record<string, unknown> {\r\n\tconst { type, opt } = getUserStoreConfig($asai);\r\n\tconst meta: Record<string, unknown> = {\r\n\t\ttype,\r\n\t\tlabel: STORE_TYPE_LABELS[type] || type,\r\n\t\tmode: type === 'file' ? 'json-blob' : type,\r\n\t\tcreate: opt.create ?? 1,\r\n\t};\r\n\tif (type === 'file') {\r\n\t\tmeta.dir = opt.dir;\r\n\t\tmeta.ext = opt.ext || '.json';\r\n\t\tmeta.location = String(opt.dir || '');\r\n\t} else if (type === 'sqlite') {\r\n\t\tmeta.database = opt.database;\r\n\t\tmeta.location = String(opt.database || '');\r\n\t} else if (type === 'mysql') {\r\n\t\tmeta.host = opt.host;\r\n\t\tmeta.database = opt.database;\r\n\t\tmeta.location = `${opt.host || '127.0.0.1'}/${opt.database || 'asai'}`;\r\n\t}\r\n\treturn meta;\r\n}\r\n\r\nfunction isTableMissing(err: unknown): boolean {\r\n\tconst msg = String((err as { message?: string })?.message || err || '');\r\n\treturn msg.includes('no such table') || msg.includes(\"doesn't exist\");\r\n}\r\n\r\nfunction sqlLiteralForField(field: string, dbType: DbType, marker?: string): string {\r\n\tif (field === 'id' && marker) return qStr(marker, dbType);\r\n\tif (\r\n\t\t[\r\n\t\t\t'lv',\r\n\t\t\t'failCount',\r\n\t\t\t'mustChangePassword',\r\n\t\t\t'passwordChangedAt',\r\n\t\t\t'createdAt',\r\n\t\t\t'updatedAt',\r\n\t\t\t'lockedUntil',\r\n\t\t\t'expiresAt',\r\n\t\t\t'lastActivityAt',\r\n\t\t].includes(field)\r\n\t) {\r\n\t\treturn qNum(0);\r\n\t}\r\n\treturn qStr('', dbType);\r\n}\r\n\r\nasync function ensureSqlTable(\r\n\tdb: { sqlDb(sql: Idb): Promise<unknown> },\r\n\ttable: string,\r\n\tfields: readonly string[],\r\n\tdbType: DbType,\r\n\tmarkerField: 'id' | 'us',\r\n): Promise<void> {\r\n\ttry {\r\n\t\tawait db.sqlDb({ type: 'select', table, field: ['id'], limit: 1 });\r\n\t\treturn;\r\n\t} catch (err) {\r\n\t\tif (!isTableMissing(err)) throw err;\r\n\t}\r\n\tconst marker = SCHEMA_PROBE_ID;\r\n\tconst valueRow = fields.map((f) => sqlLiteralForField(f, dbType, f === 'id' ? marker : undefined));\r\n\tawait db.sqlDb({ type: 'insert', table, field: [...fields], value: [valueRow] });\r\n\tawait db.sqlDb({\r\n\t\ttype: 'delete',\r\n\t\ttable,\r\n\t\twhere: [[markerField, '=', qStr(marker, dbType)]],\r\n\t});\r\n}\r\n\r\n/** 确保 auth_users / auth_sessions 表存在(SQLite/MySQL 首次 SELECT 不会自动建表) */\r\nexport async function ensureUserStoreTables($asai: any): Promise<void> {\r\n\tif ($asai[USER_TABLE_ENSURED]) return;\r\n\tconst cfg = getUserStoreConfig($asai);\r\n\tif (cfg.type === 'file') {\r\n\t\t$asai[USER_TABLE_ENSURED] = true;\r\n\t\treturn;\r\n\t}\r\n\tif (!ensureUserTablesPromise) {\r\n\t\tensureUserTablesPromise = (async () => {\r\n\t\t\tconst db = getUserDataServer($asai);\r\n\t\t\tawait ensureSqlTable(db, TABLE_USERS, USER_FIELDS, cfg.type, 'id');\r\n\t\t\tawait ensureSqlTable(db, TABLE_SESSIONS, SESSION_FIELDS, cfg.type, 'id');\r\n\t\t\t$asai[USER_TABLE_ENSURED] = true;\r\n\t\t})();\r\n\t}\r\n\ttry {\r\n\t\tawait ensureUserTablesPromise;\r\n\t} catch (err) {\r\n\t\tensureUserTablesPromise = null;\r\n\t\tthrow err;\r\n\t}\r\n}\r\n\r\nasync function beforeUserStoreOp($asai: any): Promise<void> {\r\n\tif (getUserStoreConfig($asai).type !== 'file') {\r\n\t\tawait ensureUserStoreTables($asai);\r\n\t}\r\n}\r\n\r\nexport function getUserDataServer($asai: any): { sqlDb(sql: Idb): Promise<unknown> } {\r\n\treturn getDataServer($asai, 'user');\r\n}\r\n\r\nexport function isFileStore($asai: any): boolean {\r\n\treturn getUserStoreConfig($asai).type === 'file';\r\n}\r\n\r\nfunction rowToRecord<T extends Record<string, unknown>>(row: Record<string, unknown>, numericKeys: string[]): T {\r\n\tconst out: Record<string, unknown> = { ...row };\r\n\tfor (const key of numericKeys) {\r\n\t\tif (out[key] != null && out[key] !== '') out[key] = Number(out[key]);\r\n\t}\r\n\tif (out.lockedUntil === '' || out.lockedUntil == null) delete out.lockedUntil;\r\n\tif (out.email === '') delete out.email;\r\n\treturn out as T;\r\n}\r\n\r\nasync function readJsonArray(db: { sqlDb(sql: Idb): Promise<unknown> }, filename: string): Promise<Record<string, unknown>[]> {\r\n\treturn readJsonBlob(db, filename);\r\n}\r\n\r\nasync function writeJsonArray(\r\n\tdb: { sqlDb(sql: Idb): Promise<unknown> },\r\n\tfilename: string,\r\n\tdata: Record<string, unknown>[],\r\n): Promise<void> {\r\n\tawait writeJsonBlob(db, filename, data);\r\n}\r\n\r\nexport async function dbListUsers($asai: any): Promise<Record<string, unknown>[]> {\r\n\tconst db = getUserDataServer($asai);\r\n\tconst cfg = getUserStoreConfig($asai);\r\n\tif (cfg.type === 'file') {\r\n\t\treturn readJsonArray(db, FILE_USERS);\r\n\t}\r\n\tawait beforeUserStoreOp($asai);\r\n\tconst res = await db.sqlDb({ type: 'select', table: TABLE_USERS, field: [...USER_FIELDS] });\r\n\treturn asRows(res).map((r) => rowToRecord(r, ['lv', 'failCount', 'lockedUntil', 'mustChangePassword', 'passwordChangedAt', 'createdAt', 'updatedAt']));\r\n}\r\n\r\nexport async function dbFindUser($asai: any, field: 'us' | 'id', value: string): Promise<Record<string, unknown> | null> {\r\n\tconst db = getUserDataServer($asai);\r\n\tconst cfg = getUserStoreConfig($asai);\r\n\tif (cfg.type === 'file') {\r\n\t\tconst users = await readJsonArray(db, FILE_USERS);\r\n\t\treturn users.find((u) => u[field] === value) || null;\r\n\t}\r\n\tawait beforeUserStoreOp($asai);\r\n\tconst res = await db.sqlDb({\r\n\t\ttype: 'select',\r\n\t\ttable: TABLE_USERS,\r\n\t\tfield: [...USER_FIELDS],\r\n\t\twhere: [[field, '=', qStr(value, cfg.type)]],\r\n\t\tlimit: 1,\r\n\t});\r\n\tconst rows = asRows(res);\r\n\treturn rows.length ? rowToRecord(rows[0], ['lv', 'failCount', 'lockedUntil', 'mustChangePassword', 'passwordChangedAt', 'createdAt', 'updatedAt']) : null;\r\n}\r\n\r\nexport async function dbCreateUser($asai: any, user: Record<string, unknown>): Promise<Record<string, unknown>> {\r\n\tconst db = getUserDataServer($asai);\r\n\tconst cfg = getUserStoreConfig($asai);\r\n\tif (cfg.type === 'file') {\r\n\t\tconst users = await readJsonArray(db, FILE_USERS);\r\n\t\tusers.push(user);\r\n\t\tawait writeJsonArray(db, FILE_USERS, users);\r\n\t\treturn user;\r\n\t}\r\n\tawait beforeUserStoreOp($asai);\r\n\tawait db.sqlDb({\r\n\t\ttype: 'insert',\r\n\t\ttable: TABLE_USERS,\r\n\t\tfield: [...USER_FIELDS],\r\n\t\tvalue: [\r\n\t\t\tUSER_FIELDS.map((f) => {\r\n\t\t\t\tconst v = user[f];\r\n\t\t\t\tif (typeof v === 'number') return qNum(v);\r\n\t\t\t\treturn qStr(v == null ? '' : String(v), cfg.type);\r\n\t\t\t}),\r\n\t\t],\r\n\t});\r\n\treturn user;\r\n}\r\n\r\nexport async function dbUpdateUser($asai: any, us: string, patch: Record<string, unknown>): Promise<Record<string, unknown> | null> {\r\n\tconst existing = await dbFindUser($asai, 'us', us);\r\n\tif (!existing) return null;\r\n\tconst merged = { ...existing, ...patch, updatedAt: Date.now() };\r\n\tconst db = getUserDataServer($asai);\r\n\tconst cfg = getUserStoreConfig($asai);\r\n\tif (cfg.type === 'file') {\r\n\t\tconst users = await readJsonArray(db, FILE_USERS);\r\n\t\tconst idx = users.findIndex((u) => u.us === us);\r\n\t\tif (idx < 0) return null;\r\n\t\tusers[idx] = merged;\r\n\t\tawait writeJsonArray(db, FILE_USERS, users);\r\n\t\treturn merged;\r\n\t}\r\n\tawait beforeUserStoreOp($asai);\r\n\tconst sets: Idb['set'] = [];\r\n\tfor (const [key, val] of Object.entries(patch)) {\r\n\t\tif (val === undefined) continue;\r\n\t\tif (typeof val === 'number') sets!.push([key, val]);\r\n\t\telse sets!.push([key, val == null ? '' : String(val)]);\r\n\t}\r\n\tsets!.push(['updatedAt', merged.updatedAt as number]);\r\n\tawait db.sqlDb({\r\n\t\ttype: 'update',\r\n\t\ttable: TABLE_USERS,\r\n\t\tset: sets,\r\n\t\twhere: [['us', '=', qStr(us, cfg.type)]],\r\n\t});\r\n\treturn merged;\r\n}\r\n\r\nexport async function dbListSessions($asai: any): Promise<Record<string, unknown>[]> {\r\n\tconst db = getUserDataServer($asai);\r\n\tconst cfg = getUserStoreConfig($asai);\r\n\tif (cfg.type === 'file') {\r\n\t\treturn readJsonArray(db, FILE_SESSIONS);\r\n\t}\r\n\tawait beforeUserStoreOp($asai);\r\n\tconst res = await db.sqlDb({ type: 'select', table: TABLE_SESSIONS, field: [...SESSION_FIELDS] });\r\n\treturn asRows(res).map((r) => rowToRecord(r, ['createdAt', 'expiresAt', 'lastActivityAt']));\r\n}\r\n\r\nexport async function dbWriteSessions($asai: any, sessions: Record<string, unknown>[]): Promise<void> {\r\n\tconst db = getUserDataServer($asai);\r\n\tconst cfg = getUserStoreConfig($asai);\r\n\tif (cfg.type === 'file') {\r\n\t\tawait writeJsonArray(db, FILE_SESSIONS, sessions);\r\n\t\treturn;\r\n\t}\r\n\tawait beforeUserStoreOp($asai);\r\n\tconst existing = await dbListSessions($asai);\r\n\tfor (const s of existing) {\r\n\t\tawait db.sqlDb({\r\n\t\t\ttype: 'delete',\r\n\t\t\ttable: TABLE_SESSIONS,\r\n\t\t\twhere: [['id', '=', qStr(String(s.id), cfg.type)]],\r\n\t\t});\r\n\t}\r\n\tfor (const s of sessions) {\r\n\t\tawait db.sqlDb({\r\n\t\t\ttype: 'insert',\r\n\t\t\ttable: TABLE_SESSIONS,\r\n\t\t\tfield: [...SESSION_FIELDS],\r\n\t\t\tvalue: [\r\n\t\t\t\tSESSION_FIELDS.map((f) => {\r\n\t\t\t\t\tconst v = s[f];\r\n\t\t\t\t\tif (typeof v === 'number') return qNum(v);\r\n\t\t\t\t\treturn qStr(v == null ? '' : String(v), cfg.type);\r\n\t\t\t\t}),\r\n\t\t\t],\r\n\t\t});\r\n\t}\r\n}\r\n\r\nexport async function dbAddSession($asai: any, session: Record<string, unknown>): Promise<void> {\r\n\tconst db = getUserDataServer($asai);\r\n\tconst cfg = getUserStoreConfig($asai);\r\n\tif (cfg.type === 'file') {\r\n\t\tconst sessions = await readJsonArray(db, FILE_SESSIONS);\r\n\t\tsessions.push(session);\r\n\t\tawait writeJsonArray(db, FILE_SESSIONS, sessions);\r\n\t\treturn;\r\n\t}\r\n\tawait beforeUserStoreOp($asai);\r\n\tawait db.sqlDb({\r\n\t\ttype: 'insert',\r\n\t\ttable: TABLE_SESSIONS,\r\n\t\tfield: [...SESSION_FIELDS],\r\n\t\tvalue: [\r\n\t\t\tSESSION_FIELDS.map((f) => {\r\n\t\t\t\tconst v = session[f];\r\n\t\t\t\tif (typeof v === 'number') return qNum(v);\r\n\t\t\t\treturn qStr(v == null ? '' : String(v), cfg.type);\r\n\t\t\t}),\r\n\t\t],\r\n\t});\r\n}\r\n\r\nexport async function dbRemoveSession($asai: any, sessionId: string): Promise<void> {\r\n\tconst db = getUserDataServer($asai);\r\n\tconst cfg = getUserStoreConfig($asai);\r\n\tif (cfg.type === 'file') {\r\n\t\tconst sessions = await readJsonArray(db, FILE_SESSIONS);\r\n\t\tawait writeJsonArray(\r\n\t\t\tdb,\r\n\t\t\tFILE_SESSIONS,\r\n\t\t\tsessions.filter((s) => s.id !== sessionId),\r\n\t\t);\r\n\t\treturn;\r\n\t}\r\n\tawait beforeUserStoreOp($asai);\r\n\tawait db.sqlDb({\r\n\t\ttype: 'delete',\r\n\t\ttable: TABLE_SESSIONS,\r\n\t\twhere: [['id', '=', qStr(sessionId, cfg.type)]],\r\n\t});\r\n}\r\n\r\nexport async function dbRemoveSessionsByUser($asai: any, us: string): Promise<void> {\r\n\tconst db = getUserDataServer($asai);\r\n\tconst cfg = getUserStoreConfig($asai);\r\n\tif (cfg.type === 'file') {\r\n\t\tconst sessions = await readJsonArray(db, FILE_SESSIONS);\r\n\t\tawait writeJsonArray(\r\n\t\t\tdb,\r\n\t\t\tFILE_SESSIONS,\r\n\t\t\tsessions.filter((s) => s.us !== us),\r\n\t\t);\r\n\t\treturn;\r\n\t}\r\n\tawait beforeUserStoreOp($asai);\r\n\tawait db.sqlDb({\r\n\t\ttype: 'delete',\r\n\t\ttable: TABLE_SESSIONS,\r\n\t\twhere: [['us', '=', qStr(us, cfg.type)]],\r\n\t});\r\n}\r\n\r\nexport async function dbDeleteUser($asai: any, us: string): Promise<boolean> {\r\n\tconst existing = await dbFindUser($asai, 'us', us);\r\n\tif (!existing) return false;\r\n\tconst db = getUserDataServer($asai);\r\n\tconst cfg = getUserStoreConfig($asai);\r\n\tawait dbRemoveSessionsByUser($asai, us);\r\n\tif (cfg.type === 'file') {\r\n\t\tconst users = await readJsonArray(db, FILE_USERS);\r\n\t\tconst next = users.filter((u) => u.us !== us);\r\n\t\tif (next.length === users.length) return false;\r\n\t\tawait writeJsonArray(db, FILE_USERS, next);\r\n\t\treturn true;\r\n\t}\r\n\tawait beforeUserStoreOp($asai);\r\n\tawait db.sqlDb({\r\n\t\ttype: 'delete',\r\n\t\ttable: TABLE_USERS,\r\n\t\twhere: [['us', '=', qStr(us, cfg.type)]],\r\n\t});\r\n\treturn true;\r\n}\r\n","/**\r\n * IEC 62443-4-2 — 可配置安全策略(CR 1.7 / 1.12 / 2.1 / 2.5)\r\n */\r\nimport { createHash } from 'node:crypto';\r\nimport { toPublicUserLevels } from '../sysserver/api/login/service/user-level-config';\r\nimport { getUserStoreMeta } from '../sysserver/api/login/store/user-db';\r\n\r\nexport interface PasswordPolicy {\r\n\tminLength: number;\r\n\trequireUpper: boolean;\r\n\trequireLower: boolean;\r\n\trequireDigit: boolean;\r\n\trequireSpecial: boolean;\r\n\tmaxAgeDays: number;\r\n\thistoryCount: number;\r\n}\r\n\r\nexport interface RoleDef {\r\n\tname: string;\r\n\tminLv: number;\r\n\tpermissions: string[];\r\n}\r\n\r\nconst DEFAULT_POLICY: PasswordPolicy = {\r\n\tminLength: 8,\r\n\trequireUpper: false,\r\n\trequireLower: true,\r\n\trequireDigit: true,\r\n\trequireSpecial: false,\r\n\tmaxAgeDays: 0,\r\n\thistoryCount: 0,\r\n};\r\n\r\nconst DEFAULT_ROLES: RoleDef[] = [\r\n\t{ name: 'viewer', minLv: 0, permissions: ['read'] },\r\n\t{ name: 'operator', minLv: 3, permissions: ['read', 'operate'] },\r\n\t{ name: 'engineer', minLv: 5, permissions: ['read', 'operate', 'audit'] },\r\n\t{ name: 'admin', minLv: 7, permissions: ['read', 'operate', 'audit', 'admin'] },\r\n\t{ name: 'developer', minLv: 9, permissions: ['read', 'operate', 'audit', 'admin', 'develop'] },\r\n\t{ name: 'superadmin', minLv: 99, permissions: ['read', 'operate', 'audit', 'admin', 'develop', 'super'] },\r\n];\r\n\r\nexport function getSecurityBlock($asai: any): Record<string, unknown> {\r\n\treturn ($asai?.hostconfig?.security as Record<string, unknown>) || {};\r\n}\r\n\r\nexport function getLoginBanner($asai: any): { enabled: boolean; text: string } {\r\n\tconst sec = getSecurityBlock($asai);\r\n\tconst banner = (sec.banner as Record<string, unknown>) || {};\r\n\treturn {\r\n\t\tenabled: banner.enabled === 1 || banner.enabled === true,\r\n\t\ttext: String(banner.text || ''),\r\n\t};\r\n}\r\n\r\nexport function getPasswordPolicy($asai: any): PasswordPolicy {\r\n\tconst sec = getSecurityBlock($asai);\r\n\tconst p = (sec.passwordPolicy as Record<string, unknown>) || {};\r\n\tconst minFromLegacy = Number(sec.passwordMinLength ?? DEFAULT_POLICY.minLength);\r\n\treturn {\r\n\t\tminLength: Number(p.minLength ?? minFromLegacy) || DEFAULT_POLICY.minLength,\r\n\t\trequireUpper: p.requireUpper === 1 || p.requireUpper === true,\r\n\t\trequireLower: p.requireLower !== 0 && p.requireLower !== false,\r\n\t\trequireDigit: p.requireDigit !== 0 && p.requireDigit !== false,\r\n\t\trequireSpecial: p.requireSpecial === 1 || p.requireSpecial === true,\r\n\t\tmaxAgeDays: Number(p.maxAgeDays ?? 0) || 0,\r\n\t\thistoryCount: Number(p.historyCount ?? 0) || 0,\r\n\t};\r\n}\r\n\r\nexport function getSessionIdleMinutes($asai: any): number {\r\n\tconst sec = getSecurityBlock($asai);\r\n\tconst v = sec.sessionIdleMinutes;\r\n\treturn v == null || v === 0 ? 0 : Number(v);\r\n}\r\n\r\nexport function getRoleDefinitions($asai: any): RoleDef[] {\r\n\tconst sec = getSecurityBlock($asai);\r\n\tconst raw = sec.roles;\r\n\tif (!Array.isArray(raw) || !raw.length) return DEFAULT_ROLES;\r\n\treturn raw.map((r: Record<string, unknown>) => ({\r\n\t\tname: String(r.name || 'role'),\r\n\t\tminLv: Number(r.minLv ?? 0),\r\n\t\tpermissions: Array.isArray(r.permissions) ? r.permissions.map(String) : [],\r\n\t}));\r\n}\r\n\r\nexport function resolveRoleForLevel($asai: any, lv: number): RoleDef {\r\n\tconst roles = getRoleDefinitions($asai);\r\n\tlet best = roles[0];\r\n\tfor (const r of roles) {\r\n\t\tif (lv >= r.minLv && r.minLv >= (best?.minLv ?? -1)) best = r;\r\n\t}\r\n\treturn best || DEFAULT_ROLES[0];\r\n}\r\n\r\nexport function hashPasswordForHistory(password: string): string {\r\n\treturn createHash('sha256').update(password).digest('hex');\r\n}\r\n\r\nexport function validatePasswordWithPolicy(password: string, policy: PasswordPolicy): string | null {\r\n\tif (!password || typeof password !== 'string') return 'PASSWORD_REQUIRED';\r\n\tif (password.length < policy.minLength) return 'PASSWORD_TOO_SHORT';\r\n\tif (policy.requireLower && !/[a-z]/.test(password)) return 'PASSWORD_WEAK';\r\n\tif (policy.requireUpper && !/[A-Z]/.test(password)) return 'PASSWORD_WEAK';\r\n\tif (policy.requireDigit && !/[0-9]/.test(password)) return 'PASSWORD_WEAK';\r\n\tif (policy.requireSpecial && !/[^a-zA-Z0-9]/.test(password)) return 'PASSWORD_WEAK';\r\n\treturn null;\r\n}\r\n\r\nexport function parsePassHistory(raw: unknown): string[] {\r\n\tif (!raw) return [];\r\n\tif (Array.isArray(raw)) return raw.map(String);\r\n\tif (typeof raw === 'string' && raw.startsWith('[')) {\r\n\t\ttry {\r\n\t\t\tconst arr = JSON.parse(raw);\r\n\t\t\treturn Array.isArray(arr) ? arr.map(String) : [];\r\n\t\t} catch {\r\n\t\t\treturn [];\r\n\t\t}\r\n\t}\r\n\treturn [];\r\n}\r\n\r\nexport function isPasswordInHistory(password: string, history: string[]): boolean {\r\n\tconst h = hashPasswordForHistory(password);\r\n\treturn history.includes(h);\r\n}\r\n\r\nexport function isPasswordExpired(passwordChangedAt: number | undefined, maxAgeDays: number): boolean {\r\n\tif (!maxAgeDays || maxAgeDays <= 0) return false;\r\n\tif (!passwordChangedAt) return false;\r\n\treturn Date.now() - passwordChangedAt > maxAgeDays * 86400000;\r\n}\r\n\r\nexport function getPublicSecurityConfig($asai: any, lang = 'zh-CN') {\r\n\tconst policy = getPasswordPolicy($asai);\r\n\tconst banner = getLoginBanner($asai);\r\n\treturn {\r\n\t\tbanner,\r\n\t\tpasswordPolicy: {\r\n\t\t\tminLength: policy.minLength,\r\n\t\t\trequireUpper: policy.requireUpper,\r\n\t\t\trequireLower: policy.requireLower,\r\n\t\t\trequireDigit: policy.requireDigit,\r\n\t\t\trequireSpecial: policy.requireSpecial,\r\n\t\t},\r\n\t\tsessionIdleMinutes: getSessionIdleMinutes($asai),\r\n\t\troles: getRoleDefinitions($asai).map((r) => ({ name: r.name, minLv: r.minLv })),\r\n\t\tuserLevels: toPublicUserLevels($asai, lang),\r\n\t\tallowRegister: getSecurityBlock($asai).allowRegister !== 0,\r\n\t\tuserStore: getUserStoreMeta($asai),\r\n\t};\r\n}\r\n","/**\r\n * 用户等级与名称 — 管理员可自定义(持久化至 user store _meta/user-levels.json)\r\n */\r\nimport fs from 'node:fs/promises';\r\nimport path from 'node:path';\r\nimport { validatePasswordWithPolicy, getPasswordPolicy } from '../../../../infra/security-policy';\r\nimport { getUserStoreConfig } from '../store/user-db';\r\nimport {\r\n\tloadRouteCatalogAsRights,\r\n\tmergeRouteRights,\r\n\tnormalizeRouteRight,\r\n\troutesFromLegacyRights,\r\n\ttype RouteRight,\r\n} from './route-defaults';\r\n\r\nexport type { RouteRight };\r\n\r\nexport interface UserLevelDef {\r\n\tlv: number;\r\n\tkey: string;\r\n\tname: string;\r\n\tnameEn?: string;\r\n}\r\n\r\nexport interface PermissionThresholds {\r\n\tlogRead: number;\r\n\tadminRead: number;\r\n\tadminWrite: number;\r\n}\r\n\r\nexport interface UserLevelConfig {\r\n\tlevels: UserLevelDef[];\r\n\tthresholds: PermissionThresholds;\r\n\trouteRights?: RouteRight[];\r\n\t/** 管理员重置用户密码时的默认密码(持久化,不含明文回传至公开 API) */\r\n\tdefaultResetPassword?: string;\r\n\tupdatedAt?: number;\r\n\tupdatedBy?: string;\r\n}\r\n\r\nexport const DEFAULT_RESET_PASSWORD = 'Asai@1234';\r\n\r\nexport const DEFAULT_LEVELS: UserLevelDef[] = [\r\n\t{ lv: 0, key: 'guest', name: '普通用户', nameEn: 'Guest' },\r\n\t{ lv: 3, key: 'operator', name: '操作员', nameEn: 'Operator' },\r\n\t{ lv: 5, key: 'engineer', name: '工程师', nameEn: 'Engineer' },\r\n\t{ lv: 7, key: 'admin', name: '管理员', nameEn: 'Administrator' },\r\n\t{ lv: 9, key: 'developer', name: '开发者', nameEn: 'Developer' },\r\n\t{ lv: 99, key: 'superadmin', name: '超级管理员', nameEn: 'Super Administrator' },\r\n];\r\n\r\nexport const DEFAULT_THRESHOLDS: PermissionThresholds = {\r\n\tlogRead: 3,\r\n\tadminRead: 7,\r\n\tadminWrite: 9,\r\n};\r\n\r\nconst META_FILE = '_meta/user-levels.json';\r\n\r\nfunction configPath($asai: any): string {\r\n\tconst dir = String(getUserStoreConfig($asai).opt?.dir || 'webdata/webdb/users/');\r\n\treturn path.resolve(dir, META_FILE);\r\n}\r\n\r\nfunction fromHostLevels($asai: any): UserLevelDef[] | null {\r\n\tconst raw = $asai?.hostconfig?.security?.userLevels;\r\n\tif (!Array.isArray(raw) || !raw.length) return null;\r\n\tconst levels: UserLevelDef[] = [];\r\n\tfor (const item of raw) {\r\n\t\tif (!item || typeof item !== 'object') continue;\r\n\t\tconst lv = Number((item as any).lv);\r\n\t\tconst key = String((item as any).key || '').trim();\r\n\t\tconst name = String((item as any).name || (item as any).label || '').trim();\r\n\t\tif (!Number.isFinite(lv) || !key || !name) continue;\r\n\t\tlevels.push({\r\n\t\t\tlv,\r\n\t\t\tkey,\r\n\t\t\tname,\r\n\t\t\tnameEn: (item as any).nameEn ? String((item as any).nameEn) : undefined,\r\n\t\t});\r\n\t}\r\n\treturn levels.length ? levels.sort((a, b) => a.lv - b.lv) : null;\r\n}\r\n\r\nfunction fromHostThresholds($asai: any): PermissionThresholds {\r\n\tconst t = $asai?.hostconfig?.security?.permissionThresholds;\r\n\tif (!t || typeof t !== 'object') return { ...DEFAULT_THRESHOLDS };\r\n\treturn {\r\n\t\tlogRead: Number(t.logRead ?? DEFAULT_THRESHOLDS.logRead),\r\n\t\tadminRead: Number(t.adminRead ?? DEFAULT_THRESHOLDS.adminRead),\r\n\t\tadminWrite: Number(t.adminWrite ?? DEFAULT_THRESHOLDS.adminWrite),\r\n\t};\r\n}\r\n\r\nexport function getDefaultRouteRights($asai: any): RouteRight[] {\r\n\tlet base = loadRouteCatalogAsRights($asai);\r\n\tif (!base.length) {\r\n\t\tconst legacy = $asai?.hostconfig?.security?.routerRights;\r\n\t\tif (legacy && typeof legacy === 'object') {\r\n\t\t\tbase = routesFromLegacyRights(legacy);\r\n\t\t}\r\n\t}\r\n\tconst fromHost = $asai?.hostconfig?.security?.routeRights;\r\n\tif (Array.isArray(fromHost) && fromHost.length) {\r\n\t\tconst parsed: RouteRight[] = [];\r\n\t\tfor (const item of fromHost) {\r\n\t\t\tconst row = normalizeRouteRight(item);\r\n\t\t\tif (row) parsed.push(row);\r\n\t\t}\r\n\t\tif (parsed.length) base = mergeRouteRights(base, parsed);\r\n\t}\r\n\tconst legacy = $asai?.hostconfig?.security?.routerRights;\r\n\tif (legacy && typeof legacy === 'object' && base.length) {\r\n\t\tbase = mergeRouteRights(base, routesFromLegacyRights(legacy));\r\n\t}\r\n\treturn base;\r\n}\r\n\r\nexport function getDefaultUserLevelConfig($asai: any): UserLevelConfig {\r\n\treturn {\r\n\t\tlevels: fromHostLevels($asai) || DEFAULT_LEVELS.map((l) => ({ ...l })),\r\n\t\tthresholds: fromHostThresholds($asai),\r\n\t\trouteRights: getDefaultRouteRights($asai),\r\n\t};\r\n}\r\n\r\nfunction normalizeLevel(item: unknown): UserLevelDef | null {\r\n\tif (!item || typeof item !== 'object') return null;\r\n\tconst lv = Number((item as any).lv);\r\n\tconst key = String((item as any).key || '').trim().slice(0, 32);\r\n\tconst name = String((item as any).name || '').trim().slice(0, 64);\r\n\tif (!Number.isFinite(lv) || lv < 0 || !key || !name) return null;\r\n\treturn {\r\n\t\tlv: Math.floor(lv),\r\n\t\tkey,\r\n\t\tname,\r\n\t\tnameEn: (item as any).nameEn ? String((item as any).nameEn).trim().slice(0, 64) : undefined,\r\n\t};\r\n}\r\n\r\nexport function normalizeUserLevelConfig(input: Partial<UserLevelConfig>, $asai: any): UserLevelConfig {\r\n\tconst base = getDefaultUserLevelConfig($asai);\r\n\tconst synced = getUserLevelConfigSync($asai);\r\n\tconst levelBase = synced.levels?.length ? synced : base;\r\n\tconst levels: UserLevelDef[] = [];\r\n\tconst seenLv = new Set<number>();\r\n\tconst seenKey = new Set<string>();\r\n\tif (Array.isArray(input.levels) && input.levels.length) {\r\n\t\tfor (const raw of input.levels) {\r\n\t\t\tconst row = normalizeLevel(raw);\r\n\t\t\tif (!row || seenLv.has(row.lv) || seenKey.has(row.key)) continue;\r\n\t\t\tseenLv.add(row.lv);\r\n\t\t\tseenKey.add(row.key);\r\n\t\t\tlevels.push(row);\r\n\t\t}\r\n\t} else {\r\n\t\tlevels.push(...levelBase.levels.map((l) => ({ ...l })));\r\n\t}\r\n\tif (!levels.some((l) => l.lv === 0)) {\r\n\t\tlevels.unshift({ lv: 0, key: 'guest', name: '普通用户', nameEn: 'Guest' });\r\n\t}\r\n\tlevels.sort((a, b) => a.lv - b.lv);\r\n\r\n\tconst th: Partial<PermissionThresholds> = input.thresholds || {};\r\n\tconst thresholds: PermissionThresholds = {\r\n\t\tlogRead: Number.isFinite(Number(th.logRead)) ? Number(th.logRead) : base.thresholds.logRead,\r\n\t\tadminRead: Number.isFinite(Number(th.adminRead)) ? Number(th.adminRead) : base.thresholds.adminRead,\r\n\t\tadminWrite: Number.isFinite(Number(th.adminWrite)) ? Number(th.adminWrite) : base.thresholds.adminWrite,\r\n\t};\r\n\r\n\tconst syncedPwd = synced.defaultResetPassword;\r\n\tconst inputPwd = typeof input.defaultResetPassword === 'string' ? input.defaultResetPassword.trim() : '';\r\n\tconst defaultResetPassword = inputPwd || syncedPwd || DEFAULT_RESET_PASSWORD;\r\n\r\n\treturn {\r\n\t\tlevels,\r\n\t\tthresholds,\r\n\t\trouteRights: normalizeRouteRightsList(input.routeRights, base.routeRights || getDefaultRouteRights($asai)),\r\n\t\tdefaultResetPassword,\r\n\t\tupdatedAt: input.updatedAt,\r\n\t\tupdatedBy: input.updatedBy,\r\n\t};\r\n}\r\n\r\nexport function getDefaultResetPassword($asai: any): string {\r\n\tconst cfg = getUserLevelConfigSync($asai);\r\n\tconst pwd = String(cfg.defaultResetPassword || '').trim();\r\n\treturn pwd || DEFAULT_RESET_PASSWORD;\r\n}\r\n\r\nfunction normalizeRouteRightsList(raw: unknown, fallback: RouteRight[]): RouteRight[] {\r\n\tif (!Array.isArray(raw) || !raw.length) return fallback.map((r) => ({ ...r }));\r\n\tconst parsed: RouteRight[] = [];\r\n\tconst seen = new Set<string>();\r\n\tfor (const item of raw) {\r\n\t\tconst row = normalizeRouteRight(item);\r\n\t\tif (!row || seen.has(row.route)) continue;\r\n\t\tseen.add(row.route);\r\n\t\tparsed.push(row);\r\n\t}\r\n\treturn parsed.length ? parsed : fallback.map((r) => ({ ...r }));\r\n}\r\n\r\n/** 检测 UTF-8 被误解析后产生的乱码(无 CJK、非纯 ASCII) */\r\nfunction looksLikeMojibake(text: string | undefined): boolean {\r\n\tif (!text) return false;\r\n\tif (/[\\u4e00-\\u9fff]/.test(text)) return false;\r\n\tif (/^[\\x20-\\x7e]+$/.test(text)) return false;\r\n\treturn true;\r\n}\r\n\r\n/** 从默认等级 / route-catalog 恢复被损坏的中文名称 */\r\nfunction repairUserLevelConfig(cfg: UserLevelConfig, $asai: any): { cfg: UserLevelConfig; repaired: boolean } {\r\n\tlet repaired = false;\r\n\tconst levels = cfg.levels.map((l) => {\r\n\t\tconst def = DEFAULT_LEVELS.find((d) => d.lv === l.lv || d.key === l.key);\r\n\t\tif (def && looksLikeMojibake(l.name)) {\r\n\t\t\trepaired = true;\r\n\t\t\treturn { ...l, name: def.name, nameEn: l.nameEn || def.nameEn };\r\n\t\t}\r\n\t\treturn l;\r\n\t});\r\n\tconst catalogMap = new Map(loadRouteCatalogAsRights($asai, true).map((r) => [r.route, r]));\r\n\tconst routeRights = (cfg.routeRights || []).map((r) => {\r\n\t\tconst cat = catalogMap.get(r.route);\r\n\t\tif (cat?.title && looksLikeMojibake(r.title)) {\r\n\t\t\trepaired = true;\r\n\t\t\treturn { ...r, title: cat.title };\r\n\t\t}\r\n\t\treturn r;\r\n\t});\r\n\tif (!repaired) return { cfg, repaired: false };\r\n\treturn { cfg: { ...cfg, levels, routeRights }, repaired: true };\r\n}\r\n\r\nexport function validateUserLevelConfig(cfg: UserLevelConfig): string | null {\r\n\tif (!cfg.levels.length) return 'LEVELS_EMPTY';\r\n\tconst keys = new Set<string>();\r\n\tconst lvs = new Set<number>();\r\n\tfor (const l of cfg.levels) {\r\n\t\tif (keys.has(l.key) || lvs.has(l.lv)) return 'LEVELS_DUPLICATE';\r\n\t\tkeys.add(l.key);\r\n\t\tlvs.add(l.lv);\r\n\t}\r\n\tif (!lvs.has(0)) return 'LEVELS_GUEST_REQUIRED';\r\n\tconst { thresholds } = cfg;\r\n\tif (thresholds.logRead > thresholds.adminRead) return 'THRESHOLD_ORDER';\r\n\tif (thresholds.adminRead > thresholds.adminWrite) return 'THRESHOLD_ORDER';\r\n\tfor (const r of cfg.routeRights || []) {\r\n\t\tif (!r.route) return 'ROUTE_INVALID';\r\n\t\tif (!Number.isFinite(r.minLv) || r.minLv < 0) return 'ROUTE_MINLV_INVALID';\r\n\t}\r\n\treturn null;\r\n}\r\n\r\nexport function getUserLevelConfigSync($asai: any): UserLevelConfig {\r\n\treturn ($asai._userLevelConfig as UserLevelConfig) || getDefaultUserLevelConfig($asai);\r\n}\r\n\r\nexport async function loadUserLevelConfig($asai: any): Promise<UserLevelConfig> {\r\n\tconst file = configPath($asai);\r\n\ttry {\r\n\t\tconst text = await fs.readFile(file, 'utf8');\r\n\t\tconst parsed = JSON.parse(text) as Partial<UserLevelConfig>;\r\n\t\tlet cfg = normalizeUserLevelConfig(parsed, $asai);\r\n\t\tconst err = validateUserLevelConfig(cfg);\r\n\t\tif (err) {\r\n\t\t\t$asai._userLevelConfig = getDefaultUserLevelConfig($asai);\r\n\t\t} else {\r\n\t\t\tconst { cfg: fixed, repaired } = repairUserLevelConfig(cfg, $asai);\r\n\t\t\tcfg = fixed;\r\n\t\t\t$asai._userLevelConfig = cfg;\r\n\t\t\tif (repaired) {\r\n\t\t\t\tawait fs.mkdir(path.dirname(file), { recursive: true });\r\n\t\t\t\tawait fs.writeFile(file, JSON.stringify(cfg, null, 2), 'utf8');\r\n\t\t\t}\r\n\t\t}\r\n\t} catch {\r\n\t\t$asai._userLevelConfig = getDefaultUserLevelConfig($asai);\r\n\t}\r\n\treturn $asai._userLevelConfig;\r\n}\r\n\r\nexport async function saveUserLevelConfig($asai: any, input: Partial<UserLevelConfig>, updatedBy?: string): Promise<UserLevelConfig> {\r\n\tconst cfg = normalizeUserLevelConfig(input, $asai);\r\n\tconst err = validateUserLevelConfig(cfg);\r\n\tif (err) throw new Error(err);\r\n\tconst pwd = String(cfg.defaultResetPassword || '').trim() || DEFAULT_RESET_PASSWORD;\r\n\tconst policyErr = validatePasswordWithPolicy(pwd, getPasswordPolicy($asai));\r\n\tif (policyErr) throw new Error(policyErr);\r\n\tcfg.defaultResetPassword = pwd;\r\n\tcfg.updatedAt = Date.now();\r\n\tcfg.updatedBy = updatedBy;\r\n\tconst file = configPath($asai);\r\n\tawait fs.mkdir(path.dirname(file), { recursive: true });\r\n\tawait fs.writeFile(file, JSON.stringify(cfg, null, 2), 'utf8');\r\n\t$asai._userLevelConfig = cfg;\r\n\treturn cfg;\r\n}\r\n\r\nexport function getPermissionThreshold($asai: any, key: keyof PermissionThresholds): number {\r\n\treturn getUserLevelConfigSync($asai).thresholds[key];\r\n}\r\n\r\nexport function getLvSteps($asai: any): number[] {\r\n\treturn getUserLevelConfigSync($asai).levels.map((l) => l.lv);\r\n}\r\n\r\nexport function getLevelDef($asai: any, lv: number): UserLevelDef | undefined {\r\n\treturn getUserLevelConfigSync($asai).levels.find((l) => l.lv === lv);\r\n}\r\n\r\nexport function isValidUserLv($asai: any, lv: number): boolean {\r\n\treturn getUserLevelConfigSync($asai).levels.some((l) => l.lv === lv);\r\n}\r\n\r\nexport function getLevelLabel($asai: any, lv: number, lang = 'zh-CN'): string {\r\n\tconst def = getLevelDef($asai, lv);\r\n\tif (!def) return `lv${lv}`;\r\n\tif (lang.startsWith('en') && def.nameEn) return def.nameEn;\r\n\treturn def.name;\r\n}\r\n\r\nexport function toPublicUserLevels($asai: any, lang = 'zh-CN') {\r\n\tconst cfg = getUserLevelConfigSync($asai);\r\n\treturn {\r\n\t\tlevels: cfg.levels.map((l) => ({\r\n\t\t\tlv: l.lv,\r\n\t\t\tkey: l.key,\r\n\t\t\tname: getLevelLabel($asai, l.lv, lang),\r\n\t\t\tnameZh: l.name,\r\n\t\t\tnameEn: l.nameEn || l.name,\r\n\t\t})),\r\n\t\tthresholds: { ...cfg.thresholds },\r\n\t\trouteRights: (cfg.routeRights || getDefaultRouteRights($asai)).map((r) => ({ ...r })),\r\n\t};\r\n}\r\n\r\nexport function getRouteRights($asai: any): RouteRight[] {\r\n\treturn getUserLevelConfigSync($asai).routeRights || getDefaultRouteRights($asai);\r\n}\r\n\r\nexport function findRouteRight($asai: any, hash: string): RouteRight | null {\r\n\tconst routeRights = getRouteRights($asai);\r\n\tconst h = String(hash || '').replace(/^#?\\/?/, '').split('?')[0];\r\n\tif (!h || h === '/') {\r\n\t\treturn routeRights.find((r) => r.route === 'testkdd/testindex') || { route: '/', minLv: 0, public: true };\r\n\t}\r\n\tlet best: RouteRight | null = null;\r\n\tlet bestLen = -1;\r\n\tfor (const r of routeRights) {\r\n\t\tif (h === r.route || h.startsWith(r.route + '/') || h.includes(r.route)) {\r\n\t\t\tif (r.route.length > bestLen) {\r\n\t\t\t\tbest = r;\r\n\t\t\t\tbestLen = r.route.length;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\treturn best;\r\n}\r\n\r\nexport function canAccessRoute($asai: any, hash: string, userLv: number): boolean {\r\n\tconst entry = findRouteRight($asai, hash);\r\n\tif (!entry) {\r\n\t\tconst fallback = Number($asai?.hostconfig?.security?.minUserLevel ?? 0);\r\n\t\treturn userLv >= fallback;\r\n\t}\r\n\tif (entry.public || entry.minLv === 0) return true;\r\n\treturn userLv >= entry.minLv;\r\n}\r\n","import fs from 'node:fs';\r\nimport path from 'node:path';\r\n\r\n/** 路由权限条目(与 route-catalog.json 字段对齐) */\r\nexport interface RouteRight {\r\n\troute: string;\r\n\ttitle?: string;\r\n\tminLv: number;\r\n\tpublic?: boolean;\r\n}\r\n\r\nconst DEFAULT_CATALOG_REL = '../webclient/public/webmodel/sys/testkdd/route-catalog.json';\r\n\r\n/** configrouter rights.lvN → 默认 minLv 映射 */\r\nexport const LEGACY_RIGHTS_MIN_LV: Record<string, number> = {\r\n\tlv0: 0,\r\n\tlv1: 3,\r\n\tlv2: 7,\r\n\tlv3: 9,\r\n};\r\n\r\nlet cachedCatalog: { file: string; rights: RouteRight[] } | null = null;\r\n\r\nexport function resolveRouteCatalogPath($asai: any): string {\r\n\tconst custom = $asai?.hostconfig?.security?.routeCatalogPath;\r\n\tconst root = $asai?.serverRoot || process.cwd();\r\n\tif (custom) {\r\n\t\treturn path.isAbsolute(custom) ? custom : path.resolve(root, String(custom));\r\n\t}\r\n\treturn path.resolve(root, DEFAULT_CATALOG_REL);\r\n}\r\n\r\nexport function catalogItemsToRouteRights(items: unknown[]): RouteRight[] {\r\n\tconst out: RouteRight[] = [];\r\n\tfor (const item of items) {\r\n\t\tconst row = normalizeRouteRight(item);\r\n\t\tif (row) out.push(row);\r\n\t}\r\n\treturn out;\r\n}\r\n\r\n/** 从 route-catalog.json 加载默认路由权限(无硬编码清单) */\r\nexport function loadRouteCatalogAsRights($asai: any, refresh = false): RouteRight[] {\r\n\tconst file = resolveRouteCatalogPath($asai);\r\n\tif (!refresh && cachedCatalog?.file === file) {\r\n\t\treturn cachedCatalog.rights.map((r) => ({ ...r }));\r\n\t}\r\n\ttry {\r\n\t\tconst text = fs.readFileSync(file, 'utf8');\r\n\t\tconst parsed = JSON.parse(text) as { items?: unknown[] };\r\n\t\tconst rights = catalogItemsToRouteRights(Array.isArray(parsed?.items) ? parsed.items : []);\r\n\t\tcachedCatalog = { file, rights };\r\n\t\treturn rights.map((r) => ({ ...r }));\r\n\t} catch {\r\n\t\tcachedCatalog = { file, rights: [] };\r\n\t\treturn [];\r\n\t}\r\n}\r\n\r\nexport function normalizeRouteRight(item: unknown): RouteRight | null {\r\n\tif (!item || typeof item !== 'object') return null;\r\n\tconst route = String((item as any).route || '').trim().replace(/^\\/+|\\/+$/g, '');\r\n\tif (!route) return null;\r\n\tconst minLv = Number((item as any).minLv ?? 0);\r\n\treturn {\r\n\t\troute,\r\n\t\ttitle: (item as any).title ? String((item as any).title).trim().slice(0, 128) : undefined,\r\n\t\tminLv: Number.isFinite(minLv) ? Math.max(0, Math.floor(minLv)) : 0,\r\n\t\tpublic: !!(item as any).public || minLv === 0,\r\n\t};\r\n}\r\n\r\nexport function mergeRouteRights(existing: RouteRight[], incoming: RouteRight[]): RouteRight[] {\r\n\tconst map = new Map<string, RouteRight>();\r\n\tfor (const r of existing) map.set(r.route, { ...r });\r\n\tfor (const r of incoming) {\r\n\t\tconst prev = map.get(r.route);\r\n\t\tmap.set(r.route, prev ? { ...prev, ...r, route: r.route } : r);\r\n\t}\r\n\treturn [...map.values()].sort((a, b) => a.route.localeCompare(b.route));\r\n}\r\n\r\nexport function routesFromLegacyRights(rights: Record<string, string[] | undefined>, titles?: Record<string, string>): RouteRight[] {\r\n\tconst out: RouteRight[] = [];\r\n\tif (!rights || typeof rights !== 'object') return out;\r\n\tfor (const [bucket, routes] of Object.entries(rights)) {\r\n\t\tif (!Array.isArray(routes)) continue;\r\n\t\tconst minLv = LEGACY_RIGHTS_MIN_LV[bucket] ?? 0;\r\n\t\tfor (const route of routes) {\r\n\t\t\tconst r = String(route || '').trim();\r\n\t\t\tif (!r) continue;\r\n\t\t\tout.push({\r\n\t\t\t\troute: r,\r\n\t\t\t\ttitle: titles?.[r],\r\n\t\t\t\tminLv,\r\n\t\t\t\tpublic: minLv === 0,\r\n\t\t\t});\r\n\t\t}\r\n\t}\r\n\treturn out;\r\n}\r\n"],"mappings":"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","names":["fs","path","path","legacy","fs"]}
@@ -43,13 +43,105 @@ __export(LogStore_exports, {
43
43
  });
44
44
 
45
45
  // src/sysserver/lib/common/log-file-store.ts
46
- import fs from "fs/promises";
46
+ import fs2 from "fs/promises";
47
47
  import path from "path";
48
+
49
+ // src/sysserver/lib/common/AsPath.ts
50
+ var AsPath_exports = {};
51
+ __export(AsPath_exports, {
52
+ getEntryDir: () => getEntryDir,
53
+ getExecDir: () => getExecDir,
54
+ getPkgSnapshotDir: () => getPkgSnapshotDir,
55
+ getPrimaryServerRoot: () => getPrimaryServerRoot,
56
+ getRuntimeBaseDirs: () => getRuntimeBaseDirs,
57
+ isPkgRuntime: () => isPkgRuntime,
58
+ resolveServerPath: () => resolveServerPath
59
+ });
60
+ import * as fs from "fs";
61
+ import * as nodePath from "path";
62
+ function isPkgRuntime() {
63
+ return typeof process.pkg !== "undefined";
64
+ }
65
+ __name(isPkgRuntime, "isPkgRuntime");
66
+ function getPkgSnapshotDir() {
67
+ if (!isPkgRuntime()) return void 0;
68
+ const entry = process.pkg?.entrypoint ?? process.pkg?.defaultEntrypoint;
69
+ if (!entry) return void 0;
70
+ return nodePath.resolve(nodePath.dirname(entry));
71
+ }
72
+ __name(getPkgSnapshotDir, "getPkgSnapshotDir");
73
+ function getEntryDir() {
74
+ const snapshot = getPkgSnapshotDir();
75
+ if (snapshot) return snapshot;
76
+ const entry = process.argv[1];
77
+ if (!entry) {
78
+ return nodePath.dirname(process.execPath);
79
+ }
80
+ return nodePath.resolve(nodePath.dirname(entry));
81
+ }
82
+ __name(getEntryDir, "getEntryDir");
83
+ function getExecDir() {
84
+ return nodePath.dirname(process.execPath);
85
+ }
86
+ __name(getExecDir, "getExecDir");
87
+ function getRuntimeBaseDirs() {
88
+ const bases = [];
89
+ const seen = /* @__PURE__ */ new Set();
90
+ const add = /* @__PURE__ */ __name((p) => {
91
+ if (!p) return;
92
+ const abs = nodePath.resolve(p);
93
+ if (!seen.has(abs)) {
94
+ seen.add(abs);
95
+ bases.push(abs);
96
+ }
97
+ }, "add");
98
+ add(process.cwd());
99
+ add(getExecDir());
100
+ if (isPkgRuntime()) {
101
+ add(getPkgSnapshotDir());
102
+ } else {
103
+ const entryDir = getEntryDir();
104
+ if (entryDir !== getExecDir()) {
105
+ add(entryDir);
106
+ }
107
+ }
108
+ return bases;
109
+ }
110
+ __name(getRuntimeBaseDirs, "getRuntimeBaseDirs");
111
+ function resolveServerPath($asai, relPath) {
112
+ if (!relPath || typeof relPath !== "string") {
113
+ return relPath;
114
+ }
115
+ if (nodePath.isAbsolute(relPath)) {
116
+ return nodePath.normalize(relPath);
117
+ }
118
+ const root = $asai?.serverRoot || getPrimaryServerRoot();
119
+ const rel = relPath.replace(/^\.(\/)?/, "");
120
+ return nodePath.join(root, rel);
121
+ }
122
+ __name(resolveServerPath, "resolveServerPath");
123
+ function getPrimaryServerRoot() {
124
+ for (const base of getRuntimeBaseDirs()) {
125
+ try {
126
+ if (fs.statSync(nodePath.join(base, "websys")).isDirectory()) {
127
+ return base;
128
+ }
129
+ } catch {
130
+ }
131
+ }
132
+ if (isPkgRuntime()) {
133
+ return getExecDir();
134
+ }
135
+ return getEntryDir();
136
+ }
137
+ __name(getPrimaryServerRoot, "getPrimaryServerRoot");
138
+
139
+ // src/sysserver/lib/common/log-file-store.ts
48
140
  function storeBaseAbs($asai) {
49
141
  const resolved = resolveStoreConfig($asai, "log");
50
142
  const opt = normalizeStoreOpt("log", resolved.type, resolved.opt);
51
143
  const dir = String(opt.dir || "webdata/webdb/log/store/");
52
- return path.resolve(process.cwd(), dir);
144
+ return resolveServerPath($asai, dir);
53
145
  }
54
146
  __name(storeBaseAbs, "storeBaseAbs");
55
147
  var INDEX_ROOT = "index";
@@ -82,13 +174,13 @@ function rowToRecord(row) {
82
174
  }
83
175
  __name(rowToRecord, "rowToRecord");
84
176
  async function ensureDir(dir) {
85
- await fs.mkdir(dir, { recursive: true });
177
+ await fs2.mkdir(dir, { recursive: true });
86
178
  }
87
179
  __name(ensureDir, "ensureDir");
88
180
  async function readCounter($asai) {
89
181
  const file = path.join(storeBaseAbs($asai), META_ROOT, ID_COUNTER);
90
182
  try {
91
- const raw = await fs.readFile(file, "utf8");
183
+ const raw = await fs2.readFile(file, "utf8");
92
184
  const parsed = JSON.parse(raw);
93
185
  return Math.max(0, Number(parsed.next || parsed.last || 0));
94
186
  } catch {
@@ -99,7 +191,7 @@ __name(readCounter, "readCounter");
99
191
  async function writeCounter($asai, next) {
100
192
  const dir = path.join(storeBaseAbs($asai), META_ROOT);
101
193
  await ensureDir(dir);
102
- await fs.writeFile(path.join(dir, ID_COUNTER), JSON.stringify({ next, updatedAt: Date.now() }, null, 2), "utf8");
194
+ await fs2.writeFile(path.join(dir, ID_COUNTER), JSON.stringify({ next, updatedAt: Date.now() }, null, 2), "utf8");
103
195
  }
104
196
  __name(writeCounter, "writeCounter");
105
197
  async function nextId($asai) {
@@ -114,7 +206,7 @@ async function migrateLegacyBlobIfNeeded($asai) {
114
206
  const legacyPath = path.join(base, LEGACY_BLOB);
115
207
  let legacy = [];
116
208
  try {
117
- const raw = await fs.readFile(legacyPath, "utf8");
209
+ const raw = await fs2.readFile(legacyPath, "utf8");
118
210
  const parsed = JSON.parse(raw);
119
211
  if (Array.isArray(parsed) && parsed.length) legacy = parsed;
120
212
  } catch {
@@ -127,10 +219,10 @@ async function migrateLegacyBlobIfNeeded($asai) {
127
219
  const record = rowToRecord({ ...row, id });
128
220
  const abs = path.join(base, entryRelPath(record));
129
221
  await ensureDir(path.dirname(abs));
130
- await fs.writeFile(abs, JSON.stringify(record, null, 2), "utf8");
222
+ await fs2.writeFile(abs, JSON.stringify(record, null, 2), "utf8");
131
223
  }
132
224
  await writeCounter($asai, maxId);
133
- await fs.rename(legacyPath, `${legacyPath}.migrated.${Date.now()}`).catch(() => void 0);
225
+ await fs2.rename(legacyPath, `${legacyPath}.migrated.${Date.now()}`).catch(() => void 0);
134
226
  return legacy.length;
135
227
  }
136
228
  __name(migrateLegacyBlobIfNeeded, "migrateLegacyBlobIfNeeded");
@@ -140,7 +232,7 @@ async function walkIndexFiles($asai) {
140
232
  async function walk(dir) {
141
233
  let entries;
142
234
  try {
143
- entries = await fs.readdir(dir, { withFileTypes: true });
235
+ entries = await fs2.readdir(dir, { withFileTypes: true });
144
236
  } catch {
145
237
  return;
146
238
  }
@@ -150,7 +242,7 @@ async function walkIndexFiles($asai) {
150
242
  await walk(full);
151
243
  } else if (ent.isFile() && ent.name.endsWith(".json")) {
152
244
  try {
153
- const raw = await fs.readFile(full, "utf8");
245
+ const raw = await fs2.readFile(full, "utf8");
154
246
  const parsed = JSON.parse(raw);
155
247
  if (parsed && typeof parsed === "object") rows.push(rowToRecord(parsed));
156
248
  } catch {
@@ -215,7 +307,7 @@ async function fileStoreInsert($asai, row) {
215
307
  const record = rowToRecord({ id, ...row });
216
308
  const abs = path.join(storeBaseAbs($asai), entryRelPath(record));
217
309
  await ensureDir(path.dirname(abs));
218
- await fs.writeFile(abs, JSON.stringify(record, null, 2), "utf8");
310
+ await fs2.writeFile(abs, JSON.stringify(record, null, 2), "utf8");
219
311
  }
220
312
  __name(fileStoreInsert, "fileStoreInsert");
221
313
  async function fileStoreQuery($asai, filter = {}) {
@@ -277,7 +369,7 @@ async function fileStoreDeleteByFile($asai, fileName, ns = "") {
277
369
  async function walk(dir) {
278
370
  let entries;
279
371
  try {
280
- entries = await fs.readdir(dir, { withFileTypes: true });
372
+ entries = await fs2.readdir(dir, { withFileTypes: true });
281
373
  } catch {
282
374
  return;
283
375
  }
@@ -287,11 +379,11 @@ async function fileStoreDeleteByFile($asai, fileName, ns = "") {
287
379
  await walk(full);
288
380
  } else if (ent.isFile() && ent.name.endsWith(".json")) {
289
381
  try {
290
- const raw = await fs.readFile(full, "utf8");
382
+ const raw = await fs2.readFile(full, "utf8");
291
383
  const parsed = JSON.parse(raw);
292
384
  if (String(parsed.file_name) !== fileName) continue;
293
385
  if (ns && String(parsed.ns) !== ns) continue;
294
- await fs.unlink(full);
386
+ await fs2.unlink(full);
295
387
  removed += 1;
296
388
  } catch {
297
389
  }
@@ -311,12 +403,12 @@ async function fileStoreDiskStats($asai) {
311
403
  { kind: "access", dir: logger.path?.access },
312
404
  { kind: "intervention", dir: logger.intervention?.path, ns: "prod" },
313
405
  { kind: "intervention", dir: logger.intervention?.testPath, ns: "test" }
314
- ].filter((d) => d.dir);
406
+ ].filter((d) => !!d.dir);
315
407
  const stats = { total: 0, web: 0, intervention: 0, sec: 0, access: 0, prod: 0, test: 0 };
316
408
  for (const { kind, dir, ns } of scanDirs) {
317
409
  let count = 0;
318
410
  try {
319
- const entries = await fs.readdir(String(dir), { withFileTypes: true });
411
+ const entries = await fs2.readdir(String(dir), { withFileTypes: true });
320
412
  for (const ent of entries) {
321
413
  if (!ent.isFile()) continue;
322
414
  if (ent.name.endsWith(".delete") || ent.name.startsWith(".")) continue;
@@ -859,7 +951,7 @@ async function searchUnifiedLogs($asai, filter) {
859
951
  __name(searchUnifiedLogs, "searchUnifiedLogs");
860
952
  async function exportLogContent($asai, opts) {
861
953
  const format = opts.format || "raw";
862
- const { readInterventionFile } = await import("./InterventionLog-PZT2CCN3.es.js");
954
+ const { readInterventionFile } = await import("./InterventionLog-OPQ6VOBV.es.js");
863
955
  const ns = opts.ns === "test" ? "test" : "prod";
864
956
  if (opts.kind === "intervention" && opts.fileName) {
865
957
  const data = await readInterventionFile($asai, opts.fileName, ns);
@@ -922,7 +1014,7 @@ async function exportLogContent($asai, opts) {
922
1014
  }
923
1015
  __name(exportLogContent, "exportLogContent");
924
1016
  async function getComplianceReport($asai, ns = "prod") {
925
- const { listInterventionFiles, readInterventionFile } = await import("./InterventionLog-PZT2CCN3.es.js");
1017
+ const { listInterventionFiles, readInterventionFile } = await import("./InterventionLog-OPQ6VOBV.es.js");
926
1018
  const retentionYears = $asai?.hostconfig?.logger?.intervention?.retentionYears ?? 5;
927
1019
  const stats = await dbLogStats($asai);
928
1020
  const storeMeta = getLogStoreMeta($asai);
@@ -1060,7 +1152,7 @@ async function archiveInterventionYear($asai, opts) {
1060
1152
  const { pipeline } = await import("stream/promises");
1061
1153
  const { createReadStream, createWriteStream } = await import("fs");
1062
1154
  const ns = opts.ns || "prod";
1063
- const { listInterventionFiles, readInterventionFile } = await import("./InterventionLog-PZT2CCN3.es.js");
1155
+ const { listInterventionFiles, readInterventionFile } = await import("./InterventionLog-OPQ6VOBV.es.js");
1064
1156
  const yearStr = String(opts.year);
1065
1157
  const archiveBase = $asai?.hostconfig?.logger?.intervention?.archivePath || path2.join($asai?.hostconfig?.logger?.intervention?.path || "./webdata/webdb/log/intervention/", "archive/");
1066
1158
  const archiveDir = path2.join(archiveBase, yearStr);
@@ -1098,7 +1190,7 @@ async function archiveInterventionYear($asai, opts) {
1098
1190
  );
1099
1191
  await fsp.unlink(srcPath);
1100
1192
  await purgeStoreEntriesForFile($asai, f.name, ns);
1101
- const { logProcessGuardEvent } = await import("./intervention-hooks-TCGIC4IV.es.js");
1193
+ const { logProcessGuardEvent } = await import("./intervention-hooks-QNA4IZT7.es.js");
1102
1194
  await logProcessGuardEvent($asai, {
1103
1195
  action: "archive_intervention",
1104
1196
  detail: `${f.name} -> ${gzPath}`,
@@ -1174,6 +1266,8 @@ async function readWebLogFromStore($asai, source, fileName) {
1174
1266
  __name(readWebLogFromStore, "readWebLogFromStore");
1175
1267
 
1176
1268
  export {
1269
+ getPrimaryServerRoot,
1270
+ AsPath_exports,
1177
1271
  getLogStoreConfig,
1178
1272
  getLogStoreMeta,
1179
1273
  isLogStoreEnabled,
@@ -1199,4 +1293,4 @@ export {
1199
1293
  readWebLogFromStore,
1200
1294
  LogStore_exports
1201
1295
  };
1202
- //# sourceMappingURL=chunk-LTEP4XB2.es.js.map
1296
+ //# sourceMappingURL=chunk-EC67M7RR.es.js.map