asaihost-nodejs 0.0.8 → 0.0.10

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 (44) hide show
  1. package/dist/InterventionLog-WNVDQFAH.cjs.map +1 -1
  2. package/dist/LogStore-AP4T2CFD.cjs.map +1 -1
  3. package/dist/asaihost-nodejs.cjs +778 -507
  4. package/dist/asaihost-nodejs.cjs.map +1 -1
  5. package/dist/asaihost-nodejs.es.js +391 -120
  6. package/dist/asaihost-nodejs.es.js.map +1 -1
  7. package/dist/chunk-2BCIIKRG.cjs.map +1 -1
  8. package/dist/{chunk-OTL2B4WS.es.js → chunk-3E4Y5ATG.es.js} +2 -2
  9. package/dist/{chunk-ZK4O4Z2O.cjs → chunk-5EWEKXQI.cjs} +20 -20
  10. package/dist/chunk-5EWEKXQI.cjs.map +1 -0
  11. package/dist/chunk-ARHPHWT5.cjs.map +1 -1
  12. package/dist/{chunk-GXOFLFFW.cjs → chunk-FRPN33BY.cjs} +3 -2
  13. package/dist/chunk-FRPN33BY.cjs.map +1 -0
  14. package/dist/{chunk-WXW5DYNU.cjs → chunk-H2QP5J7X.cjs} +9 -9
  15. package/dist/chunk-H2QP5J7X.cjs.map +1 -0
  16. package/dist/chunk-HR5JKN7Y.cjs.map +1 -1
  17. package/dist/{chunk-BOIRAQXE.es.js → chunk-M3NURHGU.es.js} +2 -1
  18. package/dist/chunk-O6LVLSNB.cjs.map +1 -1
  19. package/dist/chunk-OCEBEEP5.cjs.map +1 -1
  20. package/dist/chunk-SMVZ3ZDJ.cjs.map +1 -1
  21. package/dist/chunk-U2YJH2RW.cjs.map +1 -1
  22. package/dist/{chunk-5WJQD4RZ.es.js → chunk-UKZ3DP37.es.js} +3 -3
  23. package/dist/intervention-hooks-4NAAAZK3.cjs.map +1 -1
  24. package/dist/log-alert-LAJ6VSAG.cjs.map +1 -1
  25. package/dist/log-formats-TUXGMCCU.cjs.map +1 -1
  26. package/dist/{password-4P7IZUDQ.es.js → password-2ZBHQQBF.es.js} +3 -3
  27. package/dist/password-T762KJOI.cjs +20 -0
  28. package/dist/password-T762KJOI.cjs.map +1 -0
  29. package/dist/user-store-6QNAL4CK.cjs +12 -0
  30. package/dist/user-store-6QNAL4CK.cjs.map +1 -0
  31. package/dist/{user-store-FXD2N55G.es.js → user-store-ZI67TXSI.es.js} +3 -3
  32. package/package.json +1 -1
  33. package/dist/chunk-GXOFLFFW.cjs.map +0 -1
  34. package/dist/chunk-WXW5DYNU.cjs.map +0 -1
  35. package/dist/chunk-ZK4O4Z2O.cjs.map +0 -1
  36. package/dist/password-MDYRL6ZD.cjs +0 -20
  37. package/dist/password-MDYRL6ZD.cjs.map +0 -1
  38. package/dist/user-store-55HOLHEM.cjs +0 -12
  39. package/dist/user-store-55HOLHEM.cjs.map +0 -1
  40. /package/dist/{chunk-OTL2B4WS.es.js.map → chunk-3E4Y5ATG.es.js.map} +0 -0
  41. /package/dist/{chunk-BOIRAQXE.es.js.map → chunk-M3NURHGU.es.js.map} +0 -0
  42. /package/dist/{chunk-5WJQD4RZ.es.js.map → chunk-UKZ3DP37.es.js.map} +0 -0
  43. /package/dist/{password-4P7IZUDQ.es.js.map → password-2ZBHQQBF.es.js.map} +0 -0
  44. /package/dist/{user-store-FXD2N55G.es.js.map → user-store-ZI67TXSI.es.js.map} +0 -0
@@ -50,7 +50,7 @@ import {
50
50
  secureCompare,
51
51
  validatePasswordChange,
52
52
  verifyPassword
53
- } from "./chunk-OTL2B4WS.es.js";
53
+ } from "./chunk-3E4Y5ATG.es.js";
54
54
  import {
55
55
  USER_LV,
56
56
  applySecretsToHostConfig,
@@ -62,20 +62,21 @@ import {
62
62
  resolveHttpsCertFromPaths,
63
63
  stripForbiddenSecretsFromHostConfig,
64
64
  validateAsaiSecrets
65
- } from "./chunk-5WJQD4RZ.es.js";
65
+ } from "./chunk-UKZ3DP37.es.js";
66
66
  import {
67
67
  getDefaultResetPassword,
68
68
  getPasswordPolicy,
69
69
  getPermissionThreshold,
70
70
  getPublicSecurityConfig,
71
71
  getUserLevelConfigSync,
72
+ getUserStoreConfig,
72
73
  isPasswordExpired,
73
74
  isValidUserLv,
74
75
  loadUserLevelConfig,
75
76
  resolveRoleForLevel,
76
77
  saveUserLevelConfig,
77
78
  validatePasswordWithPolicy
78
- } from "./chunk-BOIRAQXE.es.js";
79
+ } from "./chunk-M3NURHGU.es.js";
79
80
  import {
80
81
  getDataServerForAsDb
81
82
  } from "./chunk-ZQBHJRAO.es.js";
@@ -915,7 +916,7 @@ import * as https from "https";
915
916
  import { WebSocketServer } from "ws";
916
917
 
917
918
  // src/ws/auth.ts
918
- import { WebSocket } from "ws";
919
+ import { WebSocket as WebSocket2 } from "ws";
919
920
 
920
921
  // src/utils/userinfo.ts
921
922
  function deUserInfoWithAsai(userinfo, $asai) {
@@ -940,6 +941,84 @@ function deUserInfoWithAsai(userinfo, $asai) {
940
941
  }
941
942
  __name(deUserInfoWithAsai, "deUserInfoWithAsai");
942
943
 
944
+ // src/ws/ws-probe.ts
945
+ import { WebSocket } from "ws";
946
+ function isWsStillActive(ws2) {
947
+ if (!ws2) return false;
948
+ const state = ws2.readyState;
949
+ return state === WebSocket.CONNECTING || state === WebSocket.OPEN;
950
+ }
951
+ __name(isWsStillActive, "isWsStillActive");
952
+ function getWsProbeTimeoutMs($asai) {
953
+ return $asai?.hostconfig?.tm?.d || 3e3;
954
+ }
955
+ __name(getWsProbeTimeoutMs, "getWsProbeTimeoutMs");
956
+ function probeWsAlive($asai, wsclient, timeoutMs) {
957
+ const waitMs = timeoutMs ?? getWsProbeTimeoutMs($asai);
958
+ return new Promise((resolve6) => {
959
+ if (!wsclient || !isWsStillActive(wsclient)) {
960
+ resolve6(false);
961
+ return;
962
+ }
963
+ let settled = false;
964
+ const finish = /* @__PURE__ */ __name((alive) => {
965
+ if (settled) return;
966
+ settled = true;
967
+ clearTimeout(timer);
968
+ try {
969
+ wsclient.off?.("message", onMessage);
970
+ } catch {
971
+ }
972
+ resolve6(alive);
973
+ }, "finish");
974
+ const onMessage = /* @__PURE__ */ __name(() => finish(true), "onMessage");
975
+ const timer = setTimeout(() => finish(false), waitMs);
976
+ try {
977
+ wsclient.once?.("message", onMessage);
978
+ wsclient.send(JSON.stringify({ ty: "publish/web", db: "pong" }));
979
+ } catch {
980
+ finish(false);
981
+ }
982
+ });
983
+ }
984
+ __name(probeWsAlive, "probeWsAlive");
985
+ function terminateWs(wsclient) {
986
+ if (!wsclient) return;
987
+ try {
988
+ wsclient.terminate?.();
989
+ } catch {
990
+ }
991
+ try {
992
+ wsclient.close?.();
993
+ } catch {
994
+ }
995
+ }
996
+ __name(terminateWs, "terminateWs");
997
+ async function clearStaleWsIfDead($asai, hostdir, us, existingWs) {
998
+ if (!us || us === "asai") return true;
999
+ const map = $asai.connectionsws?.[hostdir];
1000
+ if (!existingWs) {
1001
+ if (map?.[us]) delete map[us];
1002
+ return true;
1003
+ }
1004
+ if (existingWs._asaiKicked) {
1005
+ terminateWs(existingWs);
1006
+ if (map?.[us] === existingWs) delete map[us];
1007
+ return true;
1008
+ }
1009
+ if (!isWsStillActive(existingWs)) {
1010
+ terminateWs(existingWs);
1011
+ if (map?.[us] === existingWs) delete map[us];
1012
+ return true;
1013
+ }
1014
+ const alive = await probeWsAlive($asai, existingWs);
1015
+ if (alive) return false;
1016
+ terminateWs(existingWs);
1017
+ if (map?.[us] === existingWs) delete map[us];
1018
+ return true;
1019
+ }
1020
+ __name(clearStaleWsIfDead, "clearStaleWsIfDead");
1021
+
943
1022
  // src/ws/auth.ts
944
1023
  function getWsUserinfo(req, $asai) {
945
1024
  try {
@@ -952,22 +1031,38 @@ function getWsUserinfo(req, $asai) {
952
1031
  }
953
1032
  __name(getWsUserinfo, "getWsUserinfo");
954
1033
  function listOnlineWsUsers($asai, hostdir) {
1034
+ return listOnlineWsEntries($asai, hostdir).map((e) => e.us);
1035
+ }
1036
+ __name(listOnlineWsUsers, "listOnlineWsUsers");
1037
+ function listOnlineWsEntries($asai, hostdir) {
955
1038
  const users = [];
1039
+ const seen = /* @__PURE__ */ new Set();
956
1040
  const map = $asai.connectionsws || {};
957
1041
  const dirs = hostdir ? [hostdir] : Object.keys(map);
958
1042
  for (const dir of dirs) {
959
1043
  for (const [us, ws2] of Object.entries(map[dir] || {})) {
960
1044
  if (!us || us === "asai") continue;
961
1045
  if (isWsStillActive(ws2)) {
962
- users.push(us);
1046
+ if (seen.has(us)) continue;
1047
+ seen.add(us);
1048
+ const rawLv = ws2?.Userinfo?.[1];
1049
+ if (rawLv === "" || rawLv == null) {
1050
+ users.push({ us, lv: null });
1051
+ } else {
1052
+ const lvNum = Number(rawLv);
1053
+ users.push({
1054
+ us,
1055
+ lv: Number.isFinite(lvNum) ? lvNum : null
1056
+ });
1057
+ }
963
1058
  } else if (map[dir]?.[us] === ws2) {
964
1059
  delete map[dir][us];
965
1060
  }
966
1061
  }
967
1062
  }
968
- return [...new Set(users)];
1063
+ return users;
969
1064
  }
970
- __name(listOnlineWsUsers, "listOnlineWsUsers");
1065
+ __name(listOnlineWsEntries, "listOnlineWsEntries");
971
1066
  function isUserOnlineOnWs($asai, us, hostdir) {
972
1067
  if (!us || us === "asai") return false;
973
1068
  const map = $asai.connectionsws || {};
@@ -981,19 +1076,73 @@ function isUserOnlineOnWs($asai, us, hostdir) {
981
1076
  return false;
982
1077
  }
983
1078
  __name(isUserOnlineOnWs, "isUserOnlineOnWs");
984
- function kickUserWs($asai, us, hostdir) {
1079
+ async function kickUserWs($asai, us, hostdir) {
985
1080
  if (!us || us === "asai") return;
986
1081
  const map = $asai.connectionsws || {};
987
1082
  const dirs = hostdir ? [hostdir] : Object.keys(map);
1083
+ const waits = [];
988
1084
  for (const dir of dirs) {
989
1085
  const ws2 = map[dir]?.[us];
990
1086
  if (!ws2) continue;
1087
+ if (map[dir]?.[us] === ws2) delete map[dir][us];
991
1088
  try {
992
- ws2.close();
1089
+ ws2._asaiKicked = Date.now();
993
1090
  } catch {
994
1091
  }
995
- if (map[dir]?.[us] === ws2) delete map[dir][us];
1092
+ waits.push(
1093
+ new Promise((resolve6) => {
1094
+ let done = false;
1095
+ const finish = /* @__PURE__ */ __name(() => {
1096
+ if (done) return;
1097
+ done = true;
1098
+ try {
1099
+ ws2.off?.("close", finish);
1100
+ } catch {
1101
+ }
1102
+ resolve6();
1103
+ }, "finish");
1104
+ try {
1105
+ ws2.once?.("close", finish);
1106
+ } catch {
1107
+ }
1108
+ const payload = JSON.stringify({
1109
+ ty: "publish/web",
1110
+ db: {
1111
+ exit: 1,
1112
+ type: "err",
1113
+ lang: "forcedout",
1114
+ langpm: `${us}`,
1115
+ con: `${us} forced out by another login`
1116
+ }
1117
+ });
1118
+ const hardClose = /* @__PURE__ */ __name(() => {
1119
+ try {
1120
+ if (typeof ws2.terminate === "function") ws2.terminate();
1121
+ else ws2.close();
1122
+ } catch {
1123
+ try {
1124
+ ws2.close();
1125
+ } catch {
1126
+ }
1127
+ }
1128
+ }, "hardClose");
1129
+ try {
1130
+ ws2.send(payload, () => {
1131
+ hardClose();
1132
+ finish();
1133
+ });
1134
+ } catch {
1135
+ hardClose();
1136
+ finish();
1137
+ }
1138
+ setTimeout(() => {
1139
+ hardClose();
1140
+ finish();
1141
+ }, 150);
1142
+ })
1143
+ );
996
1144
  }
1145
+ if (waits.length) await Promise.all(waits);
997
1146
  }
998
1147
  __name(kickUserWs, "kickUserWs");
999
1148
  async function removeSessionOnWsClose($asai, us, token) {
@@ -1006,12 +1155,6 @@ async function removeSessionOnWsClose($asai, us, token) {
1006
1155
  }
1007
1156
  }
1008
1157
  __name(removeSessionOnWsClose, "removeSessionOnWsClose");
1009
- function isWsStillActive(ws2) {
1010
- if (!ws2) return false;
1011
- const state = ws2.readyState;
1012
- return state === WebSocket.CONNECTING || state === WebSocket.OPEN;
1013
- }
1014
- __name(isWsStillActive, "isWsStillActive");
1015
1158
  function rejectIncomingWs(ws2, db) {
1016
1159
  const payload = JSON.stringify({ ty: "publish/web", db: { exit: 1, type: "err", ...db } });
1017
1160
  try {
@@ -1029,7 +1172,7 @@ function rejectIncomingWs(ws2, db) {
1029
1172
  }
1030
1173
  }
1031
1174
  __name(rejectIncomingWs, "rejectIncomingWs");
1032
- function isOkWs($asai, hostdir, ws2, _req, hostcfg) {
1175
+ async function isOkWs($asai, hostdir, ws2, _req, hostcfg) {
1033
1176
  const [us, , tk] = ws2.Userinfo || [];
1034
1177
  if (!us) {
1035
1178
  ws2.close();
@@ -1042,7 +1185,8 @@ function isOkWs($asai, hostdir, ws2, _req, hostcfg) {
1042
1185
  rejectIncomingWs(ws2, {
1043
1186
  lang: "pageworking",
1044
1187
  langpm: `${us}`,
1045
- con: `${us} page already running`
1188
+ con: `${us} page already running`,
1189
+ online: listOnlineWsEntries($asai, hostdir)
1046
1190
  });
1047
1191
  return false;
1048
1192
  }
@@ -1053,12 +1197,17 @@ function isOkWs($asai, hostdir, ws2, _req, hostcfg) {
1053
1197
  delete $asai.connectionsws[hostdir][us];
1054
1198
  return true;
1055
1199
  }
1056
- rejectIncomingWs(ws2, {
1057
- lang: "logged",
1058
- langpm: `${us}`,
1059
- con: `${us} logged in!`
1060
- });
1061
- return false;
1200
+ const cleared = await clearStaleWsIfDead($asai, hostdir, us, existingWs);
1201
+ if (!cleared) {
1202
+ rejectIncomingWs(ws2, {
1203
+ lang: "logged",
1204
+ langpm: `${us}`,
1205
+ con: `${us} logged in!`,
1206
+ online: listOnlineWsEntries($asai, hostdir)
1207
+ });
1208
+ return false;
1209
+ }
1210
+ return true;
1062
1211
  }
1063
1212
  if (us !== "asai") {
1064
1213
  const connections = $asai.connectionsws[hostdir] || {};
@@ -1066,19 +1215,22 @@ function isOkWs($asai, hostdir, ws2, _req, hostcfg) {
1066
1215
  (item) => item.Userinfo?.[2] === tk && item.Userinfo?.[0] !== us
1067
1216
  );
1068
1217
  const maxOnline = hostcfg.maxonline || 100;
1218
+ const online = listOnlineWsEntries($asai, hostdir);
1069
1219
  if (sameTkWs) {
1070
1220
  rejectIncomingWs(ws2, {
1071
1221
  lang: "loggedsametk",
1072
1222
  langpm: `${us}(${sameTkWs.Userinfo[0]})`,
1073
- con: `${us}(${sameTkWs.Userinfo[0]}) logged in!`
1223
+ con: `${us}(${sameTkWs.Userinfo[0]}) logged in!`,
1224
+ online
1074
1225
  });
1075
1226
  return false;
1076
1227
  }
1077
- if (Object.keys(connections).length >= maxOnline) {
1228
+ if (online.length >= maxOnline) {
1078
1229
  rejectIncomingWs(ws2, {
1079
1230
  lang: "maxlogged",
1080
1231
  langpm: `${maxOnline}`,
1081
- con: `max ${maxOnline} users online!`
1232
+ con: `max ${maxOnline} users online!`,
1233
+ online
1082
1234
  });
1083
1235
  return false;
1084
1236
  }
@@ -1109,13 +1261,13 @@ function loginWs($asai, hostdir, ws2, req, hostcfg, wsWorkHandler, logWsMessage)
1109
1261
  if (us && token && !isUserOnlineOnWs($asai, us, hostdir)) {
1110
1262
  void removeSessionOnWsClose($asai, us, String(token));
1111
1263
  }
1112
- if (ws2.readyState !== WebSocket.CLOSED && ws2.readyState !== WebSocket.CLOSING) ws2.close();
1264
+ if (ws2.readyState !== WebSocket2.CLOSED && ws2.readyState !== WebSocket2.CLOSING) ws2.close();
1113
1265
  });
1114
1266
  }
1115
1267
  __name(loginWs, "loginWs");
1116
1268
 
1117
1269
  // src/ws/message.ts
1118
- import { WebSocket as WebSocket2 } from "ws";
1270
+ import { WebSocket as WebSocket3 } from "ws";
1119
1271
  function clearWsServerTasks($asai, hostdir) {
1120
1272
  const tasks = $asai.tasksws[hostdir];
1121
1273
  if (tasks && typeof tasks === "object") {
@@ -1140,7 +1292,7 @@ function attachWssHelpers(wss, $asai) {
1140
1292
  const data = resWsMsg(msg, $asai);
1141
1293
  if (type) {
1142
1294
  wss.clients.forEach((client) => {
1143
- if ((type === 2 || client !== curws) && client.readyState === WebSocket2.OPEN) {
1295
+ if ((type === 2 || client !== curws) && client.readyState === WebSocket3.OPEN) {
1144
1296
  client.send(data);
1145
1297
  }
1146
1298
  });
@@ -1151,7 +1303,7 @@ function attachWssHelpers(wss, $asai) {
1151
1303
  wss.broadws = (msg) => {
1152
1304
  const data = resWsMsg(msg, $asai);
1153
1305
  wss.clients.forEach((client) => {
1154
- if (client?.readyState === WebSocket2.OPEN) client.send(data);
1306
+ if (client?.readyState === WebSocket3.OPEN) client.send(data);
1155
1307
  });
1156
1308
  };
1157
1309
  }
@@ -1331,12 +1483,14 @@ function createWSHost($asai, hostdir) {
1331
1483
  ws2.send(wsmsg, () => ws2.close(1013, "Server busy"));
1332
1484
  return;
1333
1485
  }
1334
- const isOpen = !hostcfg.ckws || isOkWs($asai, hostdir, ws2, req, hostcfg);
1335
- if (isOpen) {
1336
- loginWs($asai, hostdir, ws2, req, hostcfg, wsWorkHandler, logWsMessage);
1337
- } else {
1338
- ws2.close();
1339
- }
1486
+ void (async () => {
1487
+ const isOpen = !hostcfg.ckws || await isOkWs($asai, hostdir, ws2, req, hostcfg);
1488
+ if (isOpen) {
1489
+ loginWs($asai, hostdir, ws2, req, hostcfg, wsWorkHandler, logWsMessage);
1490
+ } else {
1491
+ ws2.close();
1492
+ }
1493
+ })();
1340
1494
  });
1341
1495
  $asai.serversws[hostdir] = wss;
1342
1496
  } catch (err) {
@@ -1460,11 +1614,11 @@ function createSkipChecker($asai) {
1460
1614
  }
1461
1615
  if (exact.size === 0 && prefixes.length === 0) return () => false;
1462
1616
  return (url) => {
1463
- const path8 = normalizeRequestPath(url);
1464
- if (!path8) return false;
1465
- if (exact.has(path8)) return true;
1617
+ const path9 = normalizeRequestPath(url);
1618
+ if (!path9) return false;
1619
+ if (exact.has(path9)) return true;
1466
1620
  for (let i = 0; i < prefixes.length; i++) {
1467
- if (path8.startsWith(prefixes[i])) return true;
1621
+ if (path9.startsWith(prefixes[i])) return true;
1468
1622
  }
1469
1623
  return false;
1470
1624
  };
@@ -2351,7 +2505,7 @@ async function attachServerUserLevel(req, $asai) {
2351
2505
  if (!Array.isArray(userinfo) || !userinfo[0]) return;
2352
2506
  const us = String(userinfo[0]);
2353
2507
  try {
2354
- const { createUserStore: createUserStore2 } = await import("./user-store-FXD2N55G.es.js");
2508
+ const { createUserStore: createUserStore2 } = await import("./user-store-ZI67TXSI.es.js");
2355
2509
  const user = await createUserStore2($asai).findByUsername(us);
2356
2510
  if (user && user.status === "active") {
2357
2511
  req._serverUser = { us: user.us, lv: user.lv, status: user.status };
@@ -2382,11 +2536,11 @@ function getSecurityConfig($asai) {
2382
2536
  return $asai?.hostconfig?.security || {};
2383
2537
  }
2384
2538
  __name(getSecurityConfig, "getSecurityConfig");
2385
- function pathMatchesPattern(path8, pattern) {
2539
+ function pathMatchesPattern(path9, pattern) {
2386
2540
  if (pattern.endsWith("*")) {
2387
- return path8.startsWith(pattern.slice(0, -1));
2541
+ return path9.startsWith(pattern.slice(0, -1));
2388
2542
  }
2389
- return path8 === pattern;
2543
+ return path9 === pattern;
2390
2544
  }
2391
2545
  __name(pathMatchesPattern, "pathMatchesPattern");
2392
2546
  function isAuthSkipped($asai, pathname) {
@@ -3993,6 +4147,37 @@ async function purgeOfflineSessions($asai, hostdir, store) {
3993
4147
  __name(purgeOfflineSessions, "purgeOfflineSessions");
3994
4148
 
3995
4149
  // src/sysserver/api/login/index.ts
4150
+ import fs9 from "fs";
4151
+ import path4 from "path";
4152
+ async function resolveUserLv($asai, store, us, wsLv) {
4153
+ if (!us) return null;
4154
+ try {
4155
+ const user = await store.findByUsername(us);
4156
+ if (user && user.lv != null && Number.isFinite(Number(user.lv))) {
4157
+ return Number(user.lv);
4158
+ }
4159
+ } catch {
4160
+ }
4161
+ try {
4162
+ const cfg = getUserStoreConfig($asai);
4163
+ const dir = String(cfg?.opt?.dir || "");
4164
+ if (dir) {
4165
+ const base = path4.isAbsolute(dir) ? dir : path4.join(process.cwd(), dir);
4166
+ const safeUs = us.replace(/[\\/:*?"<>|]/g, "");
4167
+ const file = path4.join(base, "json", `${safeUs}.json`);
4168
+ if (safeUs && fs9.existsSync(file)) {
4169
+ const raw = JSON.parse(fs9.readFileSync(file, "utf8"));
4170
+ const lv = Number(raw?.lv);
4171
+ if (Number.isFinite(lv)) return lv;
4172
+ }
4173
+ }
4174
+ } catch {
4175
+ }
4176
+ if (wsLv === null || wsLv === void 0 || wsLv === "") return null;
4177
+ const n = Number(wsLv);
4178
+ return Number.isFinite(n) ? n : null;
4179
+ }
4180
+ __name(resolveUserLv, "resolveUserLv");
3996
4181
  function getSecurity($asai) {
3997
4182
  return $asai?.hostconfig?.security || {};
3998
4183
  }
@@ -4153,8 +4338,11 @@ var login_default = /* @__PURE__ */ __name(($asai) => {
4153
4338
  const policy = getPasswordPolicy($asai);
4154
4339
  const mustChange = !!user.mustChangePassword || isPasswordExpired(user.passwordChangedAt, policy.maxAgeDays);
4155
4340
  const hostcfg = $asai.getHost?.(hostdir) || {};
4156
- if (hostcfg.ckws && isUserOnlineOnWs($asai, us, hostdir)) {
4157
- kickUserWs($asai, us, hostdir);
4341
+ if (hostcfg.ckws) {
4342
+ const existingWs = $asai.connectionsws?.[hostdir]?.[us];
4343
+ if (existingWs) {
4344
+ await clearStaleWsIfDead($asai, hostdir, us, existingWs);
4345
+ }
4158
4346
  }
4159
4347
  const quotaCheck = await canLogin($asai, us, hostdir);
4160
4348
  if (!quotaCheck.ok) {
@@ -4200,6 +4388,56 @@ var login_default = /* @__PURE__ */ __name(($asai) => {
4200
4388
  return sendFail(res, err?.message || err, opt);
4201
4389
  }
4202
4390
  }
4391
+ if (url.startsWith("/api/user/login/force/")) {
4392
+ try {
4393
+ const us = sanitizeString(String(req?.Userinfo?.[0] || ""), 64);
4394
+ if (!us) return sendErr(res, "AUTH_MISSING", void 0, opt);
4395
+ const myLv = Number(req?.Userinfo?.[1] ?? 0);
4396
+ const targetUs = sanitizeString(String(body?.targetUs || body?.us || ""), 64);
4397
+ const kicked = [];
4398
+ if (isUserOnlineOnWs($asai, us, hostdir)) {
4399
+ await kickUserWs($asai, us, hostdir);
4400
+ kicked.push(us);
4401
+ }
4402
+ const onlineRaw = listOnlineWsEntries($asai, hostdir).filter((e) => e.us !== us);
4403
+ const online = await Promise.all(
4404
+ onlineRaw.map(async (e) => ({
4405
+ us: e.us,
4406
+ lv: await resolveUserLv($asai, store, e.us, e.lv)
4407
+ }))
4408
+ );
4409
+ const candidates = targetUs ? online.filter((e) => e.us === targetUs) : online;
4410
+ for (const entry of candidates) {
4411
+ const entryLv = entry.lv == null ? NaN : Number(entry.lv);
4412
+ if (!Number.isFinite(entryLv) || myLv < entryLv) {
4413
+ if (targetUs) {
4414
+ return sendErr(res, "AUTH_FORBIDDEN", void 0, opt);
4415
+ }
4416
+ continue;
4417
+ }
4418
+ await kickUserWs($asai, entry.us, hostdir);
4419
+ kicked.push(entry.us);
4420
+ }
4421
+ if (!kicked.length && online.length) {
4422
+ return sendErr(res, "AUTH_FORBIDDEN", void 0, opt);
4423
+ }
4424
+ logSecurityEvent($asai, {
4425
+ type: "AUTH_SUCCESS",
4426
+ path: url,
4427
+ method: "POST",
4428
+ user: us,
4429
+ ip,
4430
+ detail: `force_login_kick:${kicked.join(",") || "none"}`
4431
+ });
4432
+ return sendSuccess(
4433
+ res,
4434
+ { ok: true, us, kicked, online: listOnlineWsEntries($asai, hostdir) },
4435
+ opt
4436
+ );
4437
+ } catch (err) {
4438
+ return sendFail(res, err?.message || err, opt);
4439
+ }
4440
+ }
4203
4441
  if (url.startsWith("/api/user/login/admin/kick/")) {
4204
4442
  if (!await checkAdmin(req, url, getPermissionThreshold($asai, "adminWrite"))) {
4205
4443
  return sendErr(res, "AUTH_FORBIDDEN", void 0, opt);
@@ -4213,7 +4451,7 @@ var login_default = /* @__PURE__ */ __name(($asai) => {
4213
4451
  if (!isSessionUserOnline($asai, target.us, hostdir)) {
4214
4452
  return sendErr(res, "SESSION_NOT_ONLINE", void 0, opt);
4215
4453
  }
4216
- kickUserWs($asai, target.us, hostdir);
4454
+ await kickUserWs($asai, target.us, hostdir);
4217
4455
  await store.removeSession(sessionId);
4218
4456
  const operator = String(req?.Userinfo?.[0] || "");
4219
4457
  await logSessionTerminate($asai, {
@@ -4412,6 +4650,39 @@ var login_default = /* @__PURE__ */ __name(($asai) => {
4412
4650
  await loadUserLevelConfig($asai);
4413
4651
  return sendSuccess(res, getPublicSecurityConfig($asai, lang), opt);
4414
4652
  }
4653
+ if (url.startsWith("/api/user/login/online/")) {
4654
+ try {
4655
+ const us = sanitizeString(String(req?.Userinfo?.[0] || ""), 64);
4656
+ if (!us) return sendErr(res, "AUTH_MISSING", void 0, opt);
4657
+ const rawOnline = listOnlineWsEntries($asai, hostdir);
4658
+ const online = await Promise.all(
4659
+ rawOnline.map(async (e) => ({
4660
+ us: e.us,
4661
+ lv: await resolveUserLv($asai, store, e.us, e.lv)
4662
+ }))
4663
+ );
4664
+ const rawMy = req?.Userinfo?.[1];
4665
+ const wsMyLv = rawMy === null || rawMy === void 0 || rawMy === "" ? null : Number(rawMy);
4666
+ const myLvOut = await resolveUserLv(
4667
+ $asai,
4668
+ store,
4669
+ us,
4670
+ Number.isFinite(wsMyLv) ? wsMyLv : null
4671
+ );
4672
+ return sendSuccess(
4673
+ res,
4674
+ {
4675
+ us,
4676
+ lv: myLvOut,
4677
+ online,
4678
+ maxonline: $asai.getHost?.(hostdir)?.maxonline ?? 100
4679
+ },
4680
+ opt
4681
+ );
4682
+ } catch (err) {
4683
+ return sendFail(res, err?.message || err, opt);
4684
+ }
4685
+ }
4415
4686
  if (url.startsWith("/api/user/login/admin/levels/")) {
4416
4687
  if (!await checkAdmin(req, url, getPermissionThreshold($asai, "adminRead"))) {
4417
4688
  return sendErr(res, "AUTH_FORBIDDEN", void 0, opt);
@@ -4534,10 +4805,10 @@ var As_default = {
4534
4805
  return relativePath;
4535
4806
  },
4536
4807
  //创建多层文件夹 同步
4537
- ensureDir(fs11, relativePath) {
4808
+ ensureDir(fs12, relativePath) {
4538
4809
  const absPathDir = this.toDirPath(relativePath);
4539
4810
  const absPath = this.toAbsolutePath(relativePath);
4540
- if (!fs11.existsSync(absPath)) {
4811
+ if (!fs12.existsSync(absPath)) {
4541
4812
  let pathTmp = "";
4542
4813
  absPathDir.split("/").forEach((el) => {
4543
4814
  if (el) {
@@ -4545,8 +4816,8 @@ var As_default = {
4545
4816
  pathTmp += "/";
4546
4817
  }
4547
4818
  pathTmp += el;
4548
- if (!fs11.existsSync(pathTmp)) {
4549
- if (!fs11.mkdirSync(pathTmp, { recursive: true })) {
4819
+ if (!fs12.existsSync(pathTmp)) {
4820
+ if (!fs12.mkdirSync(pathTmp, { recursive: true })) {
4550
4821
  return absPath;
4551
4822
  }
4552
4823
  }
@@ -4555,10 +4826,10 @@ var As_default = {
4555
4826
  }
4556
4827
  return absPath;
4557
4828
  },
4558
- makeDir(fs11, filePaths) {
4829
+ makeDir(fs12, filePaths) {
4559
4830
  return new Promise((resolve6, reject) => {
4560
4831
  try {
4561
- const newPath = this.ensureDir(fs11, filePaths);
4832
+ const newPath = this.ensureDir(fs12, filePaths);
4562
4833
  resolve6(newPath);
4563
4834
  } catch (err) {
4564
4835
  reject(err);
@@ -5155,7 +5426,7 @@ var AsDb_default = /* @__PURE__ */ __name(($asai, cfg) => {
5155
5426
  }, "default");
5156
5427
 
5157
5428
  // src/sysserver/lib/common/reqWork.ts
5158
- import * as path4 from "path";
5429
+ import * as path5 from "path";
5159
5430
  var reqWork_default = /* @__PURE__ */ __name(($asai) => {
5160
5431
  function hostDefault2(mod) {
5161
5432
  if (mod && typeof mod === "object" && "default" in mod) {
@@ -5171,16 +5442,16 @@ var reqWork_default = /* @__PURE__ */ __name(($asai) => {
5171
5442
  throw new Error("Missing path");
5172
5443
  }
5173
5444
  const decoded = decodeURIComponent(String(rawPath));
5174
- if (path4.isAbsolute(decoded)) {
5175
- return path4.normalize(decoded);
5445
+ if (path5.isAbsolute(decoded)) {
5446
+ return path5.normalize(decoded);
5176
5447
  }
5177
5448
  const rel = decoded.replace(/^\.(\/)?/, "");
5178
5449
  const serverRoot = $asai?.serverRoot;
5179
5450
  if (serverRoot && rel) {
5180
- const absRoot = path4.resolve(serverRoot);
5181
- const abs = path4.resolve(absRoot, rel);
5182
- const relCheck = path4.relative(absRoot, abs);
5183
- if (relCheck === "" || !relCheck.startsWith("..") && !path4.isAbsolute(relCheck)) {
5451
+ const absRoot = path5.resolve(serverRoot);
5452
+ const abs = path5.resolve(absRoot, rel);
5453
+ const relCheck = path5.relative(absRoot, abs);
5454
+ if (relCheck === "" || !relCheck.startsWith("..") && !path5.isAbsolute(relCheck)) {
5184
5455
  return abs;
5185
5456
  }
5186
5457
  }
@@ -5240,18 +5511,18 @@ __export(AsFs_exports, {
5240
5511
  write: () => write,
5241
5512
  writeJson: () => writeJson
5242
5513
  });
5243
- import fs9 from "fs/promises";
5244
- import path5 from "path";
5514
+ import fs10 from "fs/promises";
5515
+ import path6 from "path";
5245
5516
  async function ensureFile(filePath) {
5246
- const normalized = path5.normalize(filePath);
5247
- await fs9.mkdir(path5.dirname(normalized), { recursive: true });
5248
- const fh = await fs9.open(normalized, "a");
5517
+ const normalized = path6.normalize(filePath);
5518
+ await fs10.mkdir(path6.dirname(normalized), { recursive: true });
5519
+ const fh = await fs10.open(normalized, "a");
5249
5520
  await fh.close();
5250
5521
  }
5251
5522
  __name(ensureFile, "ensureFile");
5252
5523
  async function pathExists(filePath) {
5253
5524
  try {
5254
- await fs9.access(path5.normalize(filePath));
5525
+ await fs10.access(path6.normalize(filePath));
5255
5526
  return true;
5256
5527
  } catch {
5257
5528
  return false;
@@ -5259,7 +5530,7 @@ async function pathExists(filePath) {
5259
5530
  }
5260
5531
  __name(pathExists, "pathExists");
5261
5532
  async function readJson(filePath) {
5262
- const raw = await fs9.readFile(path5.normalize(filePath), "utf8");
5533
+ const raw = await fs10.readFile(path6.normalize(filePath), "utf8");
5263
5534
  return JSON.parse(raw);
5264
5535
  }
5265
5536
  __name(readJson, "readJson");
@@ -5270,34 +5541,34 @@ function resolvePathUnderBase(baseDir, relPath) {
5270
5541
  if (relPath.includes("\0")) {
5271
5542
  throw new Error("Invalid path");
5272
5543
  }
5273
- const base = path5.resolve(baseDir);
5274
- const target = path5.resolve(base, relPath.replace(/\\/g, "/"));
5275
- const rel = path5.relative(base, target);
5276
- if (rel.startsWith("..") || path5.isAbsolute(rel)) {
5544
+ const base = path6.resolve(baseDir);
5545
+ const target = path6.resolve(base, relPath.replace(/\\/g, "/"));
5546
+ const rel = path6.relative(base, target);
5547
+ if (rel.startsWith("..") || path6.isAbsolute(rel)) {
5277
5548
  throw new Error("Path not allowed");
5278
5549
  }
5279
5550
  return target;
5280
5551
  }
5281
5552
  __name(resolvePathUnderBase, "resolvePathUnderBase");
5282
5553
  async function readLogDir(dir) {
5283
- const resolved = path5.resolve(dir);
5284
- const stats = await fs9.stat(resolved);
5554
+ const resolved = path6.resolve(dir);
5555
+ const stats = await fs10.stat(resolved);
5285
5556
  if (!stats.isDirectory()) {
5286
5557
  throw new Error("Not a directory");
5287
5558
  }
5288
- const dirName = path5.basename(resolved);
5289
- const entries = await fs9.readdir(resolved, { withFileTypes: true });
5559
+ const dirName = path6.basename(resolved);
5560
+ const entries = await fs10.readdir(resolved, { withFileTypes: true });
5290
5561
  const children = await Promise.all(
5291
5562
  entries.map(async (entry) => {
5292
- const fullPath = path5.join(resolved, entry.name);
5293
- const st = await fs9.stat(fullPath);
5563
+ const fullPath = path6.join(resolved, entry.name);
5564
+ const st = await fs10.stat(fullPath);
5294
5565
  const dot = entry.name.lastIndexOf(".");
5295
5566
  const type = entry.isDirectory() ? "dir" : dot > -1 ? entry.name.substring(dot) : "file";
5296
5567
  return {
5297
5568
  name: entry.name,
5298
5569
  size: st.size,
5299
5570
  time: st.mtime.toISOString(),
5300
- path: path5.normalize(fullPath),
5571
+ path: path6.normalize(fullPath),
5301
5572
  type,
5302
5573
  created: st.birthtime.toISOString(),
5303
5574
  permissions: st.mode.toString(8).slice(-3)
@@ -5308,7 +5579,7 @@ async function readLogDir(dir) {
5308
5579
  name: dirName,
5309
5580
  size: stats.size,
5310
5581
  time: stats.mtime.toISOString(),
5311
- path: path5.normalize(resolved),
5582
+ path: path6.normalize(resolved),
5312
5583
  type: "dir",
5313
5584
  created: stats.birthtime.toISOString(),
5314
5585
  permissions: stats.mode.toString(8).slice(-3),
@@ -5318,7 +5589,7 @@ async function readLogDir(dir) {
5318
5589
  __name(readLogDir, "readLogDir");
5319
5590
  async function removeFile(filePath) {
5320
5591
  try {
5321
- await fs9.unlink(path5.normalize(filePath));
5592
+ await fs10.unlink(path6.normalize(filePath));
5322
5593
  } catch (err) {
5323
5594
  if (err?.code !== "ENOENT") throw err;
5324
5595
  }
@@ -5326,13 +5597,13 @@ async function removeFile(filePath) {
5326
5597
  __name(removeFile, "removeFile");
5327
5598
  var remove = removeFile;
5328
5599
  async function write(filePath, content) {
5329
- const normalized = path5.normalize(filePath);
5330
- await fs9.mkdir(path5.dirname(normalized), { recursive: true });
5331
- await fs9.writeFile(normalized, content, "utf8");
5600
+ const normalized = path6.normalize(filePath);
5601
+ await fs10.mkdir(path6.dirname(normalized), { recursive: true });
5602
+ await fs10.writeFile(normalized, content, "utf8");
5332
5603
  }
5333
5604
  __name(write, "write");
5334
5605
  async function read(filePath) {
5335
- return fs9.readFile(path5.normalize(filePath), "utf8");
5606
+ return fs10.readFile(path6.normalize(filePath), "utf8");
5336
5607
  }
5337
5608
  __name(read, "read");
5338
5609
  async function writeJson(filePath, data) {
@@ -5368,7 +5639,7 @@ __export(common_exports, {
5368
5639
  toSetObject: () => toSetObject,
5369
5640
  toWherePairs: () => toWherePairs
5370
5641
  });
5371
- import * as path6 from "path";
5642
+ import * as path7 from "path";
5372
5643
  function promisifySqlDb(query, sql) {
5373
5644
  return new Promise((resolve6, reject) => {
5374
5645
  query(sql, (err, result) => {
@@ -5433,11 +5704,11 @@ function toInsertRows(sql) {
5433
5704
  }
5434
5705
  __name(toInsertRows, "toInsertRows");
5435
5706
  function isPathInside(baseDir, targetPath) {
5436
- const base = path6.resolve(baseDir);
5437
- const target = path6.resolve(targetPath);
5438
- const relative5 = path6.relative(base, target);
5707
+ const base = path7.resolve(baseDir);
5708
+ const target = path7.resolve(targetPath);
5709
+ const relative5 = path7.relative(base, target);
5439
5710
  if (!relative5) return true;
5440
- return !relative5.startsWith("..") && !path6.isAbsolute(relative5);
5711
+ return !relative5.startsWith("..") && !path7.isAbsolute(relative5);
5441
5712
  }
5442
5713
  __name(isPathInside, "isPathInside");
5443
5714
  function joinTablePath(table, ...segments) {
@@ -5618,8 +5889,8 @@ var Sql_default = {
5618
5889
  };
5619
5890
 
5620
5891
  // src/sysserver/db/src/file/Index.ts
5621
- import * as fs10 from "fs";
5622
- import * as path7 from "path";
5892
+ import * as fs11 from "fs";
5893
+ import * as path8 from "path";
5623
5894
  function dbDriver(opt = {}) {
5624
5895
  const { Sql, DbCommon } = opt;
5625
5896
  const { isPathInside: isPathInside2, joinTablePath: joinTablePath2 } = DbCommon;
@@ -5633,20 +5904,20 @@ function dbDriver(opt = {}) {
5633
5904
  this.fileDel = (config.del || 0) !== 0;
5634
5905
  this.createDir = config.create || false;
5635
5906
  const root = config.$asai?.serverRoot || getPrimaryServerRoot();
5636
- this.baseDirAbs = path7.resolve(root, config.dir);
5907
+ this.baseDirAbs = path8.resolve(root, config.dir);
5637
5908
  }
5638
5909
  dbLog(...args) {
5639
5910
  (this.config?.$asai?.$log || console.log)("FILE", ...args);
5640
5911
  }
5641
5912
  checkFile(file) {
5642
- return fs10.existsSync(this.getAbsPath(file, false));
5913
+ return fs11.existsSync(this.getAbsPath(file, false));
5643
5914
  }
5644
5915
  /** 解析相对路径并限制在数据根目录内,防止路径穿越(跨平台) */
5645
5916
  resolvePath(relPath) {
5646
5917
  if (!relPath) {
5647
5918
  return this.baseDirAbs;
5648
5919
  }
5649
- const abs = path7.isAbsolute(relPath) ? path7.normalize(relPath) : path7.resolve(this.baseDirAbs, relPath);
5920
+ const abs = path8.isAbsolute(relPath) ? path8.normalize(relPath) : path8.resolve(this.baseDirAbs, relPath);
5650
5921
  if (!isPathInside2(this.baseDirAbs, abs)) {
5651
5922
  throw new Error("Path not allowed");
5652
5923
  }
@@ -5660,15 +5931,15 @@ function dbDriver(opt = {}) {
5660
5931
  if (!relPath) {
5661
5932
  return "";
5662
5933
  }
5663
- return path7.isAbsolute(relPath) ? path7.relative(this.baseDirAbs, relPath) : relPath;
5934
+ return path8.isAbsolute(relPath) ? path8.relative(this.baseDirAbs, relPath) : relPath;
5664
5935
  }
5665
5936
  ensureDir(relPath) {
5666
5937
  const relative5 = this.normalizeRelPath(relPath);
5667
- const dirPath = path7.dirname(relative5);
5938
+ const dirPath = path8.dirname(relative5);
5668
5939
  const absDir = this.resolvePath(dirPath === "." ? "" : dirPath);
5669
- if (this.createDir && !fs10.existsSync(absDir)) {
5940
+ if (this.createDir && !fs11.existsSync(absDir)) {
5670
5941
  this.dbLog("mkdir", "[MKDIR]", absDir);
5671
- fs10.mkdirSync(absDir, { recursive: true });
5942
+ fs11.mkdirSync(absDir, { recursive: true });
5672
5943
  }
5673
5944
  return absDir;
5674
5945
  }
@@ -5684,34 +5955,34 @@ function dbDriver(opt = {}) {
5684
5955
  }
5685
5956
  deldir(relativePath) {
5686
5957
  const absPath = this.resolvePath(relativePath);
5687
- if (!fs10.existsSync(absPath)) {
5958
+ if (!fs11.existsSync(absPath)) {
5688
5959
  return;
5689
5960
  }
5690
5961
  this.dbLog("delete", "[RMDIR]", absPath);
5691
- const entries = fs10.readdirSync(absPath, { withFileTypes: true });
5962
+ const entries = fs11.readdirSync(absPath, { withFileTypes: true });
5692
5963
  for (const entry of entries) {
5693
- const current = path7.join(absPath, entry.name);
5964
+ const current = path8.join(absPath, entry.name);
5694
5965
  if (entry.isDirectory()) {
5695
- this.deldir(path7.join(relativePath, entry.name));
5966
+ this.deldir(path8.join(relativePath, entry.name));
5696
5967
  } else {
5697
5968
  this.dbLog("delete", "[UNLINK]", current);
5698
- fs10.unlinkSync(current);
5969
+ fs11.unlinkSync(current);
5699
5970
  }
5700
5971
  }
5701
- fs10.rmdirSync(absPath);
5972
+ fs11.rmdirSync(absPath);
5702
5973
  }
5703
5974
  getReadPath(file, sql) {
5704
5975
  const candidates = [];
5705
5976
  if (sql?.filename) {
5706
- candidates.push({ dir: path7.join(file, sql.filename) });
5707
- candidates.push({ dir: path7.join(file + ".delete" + this.fileExt, sql.filename) });
5977
+ candidates.push({ dir: path8.join(file, sql.filename) });
5978
+ candidates.push({ dir: path8.join(file + ".delete" + this.fileExt, sql.filename) });
5708
5979
  } else {
5709
5980
  candidates.push({ dir: file });
5710
5981
  candidates.push({ dir: file + this.fileExt + ".delete" });
5711
5982
  }
5712
5983
  for (const candidate of candidates) {
5713
5984
  const abs = this.getAbsPath(candidate.dir, false);
5714
- if (fs10.existsSync(abs)) {
5985
+ if (fs11.existsSync(abs)) {
5715
5986
  return { path: abs, dir: candidate.dir };
5716
5987
  }
5717
5988
  }
@@ -5723,13 +5994,13 @@ function dbDriver(opt = {}) {
5723
5994
  return { path: "", dir: read2.dir };
5724
5995
  }
5725
5996
  if (sql?.filename) {
5726
- return { path: path7.dirname(read2.path), dir: path7.dirname(read2.dir) };
5997
+ return { path: path8.dirname(read2.path), dir: path8.dirname(read2.dir) };
5727
5998
  }
5728
5999
  return { path: read2.path, dir: read2.dir };
5729
6000
  }
5730
6001
  getNewPath(file, sql) {
5731
6002
  if (sql?.filename) {
5732
- return this.getAbsPath(path7.join(file, sql.filename), true);
6003
+ return this.getAbsPath(path8.join(file, sql.filename), true);
5733
6004
  }
5734
6005
  return this.getAbsPath(file, true);
5735
6006
  }
@@ -5737,7 +6008,7 @@ function dbDriver(opt = {}) {
5737
6008
  try {
5738
6009
  const filePath = sql?.type === "insert" ? this.getNewPath(file, sql) : this.getReadPath(file, sql).path || this.getNewPath(file, sql);
5739
6010
  this.dbLog("write", "[WRITE]", filePath);
5740
- fs10.writeFileSync(filePath, data, "utf8");
6011
+ fs11.writeFileSync(filePath, data, "utf8");
5741
6012
  return "ok";
5742
6013
  } catch (e) {
5743
6014
  this.dbLog("write failed", "[WRITE ERROR]", e);
@@ -5751,7 +6022,7 @@ function dbDriver(opt = {}) {
5751
6022
  return { error: "empty" };
5752
6023
  }
5753
6024
  this.dbLog("read", "[READ]", read2.path);
5754
- const data = fs10.readFileSync(read2.path, { encoding }) || "";
6025
+ const data = fs11.readFileSync(read2.path, { encoding }) || "";
5755
6026
  const fileName = this.fileExt && read2.dir.endsWith(this.fileExt) ? read2.dir : read2.dir + this.fileExt;
5756
6027
  return [{ data, file: fileName }];
5757
6028
  } catch (e) {
@@ -5768,12 +6039,12 @@ function dbDriver(opt = {}) {
5768
6039
  if (this.fileDel && sql?.deltrue) {
5769
6040
  const target = del.path + ".delete" + this.fileExt;
5770
6041
  this.dbLog("soft delete", "[SOFT DELETE]", `${del.path} -> ${target}`);
5771
- fs10.renameSync(del.path, target);
6042
+ fs11.renameSync(del.path, target);
5772
6043
  } else if (sql?.filename) {
5773
6044
  this.deldir(del.dir);
5774
6045
  } else {
5775
6046
  this.dbLog("delete", "[DELETE]", del.path);
5776
- fs10.unlinkSync(del.path);
6047
+ fs11.unlinkSync(del.path);
5777
6048
  }
5778
6049
  return "ok";
5779
6050
  } catch (e) {
@@ -5792,11 +6063,11 @@ function dbDriver(opt = {}) {
5792
6063
  const original = del.path.replace(new RegExp(`.delete${extPattern}$`), "");
5793
6064
  if (original !== del.path) {
5794
6065
  this.dbLog("restore", "[RESTORE]", `${del.path} -> ${original}`);
5795
- fs10.renameSync(del.path, original);
6066
+ fs11.renameSync(del.path, original);
5796
6067
  }
5797
6068
  } else {
5798
6069
  this.dbLog("force delete", "[FORCE DELETE]", del.path);
5799
- fs10.unlinkSync(del.path);
6070
+ fs11.unlinkSync(del.path);
5800
6071
  }
5801
6072
  return "ok";
5802
6073
  } catch (e) {
@@ -5810,7 +6081,7 @@ function dbDriver(opt = {}) {
5810
6081
  this.dbLog("list", "[LIST]", absDir);
5811
6082
  let entries;
5812
6083
  try {
5813
- entries = fs10.readdirSync(absDir, { withFileTypes: true });
6084
+ entries = fs11.readdirSync(absDir, { withFileTypes: true });
5814
6085
  } catch {
5815
6086
  return sql?.list ? { open: [], delete: [] } : [];
5816
6087
  }
@@ -5822,9 +6093,9 @@ function dbDriver(opt = {}) {
5822
6093
  const isDelete = fileName.endsWith(deleteSuffix);
5823
6094
  const baseName = isDelete ? fileName.slice(0, -deleteSuffix.length) : fileName;
5824
6095
  if (this.fileExt && !baseName.endsWith(this.fileExt)) continue;
5825
- const fullPath = path7.join(absDir, fileName);
6096
+ const fullPath = path8.join(absDir, fileName);
5826
6097
  try {
5827
- const data = fs10.readFileSync(fullPath, "utf8");
6098
+ const data = fs11.readFileSync(fullPath, "utf8");
5828
6099
  const entryData = { data, file: baseName };
5829
6100
  if (isDelete) {
5830
6101
  if (sql?.list) result.delete.push(entryData);
@@ -6590,7 +6861,7 @@ var initAsaiHostNodejs2 = {
6590
6861
  createTransportDataHandler,
6591
6862
  wireTransportConnectionLogs
6592
6863
  };
6593
- var PLUGIN_VERSION = true ? "0.0.8" : "0.0.1";
6864
+ var PLUGIN_VERSION = true ? "0.0.10" : "0.0.1";
6594
6865
  var index_default = initAsaiHostNodejs2;
6595
6866
  export {
6596
6867
  Index_default as AsaiCommon,