asaihost-nodejs 0.0.5 → 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 +469 -483
  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 +130 -144
  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
  }
@@ -5103,7 +5153,19 @@ var reqWork_default = /* @__PURE__ */ __name(($asai) => {
5103
5153
  __name(hostDefault2, "hostDefault");
5104
5154
  function getPathFromOpt(opt) {
5105
5155
  const rawPath = opt.qrdata?.path || opt.data?.path;
5106
- 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);
5107
5169
  }
5108
5170
  __name(getPathFromOpt, "getPathFromOpt");
5109
5171
  function sendSuccess(res, data, opt) {
@@ -5251,83 +5313,6 @@ async function writeJson(filePath, data) {
5251
5313
  }
5252
5314
  __name(writeJson, "writeJson");
5253
5315
 
5254
- // src/sysserver/lib/common/AsPath.ts
5255
- var AsPath_exports = {};
5256
- __export(AsPath_exports, {
5257
- getEntryDir: () => getEntryDir,
5258
- getExecDir: () => getExecDir,
5259
- getPkgSnapshotDir: () => getPkgSnapshotDir,
5260
- getPrimaryServerRoot: () => getPrimaryServerRoot,
5261
- getRuntimeBaseDirs: () => getRuntimeBaseDirs,
5262
- isPkgRuntime: () => isPkgRuntime
5263
- });
5264
- import * as fs10 from "fs";
5265
- import * as nodePath4 from "path";
5266
- function isPkgRuntime() {
5267
- return typeof process.pkg !== "undefined";
5268
- }
5269
- __name(isPkgRuntime, "isPkgRuntime");
5270
- function getPkgSnapshotDir() {
5271
- if (!isPkgRuntime()) return void 0;
5272
- const entry = process.pkg?.entrypoint ?? process.pkg?.defaultEntrypoint;
5273
- if (!entry) return void 0;
5274
- return nodePath4.resolve(nodePath4.dirname(entry));
5275
- }
5276
- __name(getPkgSnapshotDir, "getPkgSnapshotDir");
5277
- function getEntryDir() {
5278
- const snapshot = getPkgSnapshotDir();
5279
- if (snapshot) return snapshot;
5280
- const entry = process.argv[1];
5281
- if (!entry) {
5282
- return nodePath4.dirname(process.execPath);
5283
- }
5284
- return nodePath4.resolve(nodePath4.dirname(entry));
5285
- }
5286
- __name(getEntryDir, "getEntryDir");
5287
- function getExecDir() {
5288
- return nodePath4.dirname(process.execPath);
5289
- }
5290
- __name(getExecDir, "getExecDir");
5291
- function getRuntimeBaseDirs() {
5292
- const bases = [];
5293
- const seen = /* @__PURE__ */ new Set();
5294
- const add = /* @__PURE__ */ __name((p) => {
5295
- if (!p) return;
5296
- const abs = nodePath4.resolve(p);
5297
- if (!seen.has(abs)) {
5298
- seen.add(abs);
5299
- bases.push(abs);
5300
- }
5301
- }, "add");
5302
- add(process.cwd());
5303
- add(getExecDir());
5304
- if (isPkgRuntime()) {
5305
- add(getPkgSnapshotDir());
5306
- } else {
5307
- const entryDir = getEntryDir();
5308
- if (entryDir !== getExecDir()) {
5309
- add(entryDir);
5310
- }
5311
- }
5312
- return bases;
5313
- }
5314
- __name(getRuntimeBaseDirs, "getRuntimeBaseDirs");
5315
- function getPrimaryServerRoot() {
5316
- for (const base of getRuntimeBaseDirs()) {
5317
- try {
5318
- if (fs10.statSync(nodePath4.join(base, "websys")).isDirectory()) {
5319
- return base;
5320
- }
5321
- } catch {
5322
- }
5323
- }
5324
- if (isPkgRuntime()) {
5325
- return getExecDir();
5326
- }
5327
- return getEntryDir();
5328
- }
5329
- __name(getPrimaryServerRoot, "getPrimaryServerRoot");
5330
-
5331
5316
  // src/sysserver/lib/index.ts
5332
5317
  var lib_default = {
5333
5318
  As: As_default,
@@ -5358,17 +5343,17 @@ __export(common_exports, {
5358
5343
  });
5359
5344
  import * as path5 from "path";
5360
5345
  function promisifySqlDb(query, sql) {
5361
- return new Promise((resolve6, reject) => {
5346
+ return new Promise((resolve5, reject) => {
5362
5347
  query(sql, (err, result) => {
5363
5348
  if (err) {
5364
5349
  reject(err);
5365
5350
  return;
5366
5351
  }
5367
5352
  if (!result || Array.isArray(result) && result.length === 0) {
5368
- resolve6("");
5353
+ resolve5("");
5369
5354
  return;
5370
5355
  }
5371
- resolve6(result);
5356
+ resolve5(result);
5372
5357
  });
5373
5358
  });
5374
5359
  }
@@ -5606,7 +5591,7 @@ var Sql_default = {
5606
5591
  };
5607
5592
 
5608
5593
  // src/sysserver/db/src/file/Index.ts
5609
- import * as fs11 from "fs";
5594
+ import * as fs10 from "fs";
5610
5595
  import * as path6 from "path";
5611
5596
  function dbDriver(opt = {}) {
5612
5597
  const { Sql, DbCommon } = opt;
@@ -5620,13 +5605,14 @@ function dbDriver(opt = {}) {
5620
5605
  this.fileExt = config.ext === ".*" ? "" : config.ext || "";
5621
5606
  this.fileDel = (config.del || 0) !== 0;
5622
5607
  this.createDir = config.create || false;
5623
- this.baseDirAbs = path6.resolve(process.cwd(), config.dir);
5608
+ const root = config.$asai?.serverRoot || getPrimaryServerRoot();
5609
+ this.baseDirAbs = path6.resolve(root, config.dir);
5624
5610
  }
5625
5611
  dbLog(...args) {
5626
5612
  (this.config?.$asai?.$log || console.log)("FILE", ...args);
5627
5613
  }
5628
5614
  checkFile(file) {
5629
- return fs11.existsSync(this.getAbsPath(file, false));
5615
+ return fs10.existsSync(this.getAbsPath(file, false));
5630
5616
  }
5631
5617
  /** 解析相对路径并限制在数据根目录内,防止路径穿越(跨平台) */
5632
5618
  resolvePath(relPath) {
@@ -5653,9 +5639,9 @@ function dbDriver(opt = {}) {
5653
5639
  const relative4 = this.normalizeRelPath(relPath);
5654
5640
  const dirPath = path6.dirname(relative4);
5655
5641
  const absDir = this.resolvePath(dirPath === "." ? "" : dirPath);
5656
- if (this.createDir && !fs11.existsSync(absDir)) {
5642
+ if (this.createDir && !fs10.existsSync(absDir)) {
5657
5643
  this.dbLog("mkdir", "[MKDIR]", absDir);
5658
- fs11.mkdirSync(absDir, { recursive: true });
5644
+ fs10.mkdirSync(absDir, { recursive: true });
5659
5645
  }
5660
5646
  return absDir;
5661
5647
  }
@@ -5671,21 +5657,21 @@ function dbDriver(opt = {}) {
5671
5657
  }
5672
5658
  deldir(relativePath) {
5673
5659
  const absPath = this.resolvePath(relativePath);
5674
- if (!fs11.existsSync(absPath)) {
5660
+ if (!fs10.existsSync(absPath)) {
5675
5661
  return;
5676
5662
  }
5677
5663
  this.dbLog("delete", "[RMDIR]", absPath);
5678
- const entries = fs11.readdirSync(absPath, { withFileTypes: true });
5664
+ const entries = fs10.readdirSync(absPath, { withFileTypes: true });
5679
5665
  for (const entry of entries) {
5680
5666
  const current = path6.join(absPath, entry.name);
5681
5667
  if (entry.isDirectory()) {
5682
5668
  this.deldir(path6.join(relativePath, entry.name));
5683
5669
  } else {
5684
5670
  this.dbLog("delete", "[UNLINK]", current);
5685
- fs11.unlinkSync(current);
5671
+ fs10.unlinkSync(current);
5686
5672
  }
5687
5673
  }
5688
- fs11.rmdirSync(absPath);
5674
+ fs10.rmdirSync(absPath);
5689
5675
  }
5690
5676
  getReadPath(file, sql) {
5691
5677
  const candidates = [];
@@ -5698,7 +5684,7 @@ function dbDriver(opt = {}) {
5698
5684
  }
5699
5685
  for (const candidate of candidates) {
5700
5686
  const abs = this.getAbsPath(candidate.dir, false);
5701
- if (fs11.existsSync(abs)) {
5687
+ if (fs10.existsSync(abs)) {
5702
5688
  return { path: abs, dir: candidate.dir };
5703
5689
  }
5704
5690
  }
@@ -5724,7 +5710,7 @@ function dbDriver(opt = {}) {
5724
5710
  try {
5725
5711
  const filePath = sql?.type === "insert" ? this.getNewPath(file, sql) : this.getReadPath(file, sql).path || this.getNewPath(file, sql);
5726
5712
  this.dbLog("write", "[WRITE]", filePath);
5727
- fs11.writeFileSync(filePath, data, "utf8");
5713
+ fs10.writeFileSync(filePath, data, "utf8");
5728
5714
  return "ok";
5729
5715
  } catch (e) {
5730
5716
  this.dbLog("write failed", "[WRITE ERROR]", e);
@@ -5738,7 +5724,7 @@ function dbDriver(opt = {}) {
5738
5724
  return { error: "empty" };
5739
5725
  }
5740
5726
  this.dbLog("read", "[READ]", read2.path);
5741
- const data = fs11.readFileSync(read2.path, { encoding }) || "";
5727
+ const data = fs10.readFileSync(read2.path, { encoding }) || "";
5742
5728
  const fileName = this.fileExt && read2.dir.endsWith(this.fileExt) ? read2.dir : read2.dir + this.fileExt;
5743
5729
  return [{ data, file: fileName }];
5744
5730
  } catch (e) {
@@ -5755,12 +5741,12 @@ function dbDriver(opt = {}) {
5755
5741
  if (this.fileDel && sql?.deltrue) {
5756
5742
  const target = del.path + ".delete" + this.fileExt;
5757
5743
  this.dbLog("soft delete", "[SOFT DELETE]", `${del.path} -> ${target}`);
5758
- fs11.renameSync(del.path, target);
5744
+ fs10.renameSync(del.path, target);
5759
5745
  } else if (sql?.filename) {
5760
5746
  this.deldir(del.dir);
5761
5747
  } else {
5762
5748
  this.dbLog("delete", "[DELETE]", del.path);
5763
- fs11.unlinkSync(del.path);
5749
+ fs10.unlinkSync(del.path);
5764
5750
  }
5765
5751
  return "ok";
5766
5752
  } catch (e) {
@@ -5779,11 +5765,11 @@ function dbDriver(opt = {}) {
5779
5765
  const original = del.path.replace(new RegExp(`.delete${extPattern}$`), "");
5780
5766
  if (original !== del.path) {
5781
5767
  this.dbLog("restore", "[RESTORE]", `${del.path} -> ${original}`);
5782
- fs11.renameSync(del.path, original);
5768
+ fs10.renameSync(del.path, original);
5783
5769
  }
5784
5770
  } else {
5785
5771
  this.dbLog("force delete", "[FORCE DELETE]", del.path);
5786
- fs11.unlinkSync(del.path);
5772
+ fs10.unlinkSync(del.path);
5787
5773
  }
5788
5774
  return "ok";
5789
5775
  } catch (e) {
@@ -5797,7 +5783,7 @@ function dbDriver(opt = {}) {
5797
5783
  this.dbLog("list", "[LIST]", absDir);
5798
5784
  let entries;
5799
5785
  try {
5800
- entries = fs11.readdirSync(absDir, { withFileTypes: true });
5786
+ entries = fs10.readdirSync(absDir, { withFileTypes: true });
5801
5787
  } catch {
5802
5788
  return sql?.list ? { open: [], delete: [] } : [];
5803
5789
  }
@@ -5811,7 +5797,7 @@ function dbDriver(opt = {}) {
5811
5797
  if (this.fileExt && !baseName.endsWith(this.fileExt)) continue;
5812
5798
  const fullPath = path6.join(absDir, fileName);
5813
5799
  try {
5814
- const data = fs11.readFileSync(fullPath, "utf8");
5800
+ const data = fs10.readFileSync(fullPath, "utf8");
5815
5801
  const entryData = { data, file: baseName };
5816
5802
  if (isDelete) {
5817
5803
  if (sql?.list) result.delete.push(entryData);
@@ -5838,7 +5824,7 @@ function dbDriver(opt = {}) {
5838
5824
  return String(raw ?? "");
5839
5825
  }
5840
5826
  sqlDb(sql) {
5841
- return new Promise((resolve6, reject) => {
5827
+ return new Promise((resolve5, reject) => {
5842
5828
  try {
5843
5829
  let result;
5844
5830
  const tableDir = this.tableFilePath(sql.table);
@@ -5967,7 +5953,7 @@ function dbDriver(opt = {}) {
5967
5953
  }
5968
5954
  }
5969
5955
  if (result !== void 0) {
5970
- resolve6(result);
5956
+ resolve5(result);
5971
5957
  } else {
5972
5958
  reject("");
5973
5959
  }
@@ -6577,7 +6563,7 @@ var initAsaiHostNodejs2 = {
6577
6563
  createTransportDataHandler,
6578
6564
  wireTransportConnectionLogs
6579
6565
  };
6580
- var PLUGIN_VERSION = true ? "0.0.5" : "0.0.1";
6566
+ var PLUGIN_VERSION = true ? "0.0.6" : "0.0.1";
6581
6567
  var index_default = initAsaiHostNodejs2;
6582
6568
  export {
6583
6569
  Index_default as AsaiCommon,