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.
- package/README.md +518 -0
- package/dist/InterventionLog-25EHE4QR.cjs +30 -0
- package/dist/InterventionLog-25EHE4QR.cjs.map +1 -0
- package/dist/InterventionLog-R6CCPU2B.es.js +30 -0
- package/dist/InterventionLog-R6CCPU2B.es.js.map +1 -0
- package/dist/LogStore-ECXX34WC.es.js +54 -0
- package/dist/LogStore-ECXX34WC.es.js.map +1 -0
- package/dist/LogStore-M2AUBNGO.cjs +54 -0
- package/dist/LogStore-M2AUBNGO.cjs.map +1 -0
- package/dist/asaihost-nodejs.cjs +6761 -0
- package/dist/asaihost-nodejs.cjs.map +1 -0
- package/dist/asaihost-nodejs.d.cts +406 -0
- package/dist/asaihost-nodejs.d.ts +406 -0
- package/dist/asaihost-nodejs.es.js +6761 -0
- package/dist/asaihost-nodejs.es.js.map +1 -0
- package/dist/chunk-4WJDC4M4.es.js +311 -0
- package/dist/chunk-4WJDC4M4.es.js.map +1 -0
- package/dist/chunk-6U2I5EON.es.js +12 -0
- package/dist/chunk-6U2I5EON.es.js.map +1 -0
- package/dist/chunk-DROOHKB3.es.js +87 -0
- package/dist/chunk-DROOHKB3.es.js.map +1 -0
- package/dist/chunk-E7V3EBDB.es.js +435 -0
- package/dist/chunk-E7V3EBDB.es.js.map +1 -0
- package/dist/chunk-EOGZPRML.es.js +740 -0
- package/dist/chunk-EOGZPRML.es.js.map +1 -0
- package/dist/chunk-G4WVDUBH.cjs +463 -0
- package/dist/chunk-G4WVDUBH.cjs.map +1 -0
- package/dist/chunk-HHPGUJ75.cjs +162 -0
- package/dist/chunk-HHPGUJ75.cjs.map +1 -0
- package/dist/chunk-KOFCBB3N.cjs +87 -0
- package/dist/chunk-KOFCBB3N.cjs.map +1 -0
- package/dist/chunk-KUZQ36IJ.es.js +162 -0
- package/dist/chunk-KUZQ36IJ.es.js.map +1 -0
- package/dist/chunk-LOMSUPPU.es.js +1202 -0
- package/dist/chunk-LOMSUPPU.es.js.map +1 -0
- package/dist/chunk-MCMADJQR.es.js +463 -0
- package/dist/chunk-MCMADJQR.es.js.map +1 -0
- package/dist/chunk-NLBFIRDB.cjs +105 -0
- package/dist/chunk-NLBFIRDB.cjs.map +1 -0
- package/dist/chunk-O6LVLSNB.cjs +40 -0
- package/dist/chunk-O6LVLSNB.cjs.map +1 -0
- package/dist/chunk-QWVR2HNT.cjs +435 -0
- package/dist/chunk-QWVR2HNT.cjs.map +1 -0
- package/dist/chunk-SMVZ3ZDJ.cjs +12 -0
- package/dist/chunk-SMVZ3ZDJ.cjs.map +1 -0
- package/dist/chunk-UTKVJE7N.es.js +40 -0
- package/dist/chunk-UTKVJE7N.es.js.map +1 -0
- package/dist/chunk-VLMM735Q.cjs +1202 -0
- package/dist/chunk-VLMM735Q.cjs.map +1 -0
- package/dist/chunk-W7DVKGX5.cjs +311 -0
- package/dist/chunk-W7DVKGX5.cjs.map +1 -0
- package/dist/chunk-X7VHW2TD.cjs +740 -0
- package/dist/chunk-X7VHW2TD.cjs.map +1 -0
- package/dist/chunk-XBIN4C2V.es.js +105 -0
- package/dist/chunk-XBIN4C2V.es.js.map +1 -0
- package/dist/intervention-hooks-FI4EHOL5.es.js +21 -0
- package/dist/intervention-hooks-FI4EHOL5.es.js.map +1 -0
- package/dist/intervention-hooks-LE6X4C6N.cjs +21 -0
- package/dist/intervention-hooks-LE6X4C6N.cjs.map +1 -0
- package/dist/log-alert-GLCULMQP.es.js +51 -0
- package/dist/log-alert-GLCULMQP.es.js.map +1 -0
- package/dist/log-alert-LAJ6VSAG.cjs +51 -0
- package/dist/log-alert-LAJ6VSAG.cjs.map +1 -0
- package/dist/log-formats-FKFMQKNO.cjs +31 -0
- package/dist/log-formats-FKFMQKNO.cjs.map +1 -0
- package/dist/log-formats-I5E32H5F.es.js +31 -0
- package/dist/log-formats-I5E32H5F.es.js.map +1 -0
- package/dist/password-63OY27RX.es.js +20 -0
- package/dist/password-63OY27RX.es.js.map +1 -0
- package/dist/password-NZ5EGDWG.cjs +20 -0
- package/dist/password-NZ5EGDWG.cjs.map +1 -0
- package/dist/user-store-J7LWEXSW.es.js +12 -0
- package/dist/user-store-J7LWEXSW.es.js.map +1 -0
- package/dist/user-store-SX4N6PQ4.cjs +12 -0
- package/dist/user-store-SX4N6PQ4.cjs.map +1 -0
- 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"}
|