npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

asaihost-nodejs

v0.0.11

Published

AsaiWeb CMS Node.js host plugin — HTTP/WebSocket server, sysserver platform API, IEC 62443 security kernel

Readme

asaihost-nodejs

Node.js HTTP/WebSocket 服务器宿主:多站点监听、静态资源、反向代理、内置 sysserver 平台 API(登录/RBAC/日志/数据库),以及 IEC 62443 安全内核。

| 项 | 值 | |----|-----| | npm 包名 | asaihost-nodejs | | 插件入口 | index.ts(monorepo 源码)/ dist/asaihost-nodejs.es.js(发布后) | | 运行时配置 | asaihost.json + 密钥侧车 / 环境变量 | | Node 版本 | >= 20 | | 对等依赖 | ws ^8.18mysql / sqlite3 按数据存储选配) |

目录结构

asaihost-nodejs/
├── index.ts              # 包入口(默认导出 initAsaiHostNodejs + 命名 API)
├── package.json
├── tsup.config.ts
├── README.md
└── src/
    ├── index.ts          # StartAsaiHostNodejs 启动链
    ├── host-api.ts       # 对外公开 API 聚合
    ├── types.ts          # AsaiRuntime / HostConfig 等类型
    ├── core/             # init、host-config、network
    ├── http/             # server、static、security
    ├── ws/               # server、auth、message
    ├── proxy/            # 反向代理
    ├── config/           # validate、secrets
    ├── infra/            # logger、registry、security
    ├── common/server/    # ServerApi / ServerSys / ServerWs / WsClient 基类
    └── sysserver/        # 内置 api/ws/db/lib

目录

  1. 快速开始
  2. 在 AsaiCMS monorepo 内使用
  3. 独立项目集成
  4. 启动与校验流程
  5. 配置文件总览
  6. 配置 → 运行时映射
  7. 公开 API 参考
  8. 字段速查
  9. 开发与发布 npm 包
  10. 约束与前端对应

快速开始

安装

npm install asaihost-nodejs ws
# 若使用 MySQL / SQLite 数据存储
npm install mysql sqlite3

最小引导(app.ts 模式)

import fs from 'node:fs/promises';
import path from 'node:path';
import AsaiHostNodejs from 'asaihost-nodejs';

const $asai: any = {
  $lib: { /* 业务工具库 */ },
  connectionshttp: {},
  connectionsws: {},
  taskshttp: {},
  tasksws: {},
  servershttp: {},
  serversws: {},
  tm: 0,
  tmpdata: {},
};

// 1. 挂载 sysserver 平台能力(api/ws/db/lib);sqlite/mysql 驱动由独立插件注入
import AsaiHostNodejsDbsqlite from './src/plugs/asaihost-nodejs-dbsqlite/index';
import AsaiHostNodejsDbmysql from './src/plugs/asaihost-nodejs-dbmysql/index';
AsaiHostNodejs.sysserver($asai, {
  db: { sqlite: AsaiHostNodejsDbsqlite, mysql: AsaiHostNodejsDbmysql },
});

$asai.serverRoot = process.cwd();
const cfg = JSON.parse(
  await fs.readFile(path.join($asai.serverRoot, 'websys/sys/asaihost.json'), 'utf8'),
);

// 2. 配置校验与密钥注入
const stripped = AsaiHostNodejs.stripForbiddenSecretsFromHostConfig(cfg);
if (stripped.length) {
  console.warn(`[AsaiHostNodejs] 已从 asaihost.json 剥离敏感字段: ${stripped.join(', ')}`);
}
$asai.hostconfig = AsaiHostNodejs.normalizeHostConfig(cfg);
AsaiHostNodejs.normalizeSecurityConfig($asai.hostconfig);
const errors = AsaiHostNodejs.validateHostConfig($asai.hostconfig);
if (errors.length) throw new Error(errors.join('; '));

const { secrets } = await AsaiHostNodejs.loadAsaiSecrets($asai.serverRoot);
AsaiHostNodejs.applySecretsToHostConfig($asai.hostconfig, secrets);
await AsaiHostNodejs.resolveHttpsCertFromPaths($asai.serverRoot, $asai.hostconfig);

// 3. 注册业务 work 处理器并启动
$asai.asaihost = AsaiHostNodejs;
const { sysWork } = sysMod($asai);
const { apiWork } = apiMod($asai);
const { wsWork } = wsMod($asai);
const { jsonpWork } = jsonpMod($asai);

const { StartAsaiHostNodejs } = AsaiHostNodejs.fn($asai, { sysWork, apiWork, wsWork, jsonpWork });
StartAsaiHostNodejs();

完整 monorepo 示例见仓库根目录 webserver/app.ts


在 AsaiCMS monorepo 内使用

本仓库 webserver 通过相对路径引用插件源码,开发时无需先 npm pack

// webserver/app.ts
import AsaiHostNodejsMod from './src/plugs/asaihost-nodejs/index';

本地构建 npm 产物:

cd webserver/src/plugs/asaihost-nodejs
npm install
npm run build

构建产物位于 dist/asaihost-nodejs.es.js(ESM)、asaihost-nodejs.cjs(CJS)、index.d.ts(类型声明)。


独立项目集成

1. 项目结构建议

your-server/
├── app.ts                 # 引导入口(见上文)
├── websys/sys/
│   ├── asaihost.json      # 非敏感配置(可进 Git)
│   └── asaihost.secrets.local.json   # 本地密钥(勿提交)
├── .env                   # 生产推荐:环境变量注入密钥
├── webclient/             # 静态前端(hostdirs 指向)
└── src/work/              # 业务 api/sys/ws 模块

2. TypeScript

{
  "compilerOptions": {
    "module": "NodeNext",
    "moduleResolution": "NodeNext",
    "esModuleInterop": true
  }
}

从 npm 安装后:

import AsaiHostNodejs, { PLUGIN_NAME, type AsaiRuntime, type HostConfig } from 'asaihost-nodejs';

3. 运行方式

  • 开发:tsx app.tsts-node --esm app.ts
  • 生产:先 npm run build(若打包业务代码),再 node dist/app.js

4. 与传输层插件协作

TCP / gRPC / RS485 等传输插件通过 $asai.asaihost 挂载,禁止跨包 deep import src/。在 asaihost.json 中配置 tcp / grpc / rs485 块,由对应 npm 插件读取。


启动与校验流程

读取 asaihost.json
  → stripForbiddenSecretsFromHostConfig(敏感字段不得写在 JSON)
  → normalizeHostConfig + normalizeSecurityConfig
  → validateHostConfig(结构 fail-fast)
  → validateProductionSecurity(生产 IEC 62443 检查)
  → loadAsaiSecrets(.env / secrets.local.json / process.env)
  → applySecretsToHostConfig + resolveHttpsCertFromPaths
  → sysserver($asai) 已提前执行
  → fn($asai, { sysWork, apiWork, wsWork, jsonpWork })
  → StartAsaiHostNodejs()  → 多端口 HTTP/WS + 反向代理

默认导出 API 形状

interface AsaiNodejsHostPlugin {
  readonly name: 'asaihost-nodejs';
  fn(runtime, options): { StartAsaiHostNodejs; asaiWs };
  sysserver(runtime, opt?: SysserverBootOptions): void;
  AsaiCommon: { ServerApi; ServerWs; ServerSys; WsClient };
  AsaiUtils: { deUserInfoWithAsai; wsMock };
  // …配置、路由、安全、传输桥接等(见 host-api.ts)
}

配置文件总览

本插件的配置由 两份 组成,启动时合并到 $asai.hostconfig

| 文件 | 位置(monorepo 惯例) | 进 Git | 说明 | |------|----------------------|--------|------| | asaihost.json | webserver/websys/sys/asaihost.json | ✅ 是 | 结构与非敏感运维项 | | asaihost.secrets.local.json | webserver/websys/sys/ | ❌ 否 | 本地开发密钥(复制 example) | | .env | webserver/.env | ❌ 否 | 环境变量注入(生产推荐) |

加载顺序(后者覆盖前者):process.env.envasaihost.secrets.local.json → 注入 hostconfig

敏感字段(password / asaisn / aes.keybase64 / PEM 内联 / sessionSecret / wssec[0]禁止写入 asaihost.json,启动时会剥离并报错。

用户数据存储(dataStores.user

默认 filewebdata/webdb/users/users.json + sessions.json)。在 websys/sys/asaihost.json 中修改 dataStores.user 即可切换,重启 webserver 后生效app.ts 须已注入 sqlite/mysql 驱动)。

| type | 说明 | opt 主要字段 | |------|------|----------------| | file | 默认,JSON 文件 | dir, ext, create | | sqlite | 单文件库,表 auth_users / auth_sessions | database, create | | mysql | 远程 MySQL | host, user, password, database, create |

"dataStores": {
  "user": {
    "type": "file",
    "opt": { "dir": "webdata/webdb/users/", "ext": ".json", "create": 1 }
  }
}

切换 SQLite:

"user": {
  "type": "sqlite",
  "opt": { "database": "./webdata/webdb/users/users.db", "create": 1 }
}

切换 MySQL:

"user": {
  "type": "mysql",
  "opt": {
    "host": "127.0.0.1",
    "user": "root",
    "password": "",
    "database": "asai",
    "create": 1
  }
}

运行时可通过 GET /api/user/login/config/ 查看 userStore.type(file / sqlite / mysql)。兼容旧字段 userStore,但推荐只维护 dataStores.user

完整配置 — asaihost.json(合成示例)

{
  "website": { "title": "WEB", "ver": "1.0.0.0" },
  "dataStores": {
    "user": {
      "type": "file",
      "opt": { "dir": "webdata/webdb/users/", "ext": ".json", "create": 1 }
    }
  },
  "security": {
    "requireAuth": 0,
    "csp": 0,
    "auditLog": 1,
    "authSkipPaths": [
      "/api/asailog/*",
      "/api/sys/errorcodes/*",
      "/api/user/login/auth/*",
      "/api/user/login/register/*",
      "/sys/info/*",
      "/jsonp/*"
    ],
    "minUserLevel": 0,
    "allowRegister": 1,
    "lockoutMaxFails": 5,
    "lockoutMinutes": 15,
    "sessionTtlHours": 24,
    "passwordMinLength": 8,
    "quota": {
      "enabled": 0,
      "maxApiConcurrent": 500,
      "maxApiPerIp": 30,
      "maxApiPerIpPerMin": 120,
      "maxWsPerIp": 5,
      "maxLoginSessions": 100,
      "maxSessionsPerUser": 3,
      "onUserSessionOverflow": "reject"
    }
  },
  "logger": {
    "lv": { "view": 2, "record": 1 },
    "path": {
      "maxsize": 1048576,
      "client": "./webdata/webdb/log/client/",
      "server": "./webdata/webdb/log/server/"
    },
    "intervention": {
      "path": "./webdata/webdb/log/intervention/",
      "retentionYears": 5
    },
    "sample": { "API": 0.15, "WS": 0.08, "REQ_OTHER": 0.2 },
    "skip": ["/sys/info/metrics", "/sys/guard/msg", "/api/asailog/*"]
  },
  "hosts": {
    "default": {
      "port": 9198,
      "httptype": "http://",
      "maxhttp": 2000,
      "maxws": 2000,
      "maxonline": 100,
      "hostdirs": ["webclient", "websys", "webdata/upload"]
    },
    "asai": {
      "ws": 1,
      "port": 9199,
      "hostdirs": ["webclient", "websys", "webdata/upload"]
    }
  },
  "proxyhosts": {
    "default": {
      "proxyport": 9298,
      "port": 9198,
      "httptype": "http://",
      "proxyhttptype": "http://"
    }
  },
  "aes": {
    "lv": 1,
    "aad": "asai aes aad",
    "keylength": 256,
    "ivlength": 12,
    "algorithm": "aes-256-gcm"
  },
  "httpscert": {
    "keyPath": "websys/sys/certs/local.key",
    "certPath": "websys/sys/certs/local.crt"
  },
  "ip": "asai",
  "index": "index.html"
}

完整字段模板见 monorepo webserver/websys/sys/asaihost.json;校验规则以 validateHostConfig 源码为准。

密钥侧车

复制 websys/sys/asaihost.secrets.example.jsonasaihost.secrets.local.json

{
  "_comment": "禁止提交仓库。生产请改用环境变量。",
  "password": "asai",
  "asaisn": "<随机盐>",
  "aesKeyBase64": "<与前端 VITE_ASAI_AES_KEYBASE64 一致>",
  "sessionSecret": "<随机密钥>",
  "wssecToken": "asai"
}

环境变量(等价)

ASAI_HOST_PASSWORD=asai
ASAI_ASAISN=
ASAI_AES_KEYBASE64=
ASAI_SESSION_SECRET=
ASAI_WSSEC_TOKEN=
ASAI_HTTPS_KEY_PATH=websys/sys/certs/local.key
ASAI_HTTPS_CERT_PATH=websys/sys/certs/local.crt

| 环境变量 | 注入到 hostconfig | 说明 | |----------|-------------------|------| | ASAI_HOST_PASSWORD | password | 系统 bootstrap 密码 | | ASAI_ASAISN | asaisn | Userinfo 编解码盐 | | ASAI_AES_KEYBASE64 | aes.keybase64 | AES-256-GCM 密钥 | | ASAI_SESSION_SECRET | security.sessionSecret | 会话 HMAC | | ASAI_WSSEC_TOKEN | wssec[0] | WS 安全令牌 |


配置 → 运行时映射

asaihost.json + secrets
├── website / ip / index / mimetypes / pkg     → 全局
├── logger.*                                   → infra/logger, http/log
├── tm.*                                       → init, ws/auth, process
├── security.*                                 → access-control, user-store, quota
├── userStore.*                                → sysserver/api/login/store
├── aes.* (+ secrets.keybase64)                → API/WS 加解密
├── httpscert.*                                → https.createServer
├── hosts.default + hosts.<site>               → http/*, ws/*
│   ├── weburls.*                              → SPA fallback
│   └── ckhttp / ckws / max*                   → 连接监控与限流
├── proxyhosts.*                               → proxy/server
└── tcp|grpc|rs485                             → 传输插件(可选)

站点合并规则

  • 实际站点 = hosts.default 浅合并 hosts.<name>
  • default 仅作模板,不单独监听
  • asai 为内置守护站点;9199 端口冲突时 process.exit(1)

请求路由

| URL | 处理器 | |-----|--------| | /sys/* | sysWork | | /api/* | apiWork(前缀匹配 hostserverapis) | | /jsonp/* | jsonpWork | | 其它 | 静态(hostdirs 顺序查找) | | WebSocket | wsWork(msg.ty 最长前缀) |


公开 API 参考

npm 消费者仅使用包入口导出,禁止 deep import src/

配置与密钥

| 导出 | 说明 | |------|------| | normalizeHostConfig | 填充默认值、规范化结构 | | validateHostConfig | 结构校验,返回错误字符串数组 | | validateProductionSecurity | 生产环境 IEC 62443 检查 | | normalizeSecurityConfig | 安全策略默认值 | | stripForbiddenSecretsFromHostConfig | 剥离 JSON 中的敏感字段 | | loadAsaiSecrets / loadDotEnvFile | 加载密钥 | | applySecretsToHostConfig | 合并密钥到 hostconfig | | resolveHttpsCertFromPaths | 从路径读取 PEM | | validateAsaiSecrets / isDevDefaultPassword | 密钥校验 |

路由注册

| 导出 | 说明 | |------|------| | registerApi / registerWs | 注册业务路由工厂 | | initHostserverApi / initHostserverWs | 初始化平台路由表 | | syncApiRouteKeys / syncWsRouteKeys | 同步路由键列表 |

安全与基础设施

| 导出 | 说明 | |------|------| | secureCompare | 恒定时间字符串比较 | | resolvePathUnderRoots / getHostAllowedRoots | 防目录穿越 | | validateHttpAuth | HTTP Userinfo 鉴权 | | logSecurityEvent / getClientIp | 安全审计 | | sanitizeString 等 | 输入净化 |

传输桥接(供 TCP/gRPC/RS485 插件)

| 导出 | 说明 | |------|------| | getTransportBlock / getTransportDefault | 读取 hostconfig 传输配置 | | initTransportBridge | 初始化 $asai 传输桥 | | ensureDefaultConnection / createTransportDataHandler | 连接与数据回调 |

类型导出

AsaiRuntimeHostConfigAsaiHostNodejsOptionsHostBootResultAsaiSecretsSecurityConfig 等见 import type { … } from 'asaihost-nodejs'


字段速查

security

| 字段 | 默认 | 说明 | |------|------|------| | requireAuth | 0 | 1=API 需登录(authSkipPaths 除外) | | csp | 0 | 1=启用 Content-Security-Policy | | auditLog | 1 | 安全审计日志 | | quota.enabled | 0 | 连接/频率配额 |

hosts.default 常用

| 字段 | 默认 | 说明 | |------|------|------| | port | 9198 | 监听端口 | | httptype | http:// | 或 https:// | | ws | — | 1=同端口挂载 WebSocket | | maxhttp / maxws / maxonline | 2000/2000/100 | 限流 | | hostdirs | — | 静态目录(按序查找) | | close | 0 | 1=跳过启动 |

aes

| 字段 | 说明 | |------|------| | lv | 1=可选 AES;>1=全量 AES(须 secrets 注入 keybase64) | | aad / algorithm / keylength / ivlength | GCM 参数 |


开发与发布 npm 包

cd webserver/src/plugs/asaihost-nodejs
npm install
npm run typecheck    # 仅类型检查
npm run build        # tsup 打包 + tsc 声明
npm pack             # 本地验证 .tgz 内容
npm publish --access public

package.json exports 约定

| 条件 | 解析到 | |------|--------| | development | ./index.ts(monorepo + tsx 开发) | | import | ./dist/asaihost-nodejs.es.js | | require | ./dist/asaihost-nodejs.cjs | | types | ./dist/asaihost-nodejs.d.ts |

注意事项

  1. 修改 asaihost.json 后需重启 Node 进程。
  2. 端口被占用 → EADDRINUSE → 静默退出;排查 9198/9199。
  3. CONFIG_WARN 表示使用 dev 默认密码,生产请设 ASAI_HOST_PASSWORD
  4. 业务处理器经模块级 workHandlers Map 注册,不污染 global
  5. 静态路径经 resolvePathUnderRoots 防目录穿越。

约束与前端对应

  • asaihost-vue(前端)配对使用时,保持 asaihost.json / aes 密钥 / VITE_ASAI_AES_KEYBASE64 一致。
  • 插件间禁止跨包 plugs/*/src/ 引用;消费方只走 import from 'asaihost-nodejs'
  • 传输层插件仅通过 $asai.asaihost.* 与宿主协作。

| 前端 | 后端 | |------|------| | asaihost-vue | asaihost-nodejs | | public/webmodel/cfg.js | websys/sys/asaihost.json | | VITE_ASAI_AES_KEYBASE64 | ASAI_AES_KEYBASE64 |


配置以本 README 与 validateHostConfig 源码为准;monorepo 实参见 webserver/websys/sys/asaihost.jsonwebserver/app.ts