asaihost-nodejs 0.0.1

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 (76) hide show
  1. package/README.md +518 -0
  2. package/dist/InterventionLog-25EHE4QR.cjs +30 -0
  3. package/dist/InterventionLog-25EHE4QR.cjs.map +1 -0
  4. package/dist/InterventionLog-R6CCPU2B.es.js +30 -0
  5. package/dist/InterventionLog-R6CCPU2B.es.js.map +1 -0
  6. package/dist/LogStore-ECXX34WC.es.js +54 -0
  7. package/dist/LogStore-ECXX34WC.es.js.map +1 -0
  8. package/dist/LogStore-M2AUBNGO.cjs +54 -0
  9. package/dist/LogStore-M2AUBNGO.cjs.map +1 -0
  10. package/dist/asaihost-nodejs.cjs +6761 -0
  11. package/dist/asaihost-nodejs.cjs.map +1 -0
  12. package/dist/asaihost-nodejs.d.cts +406 -0
  13. package/dist/asaihost-nodejs.d.ts +406 -0
  14. package/dist/asaihost-nodejs.es.js +6761 -0
  15. package/dist/asaihost-nodejs.es.js.map +1 -0
  16. package/dist/chunk-4WJDC4M4.es.js +311 -0
  17. package/dist/chunk-4WJDC4M4.es.js.map +1 -0
  18. package/dist/chunk-6U2I5EON.es.js +12 -0
  19. package/dist/chunk-6U2I5EON.es.js.map +1 -0
  20. package/dist/chunk-DROOHKB3.es.js +87 -0
  21. package/dist/chunk-DROOHKB3.es.js.map +1 -0
  22. package/dist/chunk-E7V3EBDB.es.js +435 -0
  23. package/dist/chunk-E7V3EBDB.es.js.map +1 -0
  24. package/dist/chunk-EOGZPRML.es.js +740 -0
  25. package/dist/chunk-EOGZPRML.es.js.map +1 -0
  26. package/dist/chunk-G4WVDUBH.cjs +463 -0
  27. package/dist/chunk-G4WVDUBH.cjs.map +1 -0
  28. package/dist/chunk-HHPGUJ75.cjs +162 -0
  29. package/dist/chunk-HHPGUJ75.cjs.map +1 -0
  30. package/dist/chunk-KOFCBB3N.cjs +87 -0
  31. package/dist/chunk-KOFCBB3N.cjs.map +1 -0
  32. package/dist/chunk-KUZQ36IJ.es.js +162 -0
  33. package/dist/chunk-KUZQ36IJ.es.js.map +1 -0
  34. package/dist/chunk-LOMSUPPU.es.js +1202 -0
  35. package/dist/chunk-LOMSUPPU.es.js.map +1 -0
  36. package/dist/chunk-MCMADJQR.es.js +463 -0
  37. package/dist/chunk-MCMADJQR.es.js.map +1 -0
  38. package/dist/chunk-NLBFIRDB.cjs +105 -0
  39. package/dist/chunk-NLBFIRDB.cjs.map +1 -0
  40. package/dist/chunk-O6LVLSNB.cjs +40 -0
  41. package/dist/chunk-O6LVLSNB.cjs.map +1 -0
  42. package/dist/chunk-QWVR2HNT.cjs +435 -0
  43. package/dist/chunk-QWVR2HNT.cjs.map +1 -0
  44. package/dist/chunk-SMVZ3ZDJ.cjs +12 -0
  45. package/dist/chunk-SMVZ3ZDJ.cjs.map +1 -0
  46. package/dist/chunk-UTKVJE7N.es.js +40 -0
  47. package/dist/chunk-UTKVJE7N.es.js.map +1 -0
  48. package/dist/chunk-VLMM735Q.cjs +1202 -0
  49. package/dist/chunk-VLMM735Q.cjs.map +1 -0
  50. package/dist/chunk-W7DVKGX5.cjs +311 -0
  51. package/dist/chunk-W7DVKGX5.cjs.map +1 -0
  52. package/dist/chunk-X7VHW2TD.cjs +740 -0
  53. package/dist/chunk-X7VHW2TD.cjs.map +1 -0
  54. package/dist/chunk-XBIN4C2V.es.js +105 -0
  55. package/dist/chunk-XBIN4C2V.es.js.map +1 -0
  56. package/dist/intervention-hooks-FI4EHOL5.es.js +21 -0
  57. package/dist/intervention-hooks-FI4EHOL5.es.js.map +1 -0
  58. package/dist/intervention-hooks-LE6X4C6N.cjs +21 -0
  59. package/dist/intervention-hooks-LE6X4C6N.cjs.map +1 -0
  60. package/dist/log-alert-GLCULMQP.es.js +51 -0
  61. package/dist/log-alert-GLCULMQP.es.js.map +1 -0
  62. package/dist/log-alert-LAJ6VSAG.cjs +51 -0
  63. package/dist/log-alert-LAJ6VSAG.cjs.map +1 -0
  64. package/dist/log-formats-FKFMQKNO.cjs +31 -0
  65. package/dist/log-formats-FKFMQKNO.cjs.map +1 -0
  66. package/dist/log-formats-I5E32H5F.es.js +31 -0
  67. package/dist/log-formats-I5E32H5F.es.js.map +1 -0
  68. package/dist/password-63OY27RX.es.js +20 -0
  69. package/dist/password-63OY27RX.es.js.map +1 -0
  70. package/dist/password-NZ5EGDWG.cjs +20 -0
  71. package/dist/password-NZ5EGDWG.cjs.map +1 -0
  72. package/dist/user-store-J7LWEXSW.es.js +12 -0
  73. package/dist/user-store-J7LWEXSW.es.js.map +1 -0
  74. package/dist/user-store-SX4N6PQ4.cjs +12 -0
  75. package/dist/user-store-SX4N6PQ4.cjs.map +1 -0
  76. package/package.json +79 -0
package/README.md ADDED
@@ -0,0 +1,518 @@
1
+ # asaihost-nodejs
2
+
3
+ Node.js HTTP/WebSocket 服务器宿主:多站点监听、静态资源、反向代理、内置 sysserver 平台 API(登录/RBAC/日志/数据库),以及 IEC 62443 安全内核。
4
+
5
+ | 项 | 值 |
6
+ |----|-----|
7
+ | **npm 包名** | `asaihost-nodejs` |
8
+ | **插件入口** | `index.ts`(monorepo 源码)/ `dist/asaihost-nodejs.es.js`(发布后) |
9
+ | **运行时配置** | `asaihost.json` + 密钥侧车 / 环境变量 |
10
+ | **Node 版本** | `>= 20` |
11
+ | **对等依赖** | `ws ^8.18`(`mysql` / `sqlite3` 按数据存储选配) |
12
+
13
+ ### 目录结构
14
+
15
+ ```
16
+ asaihost-nodejs/
17
+ ├── index.ts # 包入口(默认导出 initAsaiHost + 命名 API)
18
+ ├── package.json
19
+ ├── tsup.config.ts
20
+ ├── README.md
21
+ └── src/
22
+ ├── index.ts # StartAsaiHost 启动链
23
+ ├── host-api.ts # 对外公开 API 聚合
24
+ ├── types.ts # AsaiRuntime / HostConfig 等类型
25
+ ├── core/ # init、host-config、network
26
+ ├── http/ # server、static、security
27
+ ├── ws/ # server、auth、message
28
+ ├── proxy/ # 反向代理
29
+ ├── config/ # validate、secrets
30
+ ├── infra/ # logger、registry、security
31
+ ├── common/server/ # ServerApi / ServerSys / ServerWs / WsClient 基类
32
+ └── sysserver/ # 内置 api/ws/db/lib
33
+ ```
34
+
35
+ ---
36
+
37
+ ## 目录
38
+
39
+ 1. [快速开始](#快速开始)
40
+ 2. [在 AsaiCMS monorepo 内使用](#在-asaicms-monorepo-内使用)
41
+ 3. [独立项目集成](#独立项目集成)
42
+ 4. [启动与校验流程](#启动与校验流程)
43
+ 5. [配置文件总览](#配置文件总览)
44
+ 6. [配置 → 运行时映射](#配置--运行时映射)
45
+ 7. [公开 API 参考](#公开-api-参考)
46
+ 8. [字段速查](#字段速查)
47
+ 9. [开发与发布 npm 包](#开发与发布-npm-包)
48
+ 10. [约束与前端对应](#约束与前端对应)
49
+
50
+ ---
51
+
52
+ ## 快速开始
53
+
54
+ ### 安装
55
+
56
+ ```bash
57
+ npm install asaihost-nodejs ws
58
+ # 若使用 MySQL / SQLite 数据存储
59
+ npm install mysql sqlite3
60
+ ```
61
+
62
+ ### 最小引导(app.ts 模式)
63
+
64
+ ```typescript
65
+ import fs from 'node:fs/promises';
66
+ import path from 'node:path';
67
+ import AsaiHost from 'asaihost-nodejs';
68
+
69
+ const $asai: any = {
70
+ $lib: { /* 业务工具库 */ },
71
+ connectionshttp: {},
72
+ connectionsws: {},
73
+ taskshttp: {},
74
+ tasksws: {},
75
+ servershttp: {},
76
+ serversws: {},
77
+ tm: 0,
78
+ tmpdata: {},
79
+ };
80
+
81
+ // 1. 挂载 sysserver 平台能力(api/ws/db/lib)
82
+ AsaiHost.sysserver($asai);
83
+
84
+ $asai.serverRoot = process.cwd();
85
+ const cfg = JSON.parse(
86
+ await fs.readFile(path.join($asai.serverRoot, 'websys/sys/asaihost.json'), 'utf8'),
87
+ );
88
+
89
+ // 2. 配置校验与密钥注入
90
+ const stripped = AsaiHost.stripForbiddenSecretsFromHostConfig(cfg);
91
+ if (stripped.length) {
92
+ console.warn(`[AsaiHost] 已从 asaihost.json 剥离敏感字段: ${stripped.join(', ')}`);
93
+ }
94
+ $asai.hostconfig = AsaiHost.normalizeHostConfig(cfg);
95
+ AsaiHost.normalizeSecurityConfig($asai.hostconfig);
96
+ const errors = AsaiHost.validateHostConfig($asai.hostconfig);
97
+ if (errors.length) throw new Error(errors.join('; '));
98
+
99
+ const { secrets } = await AsaiHost.loadAsaiSecrets($asai.serverRoot);
100
+ AsaiHost.applySecretsToHostConfig($asai.hostconfig, secrets);
101
+ await AsaiHost.resolveHttpsCertFromPaths($asai.serverRoot, $asai.hostconfig);
102
+
103
+ // 3. 注册业务 work 处理器并启动
104
+ $asai.asaihost = AsaiHost;
105
+ const { sysWork } = sysMod($asai);
106
+ const { apiWork } = apiMod($asai);
107
+ const { wsWork } = wsMod($asai);
108
+ const { jsonpWork } = jsonpMod($asai);
109
+
110
+ const { StartAsaiHost } = AsaiHost.fn($asai, { sysWork, apiWork, wsWork, jsonpWork });
111
+ StartAsaiHost();
112
+ ```
113
+
114
+ > 完整 monorepo 示例见仓库根目录 `webserver/app.ts`。
115
+
116
+ ---
117
+
118
+ ## 在 AsaiCMS monorepo 内使用
119
+
120
+ 本仓库 `webserver` 通过**相对路径**引用插件源码,开发时无需先 `npm pack`:
121
+
122
+ ```typescript
123
+ // webserver/app.ts
124
+ import AsaiHostMod from './src/plugs/asaihost-nodejs/index';
125
+ ```
126
+
127
+ 本地构建 npm 产物:
128
+
129
+ ```bash
130
+ cd webserver/src/plugs/asaihost-nodejs
131
+ npm install
132
+ npm run build
133
+ ```
134
+
135
+ 构建产物位于 `dist/`:`asaihost-nodejs.es.js`(ESM)、`asaihost-nodejs.cjs`(CJS)、`index.d.ts`(类型声明)。
136
+
137
+ ---
138
+
139
+ ## 独立项目集成
140
+
141
+ ### 1. 项目结构建议
142
+
143
+ ```
144
+ your-server/
145
+ ├── app.ts # 引导入口(见上文)
146
+ ├── websys/sys/
147
+ │ ├── asaihost.json # 非敏感配置(可进 Git)
148
+ │ └── asaihost.secrets.local.json # 本地密钥(勿提交)
149
+ ├── .env # 生产推荐:环境变量注入密钥
150
+ ├── webclient/ # 静态前端(hostdirs 指向)
151
+ └── src/work/ # 业务 api/sys/ws 模块
152
+ ```
153
+
154
+ ### 2. TypeScript
155
+
156
+ ```json
157
+ {
158
+ "compilerOptions": {
159
+ "module": "NodeNext",
160
+ "moduleResolution": "NodeNext",
161
+ "esModuleInterop": true
162
+ }
163
+ }
164
+ ```
165
+
166
+ 从 npm 安装后:
167
+
168
+ ```typescript
169
+ import AsaiHost, { PLUGIN_NAME, type AsaiRuntime, type HostConfig } from 'asaihost-nodejs';
170
+ ```
171
+
172
+ ### 3. 运行方式
173
+
174
+ - 开发:`tsx app.ts` 或 `ts-node --esm app.ts`
175
+ - 生产:先 `npm run build`(若打包业务代码),再 `node dist/app.js`
176
+
177
+ ### 4. 与传输层插件协作
178
+
179
+ TCP / gRPC / RS485 等传输插件通过 `$asai.asaihost` 挂载,**禁止**跨包 deep import `src/`。在 `asaihost.json` 中配置 `tcp` / `grpc` / `rs485` 块,由对应 npm 插件读取。
180
+
181
+ ---
182
+
183
+ ## 启动与校验流程
184
+
185
+ ```
186
+ 读取 asaihost.json
187
+ → stripForbiddenSecretsFromHostConfig(敏感字段不得写在 JSON)
188
+ → normalizeHostConfig + normalizeSecurityConfig
189
+ → validateHostConfig(结构 fail-fast)
190
+ → validateProductionSecurity(生产 IEC 62443 检查)
191
+ → loadAsaiSecrets(.env / secrets.local.json / process.env)
192
+ → applySecretsToHostConfig + resolveHttpsCertFromPaths
193
+ → sysserver($asai) 已提前执行
194
+ → fn($asai, { sysWork, apiWork, wsWork, jsonpWork })
195
+ → StartAsaiHost() → 多端口 HTTP/WS + 反向代理
196
+ ```
197
+
198
+ ### 默认导出 API 形状
199
+
200
+ ```typescript
201
+ interface AsaiNodejsHostPlugin {
202
+ readonly name: 'asaihost-nodejs';
203
+ fn(runtime, options): { StartAsaiHost; asaiWs };
204
+ sysserver(runtime): void;
205
+ AsaiCommon: { ServerApi; ServerWs; ServerSys; WsClient };
206
+ AsaiUtils: { deUserInfoWithAsai; wsMock };
207
+ // …配置、路由、安全、传输桥接等(见 host-api.ts)
208
+ }
209
+ ```
210
+
211
+ ---
212
+
213
+ ## 配置文件总览
214
+
215
+ 本插件的配置由 **两份** 组成,启动时合并到 `$asai.hostconfig`:
216
+
217
+ | 文件 | 位置(monorepo 惯例) | 进 Git | 说明 |
218
+ |------|----------------------|--------|------|
219
+ | **asaihost.json** | `webserver/websys/sys/asaihost.json` | ✅ 是 | 结构与非敏感运维项 |
220
+ | **asaihost.secrets.local.json** | `webserver/websys/sys/` | ❌ 否 | 本地开发密钥(复制 example) |
221
+ | **.env** | `webserver/.env` | ❌ 否 | 环境变量注入(生产推荐) |
222
+
223
+ **加载顺序**(后者覆盖前者):`process.env` → `.env` → `asaihost.secrets.local.json` → 注入 `hostconfig`。
224
+
225
+ 敏感字段(`password` / `asaisn` / `aes.keybase64` / PEM 内联 / `sessionSecret` / `wssec[0]`)**禁止**写入 `asaihost.json`,启动时会剥离并报错。
226
+
227
+ ### 完整配置 — asaihost.json(合成示例)
228
+
229
+ ```json
230
+ {
231
+ "website": { "title": "WEB", "ver": "1.0.0.0" },
232
+ "userStore": {
233
+ "type": "file",
234
+ "opt": { "dir": "webdata/webdb/users/", "ext": ".json", "create": 1 }
235
+ },
236
+ "security": {
237
+ "requireAuth": 0,
238
+ "csp": 0,
239
+ "auditLog": 1,
240
+ "authSkipPaths": [
241
+ "/api/asailog/*",
242
+ "/api/sys/errorcodes/*",
243
+ "/api/user/login/auth/*",
244
+ "/api/user/login/register/*",
245
+ "/sys/info/*",
246
+ "/jsonp/*"
247
+ ],
248
+ "minUserLevel": 0,
249
+ "allowRegister": 1,
250
+ "lockoutMaxFails": 5,
251
+ "lockoutMinutes": 15,
252
+ "sessionTtlHours": 24,
253
+ "passwordMinLength": 8,
254
+ "quota": {
255
+ "enabled": 0,
256
+ "maxApiConcurrent": 500,
257
+ "maxApiPerIp": 30,
258
+ "maxApiPerIpPerMin": 120,
259
+ "maxWsPerIp": 5,
260
+ "maxLoginSessions": 100,
261
+ "maxSessionsPerUser": 3,
262
+ "onUserSessionOverflow": "reject"
263
+ }
264
+ },
265
+ "logger": {
266
+ "lv": { "view": 2, "record": 1 },
267
+ "path": {
268
+ "maxsize": 1048576,
269
+ "client": "./webdata/webdb/log/client/",
270
+ "server": "./webdata/webdb/log/server/"
271
+ },
272
+ "intervention": {
273
+ "path": "./webdata/webdb/log/intervention/",
274
+ "retentionYears": 5
275
+ },
276
+ "sample": { "API": 0.15, "WS": 0.08, "REQ_OTHER": 0.2 },
277
+ "skip": ["/sys/info/metrics", "/sys/guard/msg", "/api/asailog/*"]
278
+ },
279
+ "hosts": {
280
+ "default": {
281
+ "port": 9198,
282
+ "httptype": "http://",
283
+ "maxhttp": 2000,
284
+ "maxws": 2000,
285
+ "maxonline": 100,
286
+ "hostdirs": ["webclient", "websys", "webdata/upload"]
287
+ },
288
+ "asai": {
289
+ "ws": 1,
290
+ "port": 9199,
291
+ "hostdirs": ["webclient", "websys", "webdata/upload"]
292
+ }
293
+ },
294
+ "proxyhosts": {
295
+ "default": {
296
+ "proxyport": 9298,
297
+ "port": 9198,
298
+ "httptype": "http://",
299
+ "proxyhttptype": "http://"
300
+ }
301
+ },
302
+ "aes": {
303
+ "lv": 1,
304
+ "aad": "asai aes aad",
305
+ "keylength": 256,
306
+ "ivlength": 12,
307
+ "algorithm": "aes-256-gcm"
308
+ },
309
+ "httpscert": {
310
+ "keyPath": "websys/sys/certs/local.key",
311
+ "certPath": "websys/sys/certs/local.crt"
312
+ },
313
+ "ip": "asai",
314
+ "index": "index.html"
315
+ }
316
+ ```
317
+
318
+ > 完整字段模板见 monorepo `webserver/websys/sys/asaihost.json`;校验规则以 `validateHostConfig` 源码为准。
319
+
320
+ ### 密钥侧车
321
+
322
+ 复制 `websys/sys/asaihost.secrets.example.json` 为 `asaihost.secrets.local.json`:
323
+
324
+ ```json
325
+ {
326
+ "_comment": "禁止提交仓库。生产请改用环境变量。",
327
+ "password": "asai",
328
+ "asaisn": "<随机盐>",
329
+ "aesKeyBase64": "<与前端 VITE_ASAI_AES_KEYBASE64 一致>",
330
+ "sessionSecret": "<随机密钥>",
331
+ "wssecToken": "asai"
332
+ }
333
+ ```
334
+
335
+ ### 环境变量(等价)
336
+
337
+ ```env
338
+ ASAI_HOST_PASSWORD=asai
339
+ ASAI_ASAISN=
340
+ ASAI_AES_KEYBASE64=
341
+ ASAI_SESSION_SECRET=
342
+ ASAI_WSSEC_TOKEN=
343
+ ASAI_HTTPS_KEY_PATH=websys/sys/certs/local.key
344
+ ASAI_HTTPS_CERT_PATH=websys/sys/certs/local.crt
345
+ ```
346
+
347
+ | 环境变量 | 注入到 hostconfig | 说明 |
348
+ |----------|-------------------|------|
349
+ | `ASAI_HOST_PASSWORD` | `password` | 系统 bootstrap 密码 |
350
+ | `ASAI_ASAISN` | `asaisn` | Userinfo 编解码盐 |
351
+ | `ASAI_AES_KEYBASE64` | `aes.keybase64` | AES-256-GCM 密钥 |
352
+ | `ASAI_SESSION_SECRET` | `security.sessionSecret` | 会话 HMAC |
353
+ | `ASAI_WSSEC_TOKEN` | `wssec[0]` | WS 安全令牌 |
354
+
355
+ ---
356
+
357
+ ## 配置 → 运行时映射
358
+
359
+ ```
360
+ asaihost.json + secrets
361
+ ├── website / ip / index / mimetypes / pkg → 全局
362
+ ├── logger.* → infra/logger, http/log
363
+ ├── tm.* → init, ws/auth, process
364
+ ├── security.* → access-control, user-store, quota
365
+ ├── userStore.* → sysserver/api/login/store
366
+ ├── aes.* (+ secrets.keybase64) → API/WS 加解密
367
+ ├── httpscert.* → https.createServer
368
+ ├── hosts.default + hosts.<site> → http/*, ws/*
369
+ │ ├── weburls.* → SPA fallback
370
+ │ └── ckhttp / ckws / max* → 连接监控与限流
371
+ ├── proxyhosts.* → proxy/server
372
+ └── tcp|grpc|rs485 → 传输插件(可选)
373
+ ```
374
+
375
+ ### 站点合并规则
376
+
377
+ - 实际站点 = `hosts.default` 浅合并 `hosts.<name>`
378
+ - `default` 仅作模板,**不单独监听**
379
+ - `asai` 为内置守护站点;9199 端口冲突时 `process.exit(1)`
380
+
381
+ ### 请求路由
382
+
383
+ | URL | 处理器 |
384
+ |-----|--------|
385
+ | `/sys/*` | sysWork |
386
+ | `/api/*` | apiWork(前缀匹配 `hostserverapis`) |
387
+ | `/jsonp/*` | jsonpWork |
388
+ | 其它 | 静态(`hostdirs` 顺序查找) |
389
+ | WebSocket | wsWork(`msg.ty` 最长前缀) |
390
+
391
+ ---
392
+
393
+ ## 公开 API 参考
394
+
395
+ **npm 消费者仅使用包入口导出,禁止 deep import `src/`。**
396
+
397
+ ### 配置与密钥
398
+
399
+ | 导出 | 说明 |
400
+ |------|------|
401
+ | `normalizeHostConfig` | 填充默认值、规范化结构 |
402
+ | `validateHostConfig` | 结构校验,返回错误字符串数组 |
403
+ | `validateProductionSecurity` | 生产环境 IEC 62443 检查 |
404
+ | `normalizeSecurityConfig` | 安全策略默认值 |
405
+ | `stripForbiddenSecretsFromHostConfig` | 剥离 JSON 中的敏感字段 |
406
+ | `loadAsaiSecrets` / `loadDotEnvFile` | 加载密钥 |
407
+ | `applySecretsToHostConfig` | 合并密钥到 hostconfig |
408
+ | `resolveHttpsCertFromPaths` | 从路径读取 PEM |
409
+ | `validateAsaiSecrets` / `isDevDefaultPassword` | 密钥校验 |
410
+
411
+ ### 路由注册
412
+
413
+ | 导出 | 说明 |
414
+ |------|------|
415
+ | `registerApi` / `registerWs` | 注册业务路由工厂 |
416
+ | `initHostserverApi` / `initHostserverWs` | 初始化平台路由表 |
417
+ | `syncApiRouteKeys` / `syncWsRouteKeys` | 同步路由键列表 |
418
+
419
+ ### 安全与基础设施
420
+
421
+ | 导出 | 说明 |
422
+ |------|------|
423
+ | `secureCompare` | 恒定时间字符串比较 |
424
+ | `resolvePathUnderRoots` / `getHostAllowedRoots` | 防目录穿越 |
425
+ | `validateHttpAuth` | HTTP Userinfo 鉴权 |
426
+ | `logSecurityEvent` / `getClientIp` | 安全审计 |
427
+ | `sanitizeString` 等 | 输入净化 |
428
+
429
+ ### 传输桥接(供 TCP/gRPC/RS485 插件)
430
+
431
+ | 导出 | 说明 |
432
+ |------|------|
433
+ | `getTransportBlock` / `getTransportDefault` | 读取 hostconfig 传输配置 |
434
+ | `initTransportBridge` | 初始化 `$asai` 传输桥 |
435
+ | `ensureDefaultConnection` / `createTransportDataHandler` | 连接与数据回调 |
436
+
437
+ ### 类型导出
438
+
439
+ `AsaiRuntime`、`HostConfig`、`AsaiHostOptions`、`HostBootResult`、`AsaiSecrets`、`SecurityConfig` 等见 `import type { … } from 'asaihost-nodejs'`。
440
+
441
+ ---
442
+
443
+ ## 字段速查
444
+
445
+ ### security
446
+
447
+ | 字段 | 默认 | 说明 |
448
+ |------|------|------|
449
+ | `requireAuth` | 0 | 1=API 需登录(authSkipPaths 除外) |
450
+ | `csp` | 0 | 1=启用 Content-Security-Policy |
451
+ | `auditLog` | 1 | 安全审计日志 |
452
+ | `quota.enabled` | 0 | 连接/频率配额 |
453
+
454
+ ### hosts.default 常用
455
+
456
+ | 字段 | 默认 | 说明 |
457
+ |------|------|------|
458
+ | `port` | 9198 | 监听端口 |
459
+ | `httptype` | `http://` | 或 `https://` |
460
+ | `ws` | — | 1=同端口挂载 WebSocket |
461
+ | `maxhttp` / `maxws` / `maxonline` | 2000/2000/100 | 限流 |
462
+ | `hostdirs` | — | 静态目录(按序查找) |
463
+ | `close` | 0 | 1=跳过启动 |
464
+
465
+ ### aes
466
+
467
+ | 字段 | 说明 |
468
+ |------|------|
469
+ | `lv` | 1=可选 AES;>1=全量 AES(须 secrets 注入 keybase64) |
470
+ | `aad` / `algorithm` / `keylength` / `ivlength` | GCM 参数 |
471
+
472
+ ---
473
+
474
+ ## 开发与发布 npm 包
475
+
476
+ ```bash
477
+ cd webserver/src/plugs/asaihost-nodejs
478
+ npm install
479
+ npm run typecheck # 仅类型检查
480
+ npm run build # tsup 打包 + tsc 声明
481
+ npm pack # 本地验证 .tgz 内容
482
+ npm publish --access public
483
+ ```
484
+
485
+ ### package.json exports 约定
486
+
487
+ | 条件 | 解析到 |
488
+ |------|--------|
489
+ | `development` | `./index.ts`(monorepo + tsx 开发) |
490
+ | `import` | `./dist/asaihost-nodejs.es.js` |
491
+ | `require` | `./dist/asaihost-nodejs.cjs` |
492
+ | `types` | `./dist/asaihost-nodejs.d.ts` |
493
+
494
+ ### 注意事项
495
+
496
+ 1. 修改 `asaihost.json` 后需**重启** Node 进程。
497
+ 2. 端口被占用 → `EADDRINUSE` → 静默退出;排查 9198/9199。
498
+ 3. `CONFIG_WARN` 表示使用 dev 默认密码,生产请设 `ASAI_HOST_PASSWORD`。
499
+ 4. 业务处理器经模块级 `workHandlers` Map 注册,不污染 `global`。
500
+ 5. 静态路径经 `resolvePathUnderRoots` 防目录穿越。
501
+
502
+ ---
503
+
504
+ ## 约束与前端对应
505
+
506
+ - 与 `asaihost-vue`(前端)配对使用时,保持 `asaihost.json` / `aes` 密钥 / `VITE_ASAI_AES_KEYBASE64` 一致。
507
+ - 插件间禁止跨包 `plugs/*/src/` 引用;消费方只走 `import from 'asaihost-nodejs'`。
508
+ - 传输层插件仅通过 `$asai.asaihost.*` 与宿主协作。
509
+
510
+ | 前端 | 后端 |
511
+ |------|------|
512
+ | `asaihost-vue` | `asaihost-nodejs` |
513
+ | `public/webmodel/cfg.js` | `websys/sys/asaihost.json` |
514
+ | `VITE_ASAI_AES_KEYBASE64` | `ASAI_AES_KEYBASE64` |
515
+
516
+ ---
517
+
518
+ *配置以本 README 与 `validateHostConfig` 源码为准;monorepo 实参见 `webserver/websys/sys/asaihost.json` 与 `webserver/app.ts`。*
@@ -0,0 +1,30 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true});
2
+
3
+
4
+
5
+
6
+
7
+
8
+
9
+
10
+
11
+
12
+ var _chunkG4WVDUBHcjs = require('./chunk-G4WVDUBH.cjs');
13
+ require('./chunk-VLMM735Q.cjs');
14
+ require('./chunk-W7DVKGX5.cjs');
15
+ require('./chunk-O6LVLSNB.cjs');
16
+ require('./chunk-HHPGUJ75.cjs');
17
+ require('./chunk-SMVZ3ZDJ.cjs');
18
+
19
+
20
+
21
+
22
+
23
+
24
+
25
+
26
+
27
+
28
+
29
+ exports.crc32 = _chunkG4WVDUBHcjs.crc32; exports.deleteInterventionFile = _chunkG4WVDUBHcjs.deleteInterventionFile; exports.getInterventionTaxonomy = _chunkG4WVDUBHcjs.getInterventionTaxonomy; exports.getRetentionMeta = _chunkG4WVDUBHcjs.getRetentionMeta; exports.listInterventionFiles = _chunkG4WVDUBHcjs.listInterventionFiles; exports.logIntervention = _chunkG4WVDUBHcjs.logIntervention; exports.parseCefLine = _chunkG4WVDUBHcjs.parseCefLine; exports.readInterventionFile = _chunkG4WVDUBHcjs.readInterventionFile; exports.sha256Hex = _chunkG4WVDUBHcjs.sha256Hex; exports.verifyChainForFile = _chunkG4WVDUBHcjs.verifyChainForFile;
30
+ //# sourceMappingURL=InterventionLog-25EHE4QR.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["d:\\Web\\Git\\asaicms-v1\\webserver\\src\\plugs\\asaihost-nodejs\\dist\\InterventionLog-25EHE4QR.cjs"],"names":[],"mappings":"AAAA;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF,wDAA6B;AAC7B,gCAA6B;AAC7B,gCAA6B;AAC7B,gCAA6B;AAC7B,gCAA6B;AAC7B,gCAA6B;AAC7B;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF,unBAAC","file":"D:\\Web\\Git\\asaicms-v1\\webserver\\src\\plugs\\asaihost-nodejs\\dist\\InterventionLog-25EHE4QR.cjs"}
@@ -0,0 +1,30 @@
1
+ import {
2
+ crc32,
3
+ deleteInterventionFile,
4
+ getInterventionTaxonomy,
5
+ getRetentionMeta,
6
+ listInterventionFiles,
7
+ logIntervention,
8
+ parseCefLine,
9
+ readInterventionFile,
10
+ sha256Hex,
11
+ verifyChainForFile
12
+ } from "./chunk-MCMADJQR.es.js";
13
+ import "./chunk-LOMSUPPU.es.js";
14
+ import "./chunk-4WJDC4M4.es.js";
15
+ import "./chunk-UTKVJE7N.es.js";
16
+ import "./chunk-KUZQ36IJ.es.js";
17
+ import "./chunk-6U2I5EON.es.js";
18
+ export {
19
+ crc32,
20
+ deleteInterventionFile,
21
+ getInterventionTaxonomy,
22
+ getRetentionMeta,
23
+ listInterventionFiles,
24
+ logIntervention,
25
+ parseCefLine,
26
+ readInterventionFile,
27
+ sha256Hex,
28
+ verifyChainForFile
29
+ };
30
+ //# sourceMappingURL=InterventionLog-R6CCPU2B.es.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,54 @@
1
+ import {
2
+ archiveInterventionYear,
3
+ exportLogContent,
4
+ getComplianceReport,
5
+ getEffectiveStoreType,
6
+ getLogStoreConfig,
7
+ getLogStoreMeta,
8
+ getUnifiedEntry,
9
+ getUnifiedStats,
10
+ groupsToInterventionFiles,
11
+ groupsToManageChildren,
12
+ isLogStoreEnabled,
13
+ isLogStoreFileBackend,
14
+ isLogStoreSqlite,
15
+ listUnifiedGroups,
16
+ mirrorAccessLog,
17
+ mirrorInterventionLog,
18
+ mirrorWebLog,
19
+ prefersDiskLogAccess,
20
+ purgeSqliteEntriesForFile,
21
+ purgeStoreEntriesForFile,
22
+ queryUnifiedLogs,
23
+ readWebLogFromStore,
24
+ searchUnifiedLogs
25
+ } from "./chunk-LOMSUPPU.es.js";
26
+ import "./chunk-UTKVJE7N.es.js";
27
+ import "./chunk-KUZQ36IJ.es.js";
28
+ import "./chunk-6U2I5EON.es.js";
29
+ export {
30
+ archiveInterventionYear,
31
+ exportLogContent,
32
+ getComplianceReport,
33
+ getEffectiveStoreType,
34
+ getLogStoreConfig,
35
+ getLogStoreMeta,
36
+ getUnifiedEntry,
37
+ getUnifiedStats,
38
+ groupsToInterventionFiles,
39
+ groupsToManageChildren,
40
+ isLogStoreEnabled,
41
+ isLogStoreFileBackend,
42
+ isLogStoreSqlite,
43
+ listUnifiedGroups,
44
+ mirrorAccessLog,
45
+ mirrorInterventionLog,
46
+ mirrorWebLog,
47
+ prefersDiskLogAccess,
48
+ purgeSqliteEntriesForFile,
49
+ purgeStoreEntriesForFile,
50
+ queryUnifiedLogs,
51
+ readWebLogFromStore,
52
+ searchUnifiedLogs
53
+ };
54
+ //# sourceMappingURL=LogStore-ECXX34WC.es.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,54 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true});
2
+
3
+
4
+
5
+
6
+
7
+
8
+
9
+
10
+
11
+
12
+
13
+
14
+
15
+
16
+
17
+
18
+
19
+
20
+
21
+
22
+
23
+
24
+
25
+ var _chunkVLMM735Qcjs = require('./chunk-VLMM735Q.cjs');
26
+ require('./chunk-O6LVLSNB.cjs');
27
+ require('./chunk-HHPGUJ75.cjs');
28
+ require('./chunk-SMVZ3ZDJ.cjs');
29
+
30
+
31
+
32
+
33
+
34
+
35
+
36
+
37
+
38
+
39
+
40
+
41
+
42
+
43
+
44
+
45
+
46
+
47
+
48
+
49
+
50
+
51
+
52
+
53
+ exports.archiveInterventionYear = _chunkVLMM735Qcjs.archiveInterventionYear; exports.exportLogContent = _chunkVLMM735Qcjs.exportLogContent; exports.getComplianceReport = _chunkVLMM735Qcjs.getComplianceReport; exports.getEffectiveStoreType = _chunkVLMM735Qcjs.getEffectiveStoreType; exports.getLogStoreConfig = _chunkVLMM735Qcjs.getLogStoreConfig; exports.getLogStoreMeta = _chunkVLMM735Qcjs.getLogStoreMeta; exports.getUnifiedEntry = _chunkVLMM735Qcjs.getUnifiedEntry; exports.getUnifiedStats = _chunkVLMM735Qcjs.getUnifiedStats; exports.groupsToInterventionFiles = _chunkVLMM735Qcjs.groupsToInterventionFiles; exports.groupsToManageChildren = _chunkVLMM735Qcjs.groupsToManageChildren; exports.isLogStoreEnabled = _chunkVLMM735Qcjs.isLogStoreEnabled; exports.isLogStoreFileBackend = _chunkVLMM735Qcjs.isLogStoreFileBackend; exports.isLogStoreSqlite = _chunkVLMM735Qcjs.isLogStoreSqlite; exports.listUnifiedGroups = _chunkVLMM735Qcjs.listUnifiedGroups; exports.mirrorAccessLog = _chunkVLMM735Qcjs.mirrorAccessLog; exports.mirrorInterventionLog = _chunkVLMM735Qcjs.mirrorInterventionLog; exports.mirrorWebLog = _chunkVLMM735Qcjs.mirrorWebLog; exports.prefersDiskLogAccess = _chunkVLMM735Qcjs.prefersDiskLogAccess; exports.purgeSqliteEntriesForFile = _chunkVLMM735Qcjs.purgeSqliteEntriesForFile; exports.purgeStoreEntriesForFile = _chunkVLMM735Qcjs.purgeStoreEntriesForFile; exports.queryUnifiedLogs = _chunkVLMM735Qcjs.queryUnifiedLogs; exports.readWebLogFromStore = _chunkVLMM735Qcjs.readWebLogFromStore; exports.searchUnifiedLogs = _chunkVLMM735Qcjs.searchUnifiedLogs;
54
+ //# sourceMappingURL=LogStore-M2AUBNGO.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["d:\\Web\\Git\\asaicms-v1\\webserver\\src\\plugs\\asaihost-nodejs\\dist\\LogStore-M2AUBNGO.cjs"],"names":[],"mappings":"AAAA;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF,wDAA6B;AAC7B,gCAA6B;AAC7B,gCAA6B;AAC7B,gCAA6B;AAC7B;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF,giDAAC","file":"D:\\Web\\Git\\asaicms-v1\\webserver\\src\\plugs\\asaihost-nodejs\\dist\\LogStore-M2AUBNGO.cjs"}