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

@kesi/mock

v1.0.1

Published

KESI 前端内存 mock —— URL 驱动的整站演示数据 + axios/WebSocket 传输层拦截

Readme

@kesi/mock

KESI 前端内存 mock —— 单一 JSON 数据源 + axios / WebSocket 传输层拦截。 不依赖真实后端,业务代码零改动即可跑通全平台演示。

packages/kesi/src/lib/kesi/mock/ 抽出为独立工作区库包,应用侧只剩接线。

特性

  • 一个场景一个数据包:演示数据是 data/ 下的 JSON 文件(唯一真源,可手改)。 各 src/data/*.ts 只剩规则(handler / 资源声明),不含任何记录数组 —— 两个场景共用同一套规则,只是数据不同。
  • 运行时动态获取src/loader.tsfetch(真实 HTTP),失败回退动态 import()(独立懒加载 chunk)—— 数据不进任何 JS 启动包,也不内联进产物。
  • URL 前缀即开关/_m_<name>/ 启用,无前缀即真实模式(无默认值)。 <name>数据包别名building → 楼宇包)时装载该包全部数据集; 是数据集名iot/ai…)时用默认包,只装载 base + 该数据集;all 装载默认包全部数据集。
  • 按数据集分片:JSON 里每个集合按数据集分片,因此 _m_iot 只装 base + iot, 语义与旧版逐数据集注册逐字节一致
  • 只拦网络层:复用 @kesi/client 的全部真实逻辑(createAPI / convert_* / model / auth),只替换传输。
  • 契约对齐:查询引擎(filter 操作符 / sort / skip / limit / count)与真实后端语义一致; 记录在装载时做结构 + 契约校验兜底(见下)。
  • 可见的兜底:未覆盖端点仍返回 200(不让页面白屏),但带 x-mock-demo 提示头 + 一次性告警。
  • WS 桥:接管 window.WebSocket,订阅转事件总线,消除真实 /ws 重连刷屏。

可用数据包

| 别名 | 文件 | 场景 | 数据集 | 规模 | |---|---|---|---|---| | factory(默认) | data/mock-data.json | 智慧工厂(中文) | base, iot, business, video, apps, ai, system | 79 集合 / 209 条 | | building | data/mock-data-building.json | 智慧楼宇(中文) | base, building | 81 集合 / 214 条 | | en / factory-en | data/mock-data-en.json | 智慧工厂(English) | base, iot, business, video, apps, ai, system | 79 集合 / 209 条 | | building-en | data/mock-data-building-en.json | 智慧楼宇(English) | base, building | 81 集合 / 214 条 |

http://localhost:5173/_m_all/           # 工厂(默认包)全部数据集
http://localhost:5173/_m_iot/           # 默认包:base + 物联
http://localhost:5173/_m_building/      # 智慧楼宇(中文)
http://localhost:5173/_m_en/            # 智慧工厂(English)
http://localhost:5173/_m_building-en/   # 智慧楼宇(English)

工厂场景内容:7 类设备模型(空压机 / 注塑机 / CNC / 燃气锅炉 / 循环水泵 / 变频器 / 环境传感器)、 15 台设备、报警、6 张工厂管理表、流程 / 报表 / 数据集。

楼宇场景内容:9 类机电设备模型(冷水机组 / 空调机组 AHU / 新风机组 / 电梯 / 照明回路 / 给排水泵 / 智能电表 / 门禁闸机 / 环境传感器)、19 台设备、7 条告警 + 4 条规则告警、 6 张运维表(巡检 / 维保工单 / 分项能耗 / 备件 / 环境监测 / 访客登记)、楼宇流程 / 报表 / 数据集、 监控点位与 AI 助手命名。

平台脚手架(登录 / 设置 / 用户 / 消息、系统备份、模型供应商等)各包一致。

英文包的翻译约定(重要)

英文包把展示文案(设备名、字段标题、描述、消息、区域、人名、公司名…)全部英文化, 但刻意保留下面这些字段的中文原值:

| 字段 | 为什么保留 | |---|---| | warning/warning[*].level / .status / .processed | src/schemas/warning.schema.ts 的筛选枚举就是 ['低','中','高'] / ['未确认','已确认'] / ['未处理','已处理']ClearAlarmDialog 等直接以 filter.processed = '已处理' 查询 | | core/t/schema[*].warning.rules[*].level | DeviceViewDialog / AlarmRulesTablevel === '高' 着色 | | core/message[*].messageType / .optType | 应用把它们当 i18n keyen.json系统→System通知→Notification) |

本应用的约定是「中文值当 i18n key / 筛选枚举」,所以保留中文反而得到英文界面 + 可用筛选; 若把这些也翻成英文,界面同样是英文,但筛选、统计与告警着色会全部失配。 英文包与中文包的结构与记录 ID 完全一致npm run smoke:bundles 会校验), 以后往中文包加设备时记得同步英文包。

新增第三个场景:把 data/mock-data-<name>.json 放好,并在 src/loader.tsMOCK_BUNDLESBUNDLE_IMPORTERS 各登记一行(后者必须是字面量 import,否则打包器 无法切分懒加载 chunk)。

数据放在哪、怎么被读到

data/mock-data*.json                 ← 4 个数据包(唯一真源;中英各 2 个,142~160KB)
        │
        ├─ 1) fetch 调用处传入的地址                        ← installMockIfNeeded({ dataUrl })
        │      或 setMockDataUrl(url) / window.__MOCK_DATA_URL__
        ├─ 2) fetch `${BASE_URL}mock/<包文件名>`            ← 推荐:真实 HTTP
        │      (宿主 `npm run data:copy -- <静态目录>`,如 -- ../kesi/public,会复制全部包)
        ├─ 3) 动态 import('../data/<包文件名>')             ← 兜底:打包器切成独立懒加载 chunk
        └─ 4) provideMockData(json)                         ← Node 脚本 / 宿主接口拉取后注入
        ↓
src/loader.ts  →  按数据集分片 seedCollection(结构 + 契约校验)
        ↓
内存集合 + 查询引擎(src/store.ts)

fetch 候选都失败时不静默:打印明确错误 + 修复指引,并以空集合继续 (请求走演示兜底 200 + x-mock-demo 头,缺口可见但不白屏)。 显式指定的地址(第 1 条)失败时另有一条点名告警 —— 否则公网地址写错 / 被 CORS 拦下时, 会静默跑着内置数据,排查毫无线索。

用公网地址托管数据包

dataUrl 接受任意绝对 http(s) 地址(第 1 条候选本来就支持跨域),例如 CDN / 对象存储 / raw.githubusercontent.com

installMockIfNeeded({ dataUrl: 'https://cdn.example.com/kesi/mock-data-building.json' });

三条硬性前提:

  1. CORS:响应必须带 Access-Control-Allow-Origin(允许本站源或 *)。 我们只发简单 GET(无自定义头)→ 不触发预检,不需要 Access-Control-Allow-Headers
  2. HTTPS:页面是 https 时地址也必须是 https,否则被浏览器的混合内容策略拦截。
  3. 内容:GET 直接返回 kesi-mock-data 格式的 JSON(format / version / datasets / collections)—— 把 data/ 下的文件原样上传即可,不需要任何加工。

注意:公网地址只是换数据来源_m_<别名> 选包 / 选数据集的逻辑不变(远端包里的 datasets 决定可选项)。当前不接受自定义请求头 —— 需要鉴权头的私有地址请用 provideMockData(json) 自己拉取后注入。

用法(消费方)

// main.tsx —— 必须排在 App 之前(模块求值期副作用:URL 含 /_m_ 时同步接管传输层)
import { installMockIfNeeded } from '@kesi/mock/bootstrap';
import { initKesiConfig } from '@/lib/kesi/config';
import App from './App';

// 数据地址可选:不传则自动探测(BASE_URL 静态目录 → 动态 import 兜底)
installMockIfNeeded().finally(() => {
  initKesiConfig();
  render(<App />);
});

// 指定数据地址(三种等价写法)
installMockIfNeeded({ dataUrl: '/static/mock-data.json' });
installMockIfNeeded('/static/mock-data.json');          // 字符串简写
// 或装载前调用底层 API(手动模式也适用):
//   import { setMockDataUrl } from '@kesi/mock';
//   setMockDataUrl('/static/mock-data.json');

dataUrl 会在装载之前登记为最高优先级的 fetch 地址;真实模式(URL 无 /_m_)下即使传了 也不会发起任何请求。

想让数据走真实 fetch(而不是回退 chunk),把 JSON 放进宿主静态目录:

cd packages/mock
npm run data:copy -- ../kesi/public
# → packages/kesi/public/mock/mock-data.json
#   packages/kesi/public/mock/mock-data-building.json

参考实现:packages/kesi/src/main.tsx

什么不该进本包:应用的认证/登录态逻辑(如 packages/kesisetupAuthInterceptor, 处理 401/403 后清登录态与跳转)留在应用侧。判据是「这件事属于谁」—— mock 的启用判定与免登录属 mock,应用登录态属应用。

三条硬约束(改错会静默失效或让数据回到启动包)

  1. axios / @kesi/client / react / dayjs 是 peerDependency,构建时 external。 mock 靠 patch 消费方的 axios 实例拦截请求;一旦把 axios 打进本包,补丁作用在另一份副本上, 拦截会静默失效(请求照常打到真实后端且无任何报错)。@kesi/client 同理——它的 config 是 模块级单例,bootstrap 的自动登录要 setConfig 写它,副本化后写不到应用那份。消费方还需把 axios 放进 resolve.dedupe
  2. barrel 不得静态再导出 ./data/** data/index.ts 静态 import 了全部数据集规则文件,被 barrel 再导出会把整张规则图拉进消费方启动包。 数据入口一律深路径:await import('@kesi/mock/data')@kesi/mock/data/base。 (src/loader.tssrc/ 顶层、不 import 任何数据集文件,所以可以从 barrel 安全导出。)
  3. 消费方需 optimizeDeps.exclude: ['@kesi/mock'] 预打包会把本包摊平成单文件,loader.tsimport('../data/mock-data*.json') 的懒加载被拉直。

另注:不要把数据改回 new URL('../data/mock-data.json', import.meta.url)。 Vite 在 library 模式下会把这类资源内联成 base64 data URL 写进 JS(实测 loader.js 从 9KB 涨到 198KB), 等于把数据塞回产物里。fetch + 动态 import() 的组合才是「数据不进 JS」。 新增数据包时,BUNDLE_IMPORTERS 里必须是字面量 import(变量路径打包器无法切分 chunk)。

命令

npm run build          # 构建 dist(vite preserveModules + tsc 声明文件)
npm run type-check
npm run smoke          # 传输层 21 项断言
npm run smoke:client   # 真实 @kesi/client 整链路 9 项断言
npm run smoke:bootstrap # bootstrap 数据地址参数 7 项断言(含真实模式不发请求)
npm run smoke:bundles  # 数据包 34 项断言(别名 / 场景不串味 / 英文包 / 结构镜像 / 产物兜底)
npm run check          # 数据校验:全部数据包(结构 + 契约);CI:有 error 级违规即非零退出
npm run check -- data/mock-data-building.json   # 只校验指定包
npm run data:copy -- <静态目录>   # 把全部 mock-data*.json 复制到宿主静态目录(走真实 fetch)

本包不依赖应用,scripts/ 下的脚本可独立运行(Node 24 原生类型擦除,直接跑 .ts)。 应用侧 npm run mock:smoke / mock:check 是转发到这里。

改了 src/ 之后必须重新 npm run build —— 应用消费的是 dist 产物。

目录

data/                          # ★ 数据包(唯一真源,集合 → 数据集分片 → 记录)
├── mock-data.json             # 智慧工厂(79 集合 / 209 条)
├── mock-data-building.json    # 智慧楼宇(81 集合 / 214 条)
├── mock-data-en.json          # 智慧工厂 English
└── mock-data-building-en.json # 智慧楼宇 English

src/
├── index.ts        # 纯 barrel(无副作用):传输层 + 规则 + 契约 + 事件 + stubs
├── bootstrap.ts    # ★ 启动引导:模块求值期装传输层 + 渲染前装数据/免登录(入口 @kesi/mock/bootstrap)
├── url.ts          # mock name 解析(零依赖,bootstrap 与 data 共用)
├── loader.ts       # ★ 数据装载:fetch / 动态 import / 注入 → 按数据集分片注册 + 结构校验
├── mock-config.ts  # 运行时配置(log / defaultDelay);router 与 loader 的公共上游
├── install.ts      # installMockTransport(同步)/ installMockData(异步)/ installMockAdapter
├── adapter.ts      # axios adapter:URL 归一 → router;4xx 按 AxiosError 抛;__MOCK_REQ_LOG__
├── router.ts       # 请求入口 await 数据就绪;规则匹配 → 集合 CRUD → 演示兜底
├── store.ts        # 内存集合 + 查询引擎(不裁剪字段投影)+ 装载时契约校验
├── contracts.ts    # 种子契约表(字段 / 类型 / 取值范围)
├── websocket.ts    # window.WebSocket 桥
├── push.ts         # 模拟推送定时器(message 20s / logs 8s / historycomputed 2s)
├── events.ts       # 事件总线 + 响应式值仓库
├── stubs.tsx       # useWS / useTag / useTableData / useServerTime(手动模式覆盖用)
└── data/           # 各数据集:只有规则,没有记录
    ├── index.ts    # 注册表 + registerMockByName + 数据装载 API 再导出
    ├── base.ts     # 登录链路 / 设置 / 静态资源与动态模式声明(+ mockUser 常量)
    ├── messages.ts iot.ts business.ts video.ts apps.ts ai.ts system.ts

数据校验(结构 + 契约)

两层防御,由 npm run check每个数据包跑一遍:

  1. JSON 结构校验loader.validateMockDataBundle):format / version / datasets / collections[*].parts[*] 必须是数组 —— 手改 JSON 写错形状会立刻报错,不会静默进内存。
  2. 契约校验contracts.ts):把「数据字段必须与前端类型一致」从口头约定变成可执行校验。 bugs/ 下 BUG-033/037/038/039/044/048/050 属同一族(字段名或结构错配 → 列表空白 / 按钮禁用 / 关联数恒 0 / 详情弹窗空壳),现在会被拦下。

新增或修改数据时,若该集合在真实后端有稳定 shape,请顺手在契约表登记。 跨场景的一致性由 npm run smoke:bundles 兜底:各包子集互不串味,且英文包与中文包结构 / ID 完全镜像。

已知残留

packages/kesi/docs/mock-api-mode.md §十一(生产构建下 core/setting/part 有 1 次真实请求, 存量问题,怀疑 @kesi/client 产物内联了自己的 axios 副本)。