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
@@ -4,17 +4,19 @@ import {
4
4
  logSecurityConfigIntervention,
5
5
  logSessionTerminate,
6
6
  logUserRbacChange
7
- } from "./chunk-SB23ESX2.es.js";
7
+ } from "./chunk-GCR56QH7.es.js";
8
8
  import {
9
9
  InterventionLog_exports
10
- } from "./chunk-VUZO7DCA.es.js";
10
+ } from "./chunk-N6LBKGML.es.js";
11
11
  import {
12
+ AsPath_exports,
12
13
  LogStore_exports,
13
14
  archiveInterventionYear,
14
15
  exportLogContent,
15
16
  getComplianceReport,
16
17
  getEffectiveStoreType,
17
18
  getLogStoreMeta,
19
+ getPrimaryServerRoot,
18
20
  getUnifiedEntry,
19
21
  getUnifiedStats,
20
22
  groupsToInterventionFiles,
@@ -28,7 +30,7 @@ import {
28
30
  queryUnifiedLogs,
29
31
  readWebLogFromStore,
30
32
  searchUnifiedLogs
31
- } from "./chunk-LTEP4XB2.es.js";
33
+ } from "./chunk-EC67M7RR.es.js";
32
34
  import {
33
35
  W3C_ACCESS_FIELDS,
34
36
  W3C_SERVER_FIELDS,
@@ -48,7 +50,7 @@ import {
48
50
  secureCompare,
49
51
  validatePasswordChange,
50
52
  verifyPassword
51
- } from "./chunk-57UQJKSL.es.js";
53
+ } from "./chunk-OTL2B4WS.es.js";
52
54
  import {
53
55
  USER_LV,
54
56
  applySecretsToHostConfig,
@@ -60,7 +62,7 @@ import {
60
62
  resolveHttpsCertFromPaths,
61
63
  stripForbiddenSecretsFromHostConfig,
62
64
  validateAsaiSecrets
63
- } from "./chunk-A6VJPLDD.es.js";
65
+ } from "./chunk-5WJQD4RZ.es.js";
64
66
  import {
65
67
  getDefaultResetPassword,
66
68
  getPasswordPolicy,
@@ -73,7 +75,7 @@ import {
73
75
  resolveRoleForLevel,
74
76
  saveUserLevelConfig,
75
77
  validatePasswordWithPolicy
76
- } from "./chunk-A5CDJGJI.es.js";
78
+ } from "./chunk-BOIRAQXE.es.js";
77
79
  import {
78
80
  getDataServerForAsDb
79
81
  } from "./chunk-ZQBHJRAO.es.js";
@@ -212,7 +214,7 @@ ${reason.name}: ${reason.message}`;
212
214
  if (restartTimes.length > MAX_RESTARTS) {
213
215
  try {
214
216
  $asai.$log("NO_RESTART", "Process crashed too frequently, gracefully shutdown and wait for daemon restart.");
215
- void import("./intervention-hooks-TCGIC4IV.es.js").then(
217
+ void import("./intervention-hooks-QNA4IZT7.es.js").then(
216
218
  ({ logProcessGuardEvent }) => logProcessGuardEvent($asai, {
217
219
  action: "crash_loop_shutdown",
218
220
  detail: `${restartTimes.length} crashes in ${RESTART_WINDOW}ms window`,
@@ -254,7 +256,7 @@ ${reason.name}: ${reason.message}`;
254
256
  }
255
257
  __name(initProcess, "initProcess");
256
258
  function gracefulShutdown($asai) {
257
- void import("./intervention-hooks-TCGIC4IV.es.js").then(
259
+ void import("./intervention-hooks-QNA4IZT7.es.js").then(
258
260
  ({ logProcessGuardEvent }) => logProcessGuardEvent($asai, {
259
261
  action: "graceful_shutdown",
260
262
  detail: "SIGTERM/SIGINT or crash guard triggered",
@@ -397,7 +399,7 @@ var LogBuffer = class _LogBuffer {
397
399
  }
398
400
  };
399
401
  function saveLog($asai, src, logstr) {
400
- return new Promise((resolve6, reject) => {
402
+ return new Promise((resolve5, reject) => {
401
403
  try {
402
404
  const bufferKey = `${$asai.id || "default"}_${src}`;
403
405
  let logBuffer = logBuffers.get(bufferKey);
@@ -406,7 +408,7 @@ function saveLog($asai, src, logstr) {
406
408
  logBuffers.set(bufferKey, logBuffer);
407
409
  }
408
410
  logBuffer.add(logstr);
409
- resolve6();
411
+ resolve5();
410
412
  } catch (err) {
411
413
  console.error(err);
412
414
  reject(err);
@@ -872,7 +874,7 @@ function initAsaiHostNodejs($asai, _opt) {
872
874
  type: "CONFIG_WARN",
873
875
  detail: "Using dev-only password; set ASAI_HOST_PASSWORD for production (IEC 62443-4-2 CR 1.7)"
874
876
  });
875
- void import("./intervention-hooks-TCGIC4IV.es.js").then(
877
+ void import("./intervention-hooks-QNA4IZT7.es.js").then(
876
878
  ({ logSecurityConfigIntervention: logSecurityConfigIntervention2 }) => logSecurityConfigIntervention2($asai, {
877
879
  section: "password",
878
880
  detail: "dev-default-password detected at startup"
@@ -898,7 +900,7 @@ function scheduleLogComplianceCheck($asai) {
898
900
  if (hours <= 0) return;
899
901
  const ms = hours * 3600 * 1e3;
900
902
  setInterval(() => {
901
- void import("./LogStore-Q35YFNAY.es.js").then(
903
+ void import("./LogStore-DWIPPRCA.es.js").then(
902
904
  ({ getComplianceReport: getComplianceReport2 }) => getComplianceReport2($asai, "prod")
903
905
  ).catch(() => void 0);
904
906
  }, ms);
@@ -1582,10 +1584,10 @@ function getStaticBaseDirs($asai) {
1582
1584
  bases.push(abs);
1583
1585
  }
1584
1586
  }, "add");
1587
+ if ($asai.serverRoot) add($asai.serverRoot);
1585
1588
  if (Array.isArray($asai.runtimeBaseDirs)) {
1586
1589
  for (const b of $asai.runtimeBaseDirs) add(b);
1587
1590
  }
1588
- if ($asai.serverRoot) add($asai.serverRoot);
1589
1591
  if ($asai.pkgSnapshotDir) add($asai.pkgSnapshotDir);
1590
1592
  return bases;
1591
1593
  }
@@ -1652,6 +1654,11 @@ function parseUrlPath(requrl) {
1652
1654
  }
1653
1655
  __name(parseUrlPath, "parseUrlPath");
1654
1656
  var STATIC_ASSET_PREFIXES = ["/assets/", "/webmodel/", "/assets/entry/", "/assets/chunk/"];
1657
+ function isMutableWebmodelConfig(urlPath) {
1658
+ const p = parseUrlPath(urlPath);
1659
+ return /^\/webmodel\/sys\/setting\/[^/]+\.json$/i.test(p);
1660
+ }
1661
+ __name(isMutableWebmodelConfig, "isMutableWebmodelConfig");
1655
1662
  function isStaticAssetPath(urlPath, indexFile) {
1656
1663
  const p = parseUrlPath(urlPath);
1657
1664
  const base = p.split("/").pop() || "";
@@ -1660,9 +1667,10 @@ function isStaticAssetPath(urlPath, indexFile) {
1660
1667
  return /\.(css|js|mjs|cjs|json|png|jpe?g|gif|svg|ico|woff2?|ttf|map|wasm|zip)(\?|$)/i.test(p);
1661
1668
  }
1662
1669
  __name(isStaticAssetPath, "isStaticAssetPath");
1663
- function sendStaticBuffer(req, res, data, mimeType, mtimeMs, $asai) {
1670
+ function sendStaticBuffer(req, res, data, mimeType, mtimeMs, $asai, urlPath = "") {
1664
1671
  const etag = `"${data.length}-${mtimeMs}"`;
1665
- if (req.headers["if-none-match"] === etag) {
1672
+ const noCache = isMutableWebmodelConfig(urlPath);
1673
+ if (!noCache && req.headers["if-none-match"] === etag) {
1666
1674
  res.writeHead(304);
1667
1675
  res.end();
1668
1676
  return;
@@ -1671,7 +1679,7 @@ function sendStaticBuffer(req, res, data, mimeType, mtimeMs, $asai) {
1671
1679
  res.writeHead(200, {
1672
1680
  "Content-Type": mimeType,
1673
1681
  "Content-Length": data.length,
1674
- "Cache-Control": "public, max-age=3600",
1682
+ "Cache-Control": noCache ? "no-cache, must-revalidate" : "public, max-age=3600",
1675
1683
  ETag: etag,
1676
1684
  "Last-Modified": new Date(mtimeMs).toUTCString()
1677
1685
  });
@@ -1685,7 +1693,8 @@ function sendStaticBuffer(req, res, data, mimeType, mtimeMs, $asai) {
1685
1693
  }
1686
1694
  }
1687
1695
  __name(sendStaticBuffer, "sendStaticBuffer");
1688
- function serveStaticFile(req, res, foundPath, mimeType, stat, $asai) {
1696
+ function serveStaticFile(req, res, foundPath, mimeType, stat, $asai, urlPath = "") {
1697
+ const noCache = isMutableWebmodelConfig(urlPath);
1689
1698
  if (stat.size <= STATIC_READ_MAX) {
1690
1699
  fs6.readFile(foundPath, (err, data) => {
1691
1700
  if (err) {
@@ -1696,13 +1705,13 @@ function serveStaticFile(req, res, foundPath, mimeType, stat, $asai) {
1696
1705
  }
1697
1706
  return;
1698
1707
  }
1699
- sendStaticBuffer(req, res, data, mimeType, stat.mtimeMs, $asai);
1708
+ sendStaticBuffer(req, res, data, mimeType, stat.mtimeMs, $asai, urlPath);
1700
1709
  });
1701
1710
  return;
1702
1711
  }
1703
1712
  const readStream = fs6.createReadStream(foundPath);
1704
1713
  const etag = `"${stat.size}-${stat.mtimeMs}"`;
1705
- if (req.headers["if-none-match"] === etag) {
1714
+ if (!noCache && req.headers["if-none-match"] === etag) {
1706
1715
  readStream.destroy();
1707
1716
  res.writeHead(304);
1708
1717
  res.end();
@@ -1721,7 +1730,7 @@ function serveStaticFile(req, res, foundPath, mimeType, stat, $asai) {
1721
1730
  try {
1722
1731
  res.writeHead(200, {
1723
1732
  "Content-Type": mimeType,
1724
- "Cache-Control": "public, max-age=3600",
1733
+ "Cache-Control": noCache ? "no-cache, must-revalidate" : "public, max-age=3600",
1725
1734
  ETag: etag,
1726
1735
  "Last-Modified": stat.mtime.toUTCString()
1727
1736
  });
@@ -1779,7 +1788,7 @@ function createStaticHandler(ctx) {
1779
1788
  return;
1780
1789
  }
1781
1790
  const mimeType = hostcfg.mimetypes?.[nodePath2.extname(found.filePath)] || "application/octet-stream";
1782
- serveStaticFile(req, res, found.filePath, mimeType, found.stat, $asai);
1791
+ serveStaticFile(req, res, found.filePath, mimeType, found.stat, $asai, processedUrl);
1783
1792
  }, "showHostDirs");
1784
1793
  return (req, res, url) => {
1785
1794
  res.setHeader("Cross-Origin-Resource-Policy", "cross-origin");
@@ -2342,7 +2351,7 @@ async function attachServerUserLevel(req, $asai) {
2342
2351
  if (!Array.isArray(userinfo) || !userinfo[0]) return;
2343
2352
  const us = String(userinfo[0]);
2344
2353
  try {
2345
- const { createUserStore: createUserStore2 } = await import("./user-store-UC5URX3C.es.js");
2354
+ const { createUserStore: createUserStore2 } = await import("./user-store-FXD2N55G.es.js");
2346
2355
  const user = await createUserStore2($asai).findByUsername(us);
2347
2356
  if (user && user.status === "active") {
2348
2357
  req._serverUser = { us: user.us, lv: user.lv, status: user.status };
@@ -2526,7 +2535,7 @@ __name(isApiCorsAllowed, "isApiCorsAllowed");
2526
2535
 
2527
2536
  // src/common/server/Api.ts
2528
2537
  function readRequestBody(req, maxBody) {
2529
- return new Promise((resolve6, reject) => {
2538
+ return new Promise((resolve5, reject) => {
2530
2539
  const chunks = [];
2531
2540
  let received = 0;
2532
2541
  let settled = false;
@@ -2534,7 +2543,7 @@ function readRequestBody(req, maxBody) {
2534
2543
  if (settled) return;
2535
2544
  settled = true;
2536
2545
  if (err) reject(err);
2537
- else resolve6(data ?? "");
2546
+ else resolve5(data ?? "");
2538
2547
  }, "finish");
2539
2548
  req.on("data", (chunk) => {
2540
2549
  if (settled) return;
@@ -2555,6 +2564,10 @@ function isRawUploadPost(url = "") {
2555
2564
  return /\/api\/asaifile\/manage\/up(?:base64|binary)(?:batch)?\//.test(url);
2556
2565
  }
2557
2566
  __name(isRawUploadPost, "isRawUploadPost");
2567
+ function isPlainSourcePost(url = "") {
2568
+ return /\/api\/robotcode\//.test(url);
2569
+ }
2570
+ __name(isPlainSourcePost, "isPlainSourcePost");
2558
2571
  function processPostPayload($asai, req, postdata, pm) {
2559
2572
  let isAes = false;
2560
2573
  let out = postdata;
@@ -2570,7 +2583,7 @@ function processPostPayload($asai, req, postdata, pm) {
2570
2583
  }
2571
2584
  }
2572
2585
  const plainJson = typeof out === "string" && out.trimStart().startsWith("{");
2573
- if (req?.Userinfo?.[2] && !plainJson && !isRawUploadPost(req?.url)) {
2586
+ if (req?.Userinfo?.[2] && !plainJson && !isRawUploadPost(req?.url) && !isPlainSourcePost(req?.url)) {
2574
2587
  pm = req.Userinfo[2];
2575
2588
  out = $asai.$lib.AsCode.asdecode(out, pm);
2576
2589
  }
@@ -2909,7 +2922,7 @@ var WsClient_default = /* @__PURE__ */ __name(($asai, wsname) => {
2909
2922
  }
2910
2923
  __name(getKeyByData, "getKeyByData");
2911
2924
  function clientwsInit() {
2912
- return new Promise((resolve6, reject) => {
2925
+ return new Promise((resolve5, reject) => {
2913
2926
  $asai.clientws[wsname].socket = new $asai.asaiWs(
2914
2927
  $asai.command.commandconfig.clientws[wsname]
2915
2928
  );
@@ -2939,7 +2952,7 @@ var WsClient_default = /* @__PURE__ */ __name(($asai, wsname) => {
2939
2952
  `${wsname}=${$asai.command.commandconfig.clientws[wsname]} is open.`
2940
2953
  );
2941
2954
  $asai.clientws[wsname].open = 1;
2942
- resolve6();
2955
+ resolve5();
2943
2956
  };
2944
2957
  });
2945
2958
  }
@@ -2969,7 +2982,7 @@ var WsClient_default = /* @__PURE__ */ __name(($asai, wsname) => {
2969
2982
  }
2970
2983
  __name(clientwsOnmessage, "clientwsOnmessage");
2971
2984
  function clientwsApi(messageData) {
2972
- return new Promise((resolve6, reject) => {
2985
+ return new Promise((resolve5, reject) => {
2973
2986
  if ($asai.clientws[wsname].open) {
2974
2987
  try {
2975
2988
  const taskOpt = {};
@@ -2981,7 +2994,7 @@ var WsClient_default = /* @__PURE__ */ __name(($asai, wsname) => {
2981
2994
  getKeyByData(messageData),
2982
2995
  {
2983
2996
  callback: /* @__PURE__ */ __name((res) => {
2984
- resolve6(res);
2997
+ resolve5(res);
2985
2998
  }, "callback"),
2986
2999
  ...messageData,
2987
3000
  ...taskOpt
@@ -4052,7 +4065,7 @@ var login_default = /* @__PURE__ */ __name(($asai) => {
4052
4065
  passwordChangedAt: Date.now(),
4053
4066
  passHistory
4054
4067
  });
4055
- logSecurityEvent($asai, { type: "AUTH_FAIL", path: url, method: "POST", user: us, ip, detail: "password_changed" });
4068
+ logSecurityEvent($asai, { type: "AUTH_SUCCESS", path: url, method: "POST", user: us, ip, detail: "password_changed" });
4056
4069
  return sendSuccess(res, { ok: true }, opt);
4057
4070
  } catch (err) {
4058
4071
  return sendFail(res, err?.message || err, opt);
@@ -4085,7 +4098,7 @@ var login_default = /* @__PURE__ */ __name(($asai) => {
4085
4098
  passwordChangedAt: Date.now(),
4086
4099
  passHistory: "[]"
4087
4100
  });
4088
- logSecurityEvent($asai, { type: "AUTH_FAIL", path: url, method: "POST", user: us, ip, detail: "register_ok" });
4101
+ logSecurityEvent($asai, { type: "AUTH_SUCCESS", path: url, method: "POST", user: us, ip, detail: "register_ok" });
4089
4102
  return sendSuccess(res, { user: publicUser($asai, user) }, opt);
4090
4103
  } catch (err) {
4091
4104
  const msg = err?.message || String(err);
@@ -4139,7 +4152,7 @@ var login_default = /* @__PURE__ */ __name(($asai) => {
4139
4152
  const session = buildSessionRecord($asai, us, ip);
4140
4153
  session.lastActivityAt = Date.now();
4141
4154
  await store.addSession(session);
4142
- logSecurityEvent($asai, { type: "AUTH_FAIL", path: url, method: "POST", user: us, ip, detail: "login_ok" });
4155
+ logSecurityEvent($asai, { type: "AUTH_SUCCESS", path: url, method: "POST", user: us, ip, detail: "login_ok" });
4143
4156
  return sendSuccess(
4144
4157
  res,
4145
4158
  {
@@ -4157,9 +4170,18 @@ var login_default = /* @__PURE__ */ __name(($asai) => {
4157
4170
  if (url.startsWith("/api/user/login/logout/")) {
4158
4171
  try {
4159
4172
  const bodySid = body.sessionId ? sanitizeString(body.sessionId, 64) : "";
4160
- if (bodySid) await store.removeSession(bodySid);
4161
4173
  const us = req?.Userinfo?.[0];
4162
- if (us) logSecurityEvent($asai, { type: "AUTH_FAIL", path: url, method: "POST", user: String(us), ip, detail: "logout" });
4174
+ if (bodySid) {
4175
+ if (!us) {
4176
+ return sendErr(res, "AUTH_MISSING", void 0, opt);
4177
+ }
4178
+ const sessions = await store.getSessions();
4179
+ const target = sessions.find((s) => s.id === bodySid);
4180
+ if (target && target.us === us) {
4181
+ await store.removeSession(bodySid);
4182
+ }
4183
+ }
4184
+ if (us) logSecurityEvent($asai, { type: "AUTH_SUCCESS", path: url, method: "POST", user: String(us), ip, detail: "logout" });
4163
4185
  return sendSuccess(res, "ok", opt);
4164
4186
  } catch (err) {
4165
4187
  return sendFail(res, err?.message || err, opt);
@@ -4499,10 +4521,10 @@ var As_default = {
4499
4521
  return relativePath;
4500
4522
  },
4501
4523
  //创建多层文件夹 同步
4502
- ensureDir(fs12, relativePath) {
4524
+ ensureDir(fs11, relativePath) {
4503
4525
  const absPathDir = this.toDirPath(relativePath);
4504
4526
  const absPath = this.toAbsolutePath(relativePath);
4505
- if (!fs12.existsSync(absPath)) {
4527
+ if (!fs11.existsSync(absPath)) {
4506
4528
  let pathTmp = "";
4507
4529
  absPathDir.split("/").forEach((el) => {
4508
4530
  if (el) {
@@ -4510,8 +4532,8 @@ var As_default = {
4510
4532
  pathTmp += "/";
4511
4533
  }
4512
4534
  pathTmp += el;
4513
- if (!fs12.existsSync(pathTmp)) {
4514
- if (!fs12.mkdirSync(pathTmp, { recursive: true })) {
4535
+ if (!fs11.existsSync(pathTmp)) {
4536
+ if (!fs11.mkdirSync(pathTmp, { recursive: true })) {
4515
4537
  return absPath;
4516
4538
  }
4517
4539
  }
@@ -4520,11 +4542,11 @@ var As_default = {
4520
4542
  }
4521
4543
  return absPath;
4522
4544
  },
4523
- makeDir(fs12, filePaths) {
4524
- return new Promise((resolve6, reject) => {
4545
+ makeDir(fs11, filePaths) {
4546
+ return new Promise((resolve5, reject) => {
4525
4547
  try {
4526
- const newPath = this.ensureDir(fs12, filePaths);
4527
- resolve6(newPath);
4548
+ const newPath = this.ensureDir(fs11, filePaths);
4549
+ resolve5(newPath);
4528
4550
  } catch (err) {
4529
4551
  reject(err);
4530
4552
  }
@@ -4976,8 +4998,36 @@ var AsDb_default = /* @__PURE__ */ __name(($asai, cfg) => {
4976
4998
  return resdb;
4977
4999
  }
4978
5000
  __name(dbFresh, "dbFresh");
5001
+ function normalizeFileSelectRow(row) {
5002
+ const nameKey = cfg.field?.data?.[0] || "name";
5003
+ const contentKey = cfg.field?.data?.[1] || "content";
5004
+ if (!row || typeof row !== "object") return row;
5005
+ const out = { ...row };
5006
+ if (out[nameKey] != null) {
5007
+ out[nameKey] = bareFileName(String(out[nameKey]));
5008
+ }
5009
+ const raw = out[contentKey];
5010
+ if (raw != null && typeof raw !== "string") {
5011
+ out[contentKey] = JSON.stringify(raw);
5012
+ }
5013
+ return out;
5014
+ }
5015
+ __name(normalizeFileSelectRow, "normalizeFileSelectRow");
5016
+ function isFileSingleNameSelect(params) {
5017
+ return cfg?.type === "file" && params?.type === "select" && !!params?.where?.length;
5018
+ }
5019
+ __name(isFileSingleNameSelect, "isFileSingleNameSelect");
4979
5020
  function normalizeSelectResult(params, resdb) {
4980
5021
  let data = resdb;
5022
+ if (isFileSingleNameSelect(params)) {
5023
+ if (Array.isArray(data)) {
5024
+ return data.map(normalizeFileSelectRow);
5025
+ }
5026
+ if (data && typeof data === "object") {
5027
+ return [normalizeFileSelectRow(data)];
5028
+ }
5029
+ return data;
5030
+ }
4981
5031
  if (params?.where?.length && Array.isArray(data) && data.length === 1) {
4982
5032
  data = data[0];
4983
5033
  }
@@ -5003,7 +5053,9 @@ var AsDb_default = /* @__PURE__ */ __name(($asai, cfg) => {
5003
5053
  __name(normalizeSelectResult, "normalizeSelectResult");
5004
5054
  function dbCodePm(req, resdb) {
5005
5055
  if (req?.Userinfo && req?.Userinfo[2]) {
5006
- resdb.data = $asai.$lib.AsCode.asencode(JSON.stringify(resdb.data), req.Userinfo[2]);
5056
+ if (resdb != null && typeof resdb === "object") {
5057
+ resdb.data = $asai.$lib.AsCode.asencode(JSON.stringify(resdb.data), req.Userinfo[2]);
5058
+ }
5007
5059
  }
5008
5060
  return resdb;
5009
5061
  }
@@ -5101,7 +5153,19 @@ var reqWork_default = /* @__PURE__ */ __name(($asai) => {
5101
5153
  __name(hostDefault2, "hostDefault");
5102
5154
  function getPathFromOpt(opt) {
5103
5155
  const rawPath = opt.qrdata?.path || opt.data?.path;
5104
- return decodeURIComponent(rawPath);
5156
+ if (!rawPath) {
5157
+ throw new Error("Missing path");
5158
+ }
5159
+ const decoded = decodeURIComponent(String(rawPath));
5160
+ const roots = $asai?.asaihost?.getHostAllowedRoots?.($asai?.hostconfig) || [];
5161
+ if (!roots.length) {
5162
+ const fallback = $asai?.serverRoot || process.cwd();
5163
+ if (fallback) roots.push(fallback);
5164
+ }
5165
+ if (!$asai?.asaihost?.resolvePathUnderRoots) {
5166
+ throw new Error("Path resolver unavailable");
5167
+ }
5168
+ return $asai.asaihost.resolvePathUnderRoots(decoded, roots);
5105
5169
  }
5106
5170
  __name(getPathFromOpt, "getPathFromOpt");
5107
5171
  function sendSuccess(res, data, opt) {
@@ -5249,83 +5313,6 @@ async function writeJson(filePath, data) {
5249
5313
  }
5250
5314
  __name(writeJson, "writeJson");
5251
5315
 
5252
- // src/sysserver/lib/common/AsPath.ts
5253
- var AsPath_exports = {};
5254
- __export(AsPath_exports, {
5255
- getEntryDir: () => getEntryDir,
5256
- getExecDir: () => getExecDir,
5257
- getPkgSnapshotDir: () => getPkgSnapshotDir,
5258
- getPrimaryServerRoot: () => getPrimaryServerRoot,
5259
- getRuntimeBaseDirs: () => getRuntimeBaseDirs,
5260
- isPkgRuntime: () => isPkgRuntime
5261
- });
5262
- import * as fs10 from "fs";
5263
- import * as nodePath4 from "path";
5264
- function isPkgRuntime() {
5265
- return typeof process.pkg !== "undefined";
5266
- }
5267
- __name(isPkgRuntime, "isPkgRuntime");
5268
- function getPkgSnapshotDir() {
5269
- if (!isPkgRuntime()) return void 0;
5270
- const entry = process.pkg?.entrypoint ?? process.pkg?.defaultEntrypoint;
5271
- if (!entry) return void 0;
5272
- return nodePath4.resolve(nodePath4.dirname(entry));
5273
- }
5274
- __name(getPkgSnapshotDir, "getPkgSnapshotDir");
5275
- function getEntryDir() {
5276
- const snapshot = getPkgSnapshotDir();
5277
- if (snapshot) return snapshot;
5278
- const entry = process.argv[1];
5279
- if (!entry) {
5280
- return nodePath4.dirname(process.execPath);
5281
- }
5282
- return nodePath4.resolve(nodePath4.dirname(entry));
5283
- }
5284
- __name(getEntryDir, "getEntryDir");
5285
- function getExecDir() {
5286
- return nodePath4.dirname(process.execPath);
5287
- }
5288
- __name(getExecDir, "getExecDir");
5289
- function getRuntimeBaseDirs() {
5290
- const bases = [];
5291
- const seen = /* @__PURE__ */ new Set();
5292
- const add = /* @__PURE__ */ __name((p) => {
5293
- if (!p) return;
5294
- const abs = nodePath4.resolve(p);
5295
- if (!seen.has(abs)) {
5296
- seen.add(abs);
5297
- bases.push(abs);
5298
- }
5299
- }, "add");
5300
- add(process.cwd());
5301
- add(getExecDir());
5302
- if (isPkgRuntime()) {
5303
- add(getPkgSnapshotDir());
5304
- } else {
5305
- const entryDir = getEntryDir();
5306
- if (entryDir !== getExecDir()) {
5307
- add(entryDir);
5308
- }
5309
- }
5310
- return bases;
5311
- }
5312
- __name(getRuntimeBaseDirs, "getRuntimeBaseDirs");
5313
- function getPrimaryServerRoot() {
5314
- for (const base of getRuntimeBaseDirs()) {
5315
- try {
5316
- if (fs10.statSync(nodePath4.join(base, "websys")).isDirectory()) {
5317
- return base;
5318
- }
5319
- } catch {
5320
- }
5321
- }
5322
- if (isPkgRuntime()) {
5323
- return getExecDir();
5324
- }
5325
- return getEntryDir();
5326
- }
5327
- __name(getPrimaryServerRoot, "getPrimaryServerRoot");
5328
-
5329
5316
  // src/sysserver/lib/index.ts
5330
5317
  var lib_default = {
5331
5318
  As: As_default,
@@ -5356,17 +5343,17 @@ __export(common_exports, {
5356
5343
  });
5357
5344
  import * as path5 from "path";
5358
5345
  function promisifySqlDb(query, sql) {
5359
- return new Promise((resolve6, reject) => {
5346
+ return new Promise((resolve5, reject) => {
5360
5347
  query(sql, (err, result) => {
5361
5348
  if (err) {
5362
5349
  reject(err);
5363
5350
  return;
5364
5351
  }
5365
5352
  if (!result || Array.isArray(result) && result.length === 0) {
5366
- resolve6("");
5353
+ resolve5("");
5367
5354
  return;
5368
5355
  }
5369
- resolve6(result);
5356
+ resolve5(result);
5370
5357
  });
5371
5358
  });
5372
5359
  }
@@ -5604,7 +5591,7 @@ var Sql_default = {
5604
5591
  };
5605
5592
 
5606
5593
  // src/sysserver/db/src/file/Index.ts
5607
- import * as fs11 from "fs";
5594
+ import * as fs10 from "fs";
5608
5595
  import * as path6 from "path";
5609
5596
  function dbDriver(opt = {}) {
5610
5597
  const { Sql, DbCommon } = opt;
@@ -5618,13 +5605,14 @@ function dbDriver(opt = {}) {
5618
5605
  this.fileExt = config.ext === ".*" ? "" : config.ext || "";
5619
5606
  this.fileDel = (config.del || 0) !== 0;
5620
5607
  this.createDir = config.create || false;
5621
- this.baseDirAbs = path6.resolve(process.cwd(), config.dir);
5608
+ const root = config.$asai?.serverRoot || getPrimaryServerRoot();
5609
+ this.baseDirAbs = path6.resolve(root, config.dir);
5622
5610
  }
5623
5611
  dbLog(...args) {
5624
5612
  (this.config?.$asai?.$log || console.log)("FILE", ...args);
5625
5613
  }
5626
5614
  checkFile(file) {
5627
- return fs11.existsSync(this.getAbsPath(file, false));
5615
+ return fs10.existsSync(this.getAbsPath(file, false));
5628
5616
  }
5629
5617
  /** 解析相对路径并限制在数据根目录内,防止路径穿越(跨平台) */
5630
5618
  resolvePath(relPath) {
@@ -5651,9 +5639,9 @@ function dbDriver(opt = {}) {
5651
5639
  const relative4 = this.normalizeRelPath(relPath);
5652
5640
  const dirPath = path6.dirname(relative4);
5653
5641
  const absDir = this.resolvePath(dirPath === "." ? "" : dirPath);
5654
- if (this.createDir && !fs11.existsSync(absDir)) {
5642
+ if (this.createDir && !fs10.existsSync(absDir)) {
5655
5643
  this.dbLog("mkdir", "[MKDIR]", absDir);
5656
- fs11.mkdirSync(absDir, { recursive: true });
5644
+ fs10.mkdirSync(absDir, { recursive: true });
5657
5645
  }
5658
5646
  return absDir;
5659
5647
  }
@@ -5669,21 +5657,21 @@ function dbDriver(opt = {}) {
5669
5657
  }
5670
5658
  deldir(relativePath) {
5671
5659
  const absPath = this.resolvePath(relativePath);
5672
- if (!fs11.existsSync(absPath)) {
5660
+ if (!fs10.existsSync(absPath)) {
5673
5661
  return;
5674
5662
  }
5675
5663
  this.dbLog("delete", "[RMDIR]", absPath);
5676
- const entries = fs11.readdirSync(absPath, { withFileTypes: true });
5664
+ const entries = fs10.readdirSync(absPath, { withFileTypes: true });
5677
5665
  for (const entry of entries) {
5678
5666
  const current = path6.join(absPath, entry.name);
5679
5667
  if (entry.isDirectory()) {
5680
5668
  this.deldir(path6.join(relativePath, entry.name));
5681
5669
  } else {
5682
5670
  this.dbLog("delete", "[UNLINK]", current);
5683
- fs11.unlinkSync(current);
5671
+ fs10.unlinkSync(current);
5684
5672
  }
5685
5673
  }
5686
- fs11.rmdirSync(absPath);
5674
+ fs10.rmdirSync(absPath);
5687
5675
  }
5688
5676
  getReadPath(file, sql) {
5689
5677
  const candidates = [];
@@ -5696,7 +5684,7 @@ function dbDriver(opt = {}) {
5696
5684
  }
5697
5685
  for (const candidate of candidates) {
5698
5686
  const abs = this.getAbsPath(candidate.dir, false);
5699
- if (fs11.existsSync(abs)) {
5687
+ if (fs10.existsSync(abs)) {
5700
5688
  return { path: abs, dir: candidate.dir };
5701
5689
  }
5702
5690
  }
@@ -5722,7 +5710,7 @@ function dbDriver(opt = {}) {
5722
5710
  try {
5723
5711
  const filePath = sql?.type === "insert" ? this.getNewPath(file, sql) : this.getReadPath(file, sql).path || this.getNewPath(file, sql);
5724
5712
  this.dbLog("write", "[WRITE]", filePath);
5725
- fs11.writeFileSync(filePath, data, "utf8");
5713
+ fs10.writeFileSync(filePath, data, "utf8");
5726
5714
  return "ok";
5727
5715
  } catch (e) {
5728
5716
  this.dbLog("write failed", "[WRITE ERROR]", e);
@@ -5736,7 +5724,7 @@ function dbDriver(opt = {}) {
5736
5724
  return { error: "empty" };
5737
5725
  }
5738
5726
  this.dbLog("read", "[READ]", read2.path);
5739
- const data = fs11.readFileSync(read2.path, { encoding }) || "";
5727
+ const data = fs10.readFileSync(read2.path, { encoding }) || "";
5740
5728
  const fileName = this.fileExt && read2.dir.endsWith(this.fileExt) ? read2.dir : read2.dir + this.fileExt;
5741
5729
  return [{ data, file: fileName }];
5742
5730
  } catch (e) {
@@ -5753,12 +5741,12 @@ function dbDriver(opt = {}) {
5753
5741
  if (this.fileDel && sql?.deltrue) {
5754
5742
  const target = del.path + ".delete" + this.fileExt;
5755
5743
  this.dbLog("soft delete", "[SOFT DELETE]", `${del.path} -> ${target}`);
5756
- fs11.renameSync(del.path, target);
5744
+ fs10.renameSync(del.path, target);
5757
5745
  } else if (sql?.filename) {
5758
5746
  this.deldir(del.dir);
5759
5747
  } else {
5760
5748
  this.dbLog("delete", "[DELETE]", del.path);
5761
- fs11.unlinkSync(del.path);
5749
+ fs10.unlinkSync(del.path);
5762
5750
  }
5763
5751
  return "ok";
5764
5752
  } catch (e) {
@@ -5777,11 +5765,11 @@ function dbDriver(opt = {}) {
5777
5765
  const original = del.path.replace(new RegExp(`.delete${extPattern}$`), "");
5778
5766
  if (original !== del.path) {
5779
5767
  this.dbLog("restore", "[RESTORE]", `${del.path} -> ${original}`);
5780
- fs11.renameSync(del.path, original);
5768
+ fs10.renameSync(del.path, original);
5781
5769
  }
5782
5770
  } else {
5783
5771
  this.dbLog("force delete", "[FORCE DELETE]", del.path);
5784
- fs11.unlinkSync(del.path);
5772
+ fs10.unlinkSync(del.path);
5785
5773
  }
5786
5774
  return "ok";
5787
5775
  } catch (e) {
@@ -5795,7 +5783,7 @@ function dbDriver(opt = {}) {
5795
5783
  this.dbLog("list", "[LIST]", absDir);
5796
5784
  let entries;
5797
5785
  try {
5798
- entries = fs11.readdirSync(absDir, { withFileTypes: true });
5786
+ entries = fs10.readdirSync(absDir, { withFileTypes: true });
5799
5787
  } catch {
5800
5788
  return sql?.list ? { open: [], delete: [] } : [];
5801
5789
  }
@@ -5809,7 +5797,7 @@ function dbDriver(opt = {}) {
5809
5797
  if (this.fileExt && !baseName.endsWith(this.fileExt)) continue;
5810
5798
  const fullPath = path6.join(absDir, fileName);
5811
5799
  try {
5812
- const data = fs11.readFileSync(fullPath, "utf8");
5800
+ const data = fs10.readFileSync(fullPath, "utf8");
5813
5801
  const entryData = { data, file: baseName };
5814
5802
  if (isDelete) {
5815
5803
  if (sql?.list) result.delete.push(entryData);
@@ -5836,7 +5824,7 @@ function dbDriver(opt = {}) {
5836
5824
  return String(raw ?? "");
5837
5825
  }
5838
5826
  sqlDb(sql) {
5839
- return new Promise((resolve6, reject) => {
5827
+ return new Promise((resolve5, reject) => {
5840
5828
  try {
5841
5829
  let result;
5842
5830
  const tableDir = this.tableFilePath(sql.table);
@@ -5965,7 +5953,7 @@ function dbDriver(opt = {}) {
5965
5953
  }
5966
5954
  }
5967
5955
  if (result !== void 0) {
5968
- resolve6(result);
5956
+ resolve5(result);
5969
5957
  } else {
5970
5958
  reject("");
5971
5959
  }
@@ -6575,7 +6563,7 @@ var initAsaiHostNodejs2 = {
6575
6563
  createTransportDataHandler,
6576
6564
  wireTransportConnectionLogs
6577
6565
  };
6578
- var PLUGIN_VERSION = true ? "0.0.4" : "0.0.1";
6566
+ var PLUGIN_VERSION = true ? "0.0.6" : "0.0.1";
6579
6567
  var index_default = initAsaiHostNodejs2;
6580
6568
  export {
6581
6569
  Index_default as AsaiCommon,