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

@tkwf/tsclient-mock

v1.4.5

Published

Type-driven mock runtime for @tkwf/tsclient — MockTransport, type-driven factory, in-memory query engine

Readme

@tkwf/tsclient-mock

类型驱动的 mock 运行时——为 @tkwf/tsclient 提供 Transport 层注入的 mock 能力,让原型、demo、单测在后端未实现时也能真实运行。

业务代码(Tkwf.User.Use<XxxService>())零改动
        ↓
   Transport 接口层 ← MockTransport 注入在这里(网络栈之前)
        ↓
   Mock 数据 / 内存数据库(createMockFactory / createMockDb)

为什么需要它

痛点

| 痛点 | 后果 | |------|------| | WebApi 未实现,原型/demo 跑不起来 | UI 无法演示可交互效果,前端被后端阻塞 | | Agent 手写 mock 数据易错 | 需读 4000+ 行生成文件才知道字段/类型,mock 结构与真实接口漂移 | | 手写 mock 是"一次性代码" | 无类型安全、无完整性保证、无查询语义,demo 只能看不能点 | | 测试与开发 mock 各自为政 | 单测一套 mock、原型一套 mock,无统一机制 |

目标

  • 业务零改动:实现 Transport 接口,Tkwf.User.Use<XxxService>() 调用链完全不变
  • Agent 可自行填充:createMockFactory<T>() 基于生成 DTO 类型递归生成合法默认值,Agent 只表达业务意图(覆盖关键字段),类型/结构由工具兜底
  • 查询语义真实:createMockDb 让 QueryBuilder 的 where/orderBy/page 在 mock 下真实过滤/排序/分页
  • 完整性保证:codegen 生成全部 field 的 handler 骨架,API 不可能漏掉

不做什么

HTTP mock server 已作为 v1.8.0 功能新增(见下方章节)。 以下仍不属于本包范围:

  • 不做 HTTP 层 mock server(MSW 式)——那属 ApiService 层职责,由 v1.8.0 MockHttpServer 在 @tkwf/tsclient-mock 内实现(走 node:http,零外部依赖)
  • 不做运行时契约校验与 mock 数据的自动缝合(AI 编排场景由消费端 SKILL 落地)
  • 不做多语言 mock 运行时(仅 TypeScript 消费端)

安装

// package.json(dev 依赖,生产零携带)
{
  "devDependencies": {
    "@tkwf/tsclient-mock": "file:../tkwf-tsclient-mock"
  }
}

快速开始

import { MockTransport, createMockDb, defaultSessionHandlers } from "@tkwf/tsclient-mock";
import { Tkwf } from "@tkwf/tsclient";

// 1. 建内存数据库 + 注册 field handler
const db = createMockDb({ paymentLogs: [] });
db.registerQuery("paymentLog", "paymentLogs");
db.registerMutation("createPaymentLog", "paymentLogs", "create");

// 2. 组装 MockTransport(会话用内置 handler)
const transport = new MockTransport({
  ...defaultSessionHandlers,
  paymentLog: (vars) => db.query("paymentLogs", vars?.filter, vars?.sort, vars?.page),
  createPaymentLog: (vars) => db.insert("paymentLogs", vars?.input),
}, { delayMs: 150 });

// 3. 注入 Transport —— 业务代码零感知
const useMock = import.meta.env.VITE_USE_MOCK === "true";
Tkwf.configure("default", {
  endpoint: "/graphql",
  ...(useMock ? { transport } : {}),
});

之后 Tkwf.User.Use<PaymentLogService>().getList() 照常调用,走的是 mock 数据。


真实感数据生成(可选,需 faker.js)

createMockFactory 支持 _strategy: "realistic" 策略,自动将字段名映射到真实数据(人名/公司名/地址/电话等)。需要安装 @faker-js/faker 并传入实例:

npm install --save-dev @faker-js/faker
import { fakerZH_CN } from "@faker-js/faker";
import { createMockFactory } from "@tkwf/tsclient-mock";
import type { Merchant } from "./gql/ts-client.g";

const factory = createMockFactory<Merchant>({
  _types: MerchantSchema,
  _strategy: "realistic",
  _faker: fakerZH_CN,
});

const merchant = factory.make();
// → { name: "张三", company: "星辰科技有限公司", address: "朝阳区建国路88号", phone: "13800138000" }

提示:_strategy: "realistic" 不传 _faker 时会自动降级为 minimal 策略,并输出 console.warn 提示安装 faker.js。


核心能力

| 模块 | 能力 | |------|------| | MockTransport | 实现 Transport:按 field 分发 handler + delayMs / failRate / error 注入 + executeRawGraphQL 解析 | | createMockFactory<T>() | 类型驱动默认值生成(递归)+ 确定性种子 + make/makeN/makeMany + _strategy: "realistic" \| "minimal" 策略(需 faker.js) + _generators 字段覆盖 + _relations 关联数据 | | createMockDb() | 内存数据库:CRUD + FilterInput/SortInput/分页 + 关联图 + mutation→query 状态同步 + queryOne + OperationFilterInput 家族兼容 | | gen-mock-handlers | 消费端 codegen 扩展:读 ts-client.g.ts → 生成全部 field 的 handler 骨架 ts-client.mock.g.ts;v1.3.0 支持 --mock-spec 生成 MOCK_SPEC.md 映射表 + createMockDb 反向引用注释 | | validateMock / selfHealing / detectChange | AI 编排基础设施:schema 校验 / 自愈重试 / 产物变更检测(不内置 LLM) | | defaultSessionHandlers | 登录链路(requestChallenge / loginByContext / loginByPassword / logout)内置 mock | | defineMock() | 类型化 handler 定义辅助(消费端 codegen 产物使用,泛型约束 field/args/result) | | createScenarioContext() | 场景协调器:setScenario 联动 db 数据集 + transport 注入,一键切换默认/空态/错误态/加载态 | | createRecordingTransport() | 录制回放装饰器:record/replay/passthrough 三态模式,真实请求录制 → 测试回放 | | mockFieldSchemaToZod() | 运行时契约校验:MockFieldSchema → zod 适配器,validateMock 底层基于 zod safeParse | | registerRelation() | 关联过滤嵌套:registerRelation 声明外键关系,some/every/none 关联查询 | | aggregate() | 聚合查询:db.aggregate(table, { fields }) 支持 count/avg/sum/max/min | | MockHttpServer | HTTP mock server:基于 node:http 的轻量 HTTP 层 mock,CORS/鉴权/GraphQL over HTTP |


消费端 codegen 工作流(v1.1.0)

一次性生成全部 handler 骨架

npx gen-mock-handlers --input src/ts-client.g.ts --output src/ts-client.mock.g.ts

同时生成 MOCK_SPEC.md 映射表(v1.3.0)

npx gen-mock-handlers --input src/ts-client.g.ts --output src/ts-client.mock.g.ts \
    --mock-spec .TKWF/merchant/MOCK_SPEC.md

--mock-spec 幂等更新 MOCK_SPEC.md 的 API → 数据表映射表:

  • 已存在 <!-- auto-generated: mapping-table --> 标记段 → 只替换标记段,保留手写的数据策略
  • 无标记 → 追加到文件末尾
  • 文件不存在 → 创建

生成的 createMockDb 同时携带反向引用注释,指示 Agent 每张表影响哪些 API:

export const db = createMockDb({
  loginPayloads: [] satisfies LoginPayload[],  // → API: loginByContext, loginByPassword, logout
  paymentLogs: [] satisfies PaymentLog[],      // → API: loadPaymentLogs
});

MOCK_SPEC.md 模板(含填写指引)位于 skills/tkwf-tsclient-mock/MOCK_SPEC.md.template, 配合 tkwf-tsclient-mock skill 使用,指导 Agent 完成从文档到 data.ts 的完整填充流程。

读取消费端 codegen 产物 ts-client.g.ts(主包生成),生成 ts-client.mock.g.ts:

  • 全部 field 的 handler 骨架(Query/Mutation 分类读 const 对象,不启发式推断)
  • 每个 field 用 defineMock<{ field; args; result }> 约束,类型错误编译期暴露
  • 生成 createMockDb 内存数据库 + DTO → MockFieldSchema 推导(_types)
  • 编译期完整性检查:_AssertAllFieldsCovered —— 主包 codegen 新增 field 后重跑本命令,漏掉的 API 直接编译报错

生成后的骨架:

export const db = createMockDb({ paymentLogs: [] });

export const handlers = {
  paymentLogs: defineMock<{ field: "paymentLogs"; args: PaymentLogsArgs; result: PaymentLogConnection }>(
    (vars) => db.query("paymentLogs", vars?.where, vars?.order, { first: vars?.first, after: vars?.after }),
  ),
  createPaymentLog: defineMock<{ field: "createPaymentLog"; args: CreatePaymentLogInput; result: PaymentLog }>(
    (vars) => db.insert("paymentLogs", vars),
  ),
} satisfies Record<keyof typeof Query | keyof typeof Mutation, MockHandler>;

骨架遵循的语义映射:

| field 特征 | 生成骨架 | |-----------|---------| | query + 返回 XxxConnection | db.query("xxx", args.where, args.order, { first, after }) | | query + 返回单实体 | db.queryOne("xxx", args.where) | | mutation + args 含 input | db.insert("xxx", args.input) | | mutation + 命名 create/update/delete | db.insert / db.update(table, id, patch) / db.remove(table, id) | | 无法归类 | db.query("xxx") + 注释"待 Agent 填充" |

AI 编排基础设施(src/ai/)

不内置 LLM 调用,为消费端 AI/Agent 填充提供三层能力(validateMock / selfHealing / detectChange):

import { validateMock, selfHealing, detectChange } from "@tkwf/tsclient-mock";

// 1. 校验:mock 数据是否符合 DTO schema(复用 MockFieldSchema)
const { ok, errors } = validateMock(agentData, dtoSchema);

// 2. 自愈:schema 校验失败自动重新生成(LLM/工厂可注入,默认重试 3 次)
const data = await selfHealing({
  schema: dtoSchema,
  generator: () => llmFill(prompt, dtoSchema),   // LLM 调用由消费端 SKILL 落地
});

// 3. 变更检测:codegen 产物 sha256 hash 与 sidecar 文件(<output>.hash)比对
const { hash, changed } = await detectChange(readFileSync("src/ts-client.g.ts", "utf-8"));
if (changed) console.log("codegen 产物已变更,请重新执行 gen-mock-handlers");

AI 填充工作流:gen-mock-handlers 生成骨架 → Agent 填充业务意图(覆盖关键字段)→ validateMock 校验 → 失败由 selfHealing 重试 → detectChange 感知主包 codegen 产物变更。


场景切换(v1.2.0)

运行时切换 mock 行为:默认态(正常数据)/ 空态(空数据)/ 错误态(注入 error)/ 加载态(长延迟)——不重启、不改代码、零业务改动。

核心概念

  • 场景 = 数据视图(db 数据集) + 注入配置(transport 注入),以场景名关联
  • 四种内置场景约定:default(正常数据 + 无注入)、empty(空数据)、error(注入 error/failRate)、loading(长 delayMs)
  • 消费端可自定义扩展任意场景名(如 "emptyLoading" 同时设空数据 + 长延迟)

多数据集(createMockDb)

const db = createMockDb(
  { paymentLogs: [] },                             // default 数据集
  {
    datasets: {
      default: { paymentLogs: [{ id: 1, status: "ok", amount: 100 }] },
      empty: { paymentLogs: [] },
    },
  },
);

db.switchDataset("empty");     // 切换到空数据
db.getDatasetName();           // → "empty"
db.listDatasets();             // → ["default", "empty"]
db.reset();                    // 重置当前活跃数据集到初始快照
db.reset("default");           // 切换到 default 并重置

场景注入(MockTransport)

const transport = new MockTransport(handlers, {
  scenarios: {
    error: {
      fieldOptions: {
        paymentLogs: { error: new Error("数据库不可用") },
      },
    },
    loading: { delayMs: 3000 },
  },
});

transport.setScenario("error");     // 切换错误态
transport.getScenario();            // → "error"
transport.getScenarioNames();       // → ["default", "error", "loading"]

注入优先级(逐项覆盖,场景优先):

error:     scenarios[scenario].fieldOptions?.[field]?.error ?? scenarios[scenario].error ?? fieldOptions?.[field]?.error
failRate:  scenarios[scenario].fieldOptions?.[field]?.failRate ?? fieldOptions?.[field]?.failRate
delayMs:   scenarios[scenario].fieldOptions?.[field]?.delayMs ?? scenarios[scenario].delayMs ?? fieldOptions?.[field]?.delayMs ?? delayMs
timeoutMs: scenarios[scenario].fieldOptions?.[field]?.timeoutMs ?? fieldOptions?.[field]?.timeoutMs

handler 感知场景

ctx.scenario 可选字段,handler 内部可据此返回差异化数据:

const handlers = {
  paymentLogs: (vars, ctx) => {
    if (ctx.scenario === "error") {
      return { nodes: [], totalCount: 0, pageInfo: {} };  // 错误态返回空列表
    }
    return db.query("paymentLogs", vars?.where, vars?.order, { first: vars?.first });
  },
};

场景协调器(createScenarioContext)

一键联动 db 数据集 + transport 注入:

const db = createMockDb({ paymentLogs: [] }, {
  datasets: {
    default: { paymentLogs: [{ id: 1, status: "ok" }] },
    empty: { paymentLogs: [] },
  },
});
const transport = new MockTransport(handlers, {
  scenarios: {
    error: { fieldOptions: { paymentLogs: { error: new Error("boom") } } },
    loading: { delayMs: 3000 },
  },
});

const scenario = createScenarioContext({ db, transport });

scenario.setScenario("empty");    // 一起切换:数据变空 + 注入不变
scenario.setScenario("error");    // 数据正常 + 注入 error
scenario.setScenario("loading");  // 数据正常 + 长延迟

协调器自动保证原子性:校验优先(场景名必须存在于 db 或 transport 至少一侧),切换失败时回滚已成功的一侧。

codegen 场景骨架

gen-mock-handlers 生成的 ts-client.mock.g.ts 产物新增两段,供消费端 Agent 填充:

// ── 场景数据集骨架(数据留 Agent 填充) ──
export const scenarios = {
  default: { paymentLogs: [] satisfies PaymentLog[], ... },
  empty:   { paymentLogs: [] satisfies PaymentLog[], ... },
};

// ── 场景注入配置骨架 ──
export const scenarioOverrides: Record<string, ScenarioConfig> = {
  error:   { fieldOptions: { /* TODO: Agent 按 field 填 error / failRate */ } },
  loading: { delayMs: 3000 },
};

分阶段策略指南

| 阶段 | 场景组合 | 说明 | |------|---------|------| | 原型 | setScenario("default") + 简单数据 | 快速验证 UI 交互,数据不严格但可交互 | | 开发 | 自定义场景:datasets.local + scenarios.dev | 本地调试数据,可叠加错误态验证异常路径 | | 测试 | setScenario("empty") / setScenario("error") | 确定性的空态/错误态,无需改代码切换 |

场景切换 = 运行时行为,不涉及代码变更或重新生成。原型→开发→测试的过度只需切场景名,业务代码零改动。


与其它类似项目的差异

业界现状:三块各自成熟的拼图

| 能力 | 成熟产品 | 缺什么 | |------|---------|--------| | Transport 注入层 | Apollo MockLink(最接近)、tRPC link(官方无 mock,#2468 wontfix)、Apollo SchemaLink | 只静态匹配,无类型驱动、无内存语义 | | 类型驱动数据工厂 | graphql-codegen typescript-mock-data、Fabbrica、zod4-mock、TypeBox | 只生成对象,无拦截、无查询 | | 内存查询语义 | MirageJS(ORM+引用完整性)、sift.js(MongoDB 操作符→数组过滤) | 无类型驱动生成,GraphQL 次级支持 |

差异化:三块拼图的缝合点

1. 不依赖 SDL schema,只依赖 codegen TS 类型

Apollo / graphql-tools 全卡在"必须有完整 schema"。RPC 风格客户端消费端已有 codegen Service 接口 + DTO 类型,本包从 TS 类型直接出发,schema 无关。

2. 注入点在 Transport 接口而非网络层

比 MSW 更接近协议语义:无需 Service Worker,Node / 浏览器 / Worker 全环境通用;业务代码不感知 mock 存在。这是 tRPC 官方欠账(#2468 wontfix)的空白。

3. field 级分发 + 内存查询语义 + 关系一致性

Mirage 证明了 mutation→query 联动是刚需,但无人把"类型驱动生成 + transport 注入 + 内存查询"三者缝合——这正是本包的定位。

优势

  • ✅ 零业务改动:Transport 层注入,调用链不变
  • ✅ 类型即契约:satisfies + codegen 重生成 → 字段变化编译报错,防漂移
  • ✅ 可交互 demo:mutation 后 query 立即可见新数据(不是静态假数据)
  • ✅ 环境无关:Node/浏览器/Worker 通用,无 Service Worker 依赖
  • ✅ 确定性可复现:种子固定 → 本地固定、CI 用 run-id
  • ✅ 生产零携带:独立包 + devDependencies,生产不打包

局限

  • ❌ 不适用:需要真实 HTTP 语义(CORS/中间件/鉴权链路)的场景
  • ❌ 查询语义子集:FilterInput 覆盖常用操作符,非常规 GraphQL 过滤需自定义 handler
  • ❌ 运行时契约校验缺位:TS 类型 → zod 的运行时校验(P4)未实现,mock 数据绕过真实 schema 校验

录制回放(v1.3.0)

真实后端的请求/响应录制 → 测试时确定性回放,测试用真实数据而非手工 mock。

三态模式

| 模式 | 行为 | |------|------| | record | 走真实 Transport,记录请求/响应(含错误) | | replay | 从录制数据匹配请求,返回录制响应(不依赖后端) | | passthrough | 直通真实 Transport,不记录 |

快速开始

import { createRecordingTransport, FileRecordingStore, normalizeTimestamps } from "@tkwf/tsclient-mock";

// 1. 录制:真实后端 → 文件
const recordTransport = createRecordingTransport(realTransport, {
  mode: "record",
  recordingName: "payment-flow",
  store: new FileRecordingStore("./recordings"),
  normalizers: {
    normalizeResult: (result) => normalizeTimestamps(normalizeTimestamps(result)),  // 时间戳归一化
  },
});
const store = new FileRecordingStore("./recordings");
store.start("payment-flow");
await recordTransport.execute({ field: "paymentLogs", type: "query", variables: { first: 10 } });
store.stop();

// 2. 回放:测试时从文件加载,确定性返回
const replayTransport = createRecordingTransport(mockTransport, {
  mode: "replay",
  recordingName: "payment-flow",
  store: new FileRecordingStore("./recordings"),
});
const result = await replayTransport.execute({ field: "paymentLogs", type: "query", variables: { first: 10 } });
// result = 录制时的真实响应

匹配与消费

  • 匹配键:field + type + 归一化 variables(variables 键排序、undefined→{})
  • 有序(默认):FIFO 消费录制条目,maxUsageCount 控制单条可消费次数
  • 无序(order: false):polling 场景,取第一个可消费条目(确定性)
  • 未命中:触发 onMiss 回调 + 抛错
  • 错误条目:回放时抛 MockRecordingError(携带 source/errorCode)

归一化

非确定性字段(时间戳/UUID)录制时替换为固定占位符,回放可重复:

import { normalizeTimestamps, normalizeUuids } from "@tkwf/tsclient-mock";

normalizeTimestamps("2026-05-01T12:00:00.000Z");  // → "2026-01-01T00:00:00.000Z"
normalizeUuids("550e8400-e29b-41d4-a716-446655440000");  // → "00000000-0000-0000-0000-000000000000"

提示:归一化器默认用于 normalizeResult(避免误伤 variables 中的合法业务 ID/时间戳)。

存储

  • 内存(默认):MemoryRecordingStore,进程内
  • 文件:FileRecordingStore(dir),<dir>/<name>.json 每文件一录制
  • 自定义:实现 RecordingStore 接口 + configureRecordingStore() 注入(复用 configureSidecar 模式)

运行时契约校验(v1.4.0)

mock 数据经过真实 schema 校验(基于 zod v4),AI 填充错误被自愈重试捕获。

MockFieldSchema → zod 适配器

mockFieldSchemaToZod(schema) 将 7 种 kind(string/number/boolean/date/enum/array/object)递归映射为 zod schema:

import { mockFieldSchemaToZod, validateWithZod } from "@tkwf/tsclient-mock";

// 直接校验数据
const result = validateWithZod(PaymentLogSchema, agentData);
if (!result.ok) {
  console.log(result.errors);   // ["$.status: Invalid option: expected one of ..."]
  console.log(result.issues);   // [{ code, path, message }] 结构化问题
}

语义保留(对齐旧 validateMock)

| 语义 | 实现 | |------|------| | undefined 不报错(未填充) | 顶层 .optional() | | object 缺失/多出字段不报错 | .partial() + strip | | 空 enumValues 放行 | 降级 z.union([z.string(), z.number()]) | | date 兼容 Date / ISO string / number 时间戳 | z.union([z.iso.datetime(), z.date(), z.number()]) |

codegen 运行时校验骨架

gen-mock-handlers 生成的产物新增 validateXxx(data) 辅助函数(动态 import,不调用不加载 zod):

const result = await validatePaymentLog(agentData);  // zod safeParse 结果
if (!result.success) console.log(result.error.issues);

依赖

zod@^4 作为 peerDependency——消费端需自行安装(仅校验功能需要):

npm install --save-dev zod@^4

MockDataSpec 规则驱动生成(v1.4.0)

从语言无关的 MockDataSpec JSON 规则模板生成数据,替代手写 data.ts。

MockDataSpec 类型族

MockDataSpec 是语言无关的规则模板,描述"生成什么数据、怎么生成"。新增独立类型族,与 MockFieldSchema(类型描述符)关注点分离:

| 类型 | 职责 | 维护者 | |------|------|--------| | MockDataSpec | 顶层规则:version/locale/seed/entities/scenarios | 人工/skill 编写 | | MockEntitySpec | 实体级规则:count/strict/fields/relations | 人工/skill 编写 | | MockFieldRule | 字段级生成策略:kind/strategy/distribution/nullable/compute | 人工/skill 编写 | | MockFieldSchema | 字段类型描述符(codegen 产物) | 自动生成 |

快速开始

import { parseMockDataSpec, generateFromSpec } from "@tkwf/tsclient-mock";
import { createMockDb } from "@tkwf/tsclient-mock";
import { fakerZH_CN } from "@faker-js/faker";

// 1. 加载规则
const spec = parseMockDataSpec(jsonString);

// 2. 生成数据
const seed = generateFromSpec(spec, { faker: fakerZH_CN });

// 3. 加载到内存数据库
const db = createMockDb({});
db.buildDataset(seed);

生成策略

| strategy | 语义 | 示例 | |----------|------|------| | sequence | 自增序列 | start: 1 → 1, 2, 3... | | uuid | UUID | 自动生成 UUID 字符串 | | ref | 引用其他实体 FK | ref: "StoreInfo.Uid" | | faker | faker 方法生成 | fakerMethod: "company.name" | | range | 数值范围 | min: 100, max: 99999 | | dateRange | 日期范围 | between: ["2026-01-01", "2026-08-16"] | | pattern | 模式字符串 | pattern: "BILL-####" | | computed | 计算字段 | compute: { op: "subtract", operands: [...] } | | constant | 固定值 | value: "fixed" | | sample | 从样本集随机选取 | samples: ["A", "B", "C"] | | enum | 枚举值 | values: ["A", "B"], distribution: "weighted" |

分布类型

| distribution | 语义 | 适用策略 | |-------------|------|---------| | uniform | 均匀分布(默认) | range, enum | | weighted | 加权离散分布 | enum(配合 weights) | | gaussian | 正态分布(首版降级为 uniform) | range | | cyclic | 轮询(确定性) | enum |

computed 表达式

安全求值,无 eval。仅支持结构化运算符:

{
  "op": "subtract",
  "operands": [
    { "field": "TotalAmount" },
    { "expr": { "op": "coalesce", "operands": [{ "field": "DiscountAmount" }, { "literal": 0 }] } }
  ]
}
// 等价于:TotalAmount - (DiscountAmount ?? 0)

v1.4.1 管线顺序:computed 在 belongsTo 关系填充 FK 之后求值,因此 computed 字段可以引用 relation 填充的 FK 字段(如 coalesce(storeId, 0))。求值顺序:makeN → applyRelations → applyComputed → applyNullable → collectIds。computed 按字段声明顺序求值,依赖项需先声明。

场景化生成(v1.4.1)

generateFromSpec(spec, { scenario }) 按 spec.scenarios[scenario] 覆盖实体 count(生成期);未提及的实体保持默认 count:

{
  "scenarios": {
    "default": { "PaymentLog": { "count": 50 }, "StoreInfo": { "count": 5 } },
    "empty":   { "PaymentLog": { "count": 0 },  "StoreInfo": { "count": 0 } },
    "minimal": { "PaymentLog": { "count": 3 },  "StoreInfo": { "count": 1 } }
  }
}
const spec = parseMockDataSpec(jsonString);
const minimal = generateFromSpec(spec, { scenario: "minimal" });  // PaymentLog=3, StoreInfo=1
const empty   = generateFromSpec(spec, { scenario: "empty" });    // 全部 0 条(验证空态 UI)
  • 未知场景 → 抛错,错误信息列出可用场景名
  • count=0 → 实体返回 [],依赖它的子实体 relation 跳过 FK 填充(warn)
  • 运行时场景切换(数据+注入联动、不重新生成)仍用 createScenarioContext——两者正交:generateFromSpec 场景参数管"生成什么量",createScenarioContext 管"运行时行为"

导入导出

import { serializeDatasetSeed, parseDatasetSeed } from "@tkwf/tsclient-mock";
// Node-only:
import { exportDatasetSeed, importDatasetSeed, loadMockDataSpec } from "@tkwf/tsclient-mock/server";

// 序列化
const json = serializeDatasetSeed(seed, { pretty: true });

// 解析
const seed = parseDatasetSeed(json);

// 文件 I/O(Node-only)
exportDatasetSeed(db, ["paymentLogs", "storeInfos"], "seed.json");
importDatasetSeed(db, "seed.json");
const spec = loadMockDataSpec("mock-data-spec.json");

v1.4.2(跨项目共享):接收方导入时用 db.buildDataset(seed, { unknownTables: "warn" }) 检测表名不匹配——seed 表名与 createMockDb 声明的表名不符时立即 console.warn(或 "error" 抛错),避免数据注入到无人查询的表导致页面空白。完整接收方工作流见 skill SKILL.md Step 5(DatasetSeed / MockDataSpec / MOCK_SPEC.md 三种接收路径)。

faker 方法映射表外置

字段名→faker 方法的映射表从 factory.ts 硬编码提取为 faker-method-map.json,位于 src/mock-spec/faker-method-map.json。.NET 侧(Bogus)可加载同一 JSON 实现跨语言一致性。


未来规划(版本路线图)

每个版本独立走:开发方案 → 审核 → 开发 → 审核报告 → 提交(见 docs/迭代开发过程/V{主版本}/)。 当前实现 = v1.4.5 内容。 历史版本说明:旧 v1.3.0–v1.9.0 为历史开发 tag(未独立发布,已并入 v1.2.2);当前 v1.3.0 为全新发布,内容为 Mock Agent 支撑。

| 版本 | 内容 | 说明 | |------|------|------| | v1.0.0 | 三大核心(MockTransport / createMockFactory / createMockDb) | ✅ | | v1.1.0 | codegen 扩展 + AI 编排(validateMock/selfHealing/detectChange) | ✅ | | v1.2.0 | 场景切换(setScenario)+ 分阶段策略 | ✅ | | v1.2.2 | 策略化数据生成(realistic/minimal)+ 关联数据生成(_relations)+ 全部历史能力汇总(含录制回放/zod 校验/关联过滤/HTTP server/工厂 DSL) | ✅ | | v1.3.0 | Mock Agent 支撑:createMockDb 反向注释(// → API:)+ gen-mock-handlers --mock-spec + MOCK_SPEC.md 模板 + tkwf-tsclient-mock skill | ✅ | | v1.4.0 | MockDataSpec 规则驱动生成:MockDataSpec 类型族 + generateFromSpec() + parseMockDataSpec() + serializeDatasetSeed()/parseDatasetSeed() + exportDatasetSeed()/importDatasetSeed() + faker 方法映射表外置 + skill 四步工作流 + schema 策略枚举约束 | ✅ | | v1.4.1 | 场景化生成 + computed 管线修正:generateFromSpec(spec, { scenario }) 场景覆盖 count + computed 移至 relations 之后(可引用 FK 字段)+ parse 场景实体名校验 | ✅ | | v1.4.2 | 接收方导入工作流全套支持:buildDataset(seed, { unknownTables }) 未知表名检测(warn/error/ignore)+ skill Step 5 接收方导入(DatasetSeed / MockDataSpec / MOCK_SPEC.md 三路径)+ 共享与移植指引 | ✅ | | v1.4.3 | gen-seed CLI + session handlers 补齐 + importDatasetSeed 透传:npx gen-seed --spec mock-data-spec.json 一键导出 seed.json + defaultSessionHandlers 补 loginBySms/ping/registerSecure/loginByQrCode + 修复 loginByPassword/loginByContext 补 success + importDatasetSeed 透传 unknownTables | ✅ | | v1.4.4 | 数组返回 handler 生成修复 + 遗留收尾:gen-mock-handlers 识别返回数组的 API(XxxDto[] / Array<XxxDto>),生成 db.query(table) 而非错误的 db.queryOne(table);where/order 用 parts 累积拼装(并存均透传);数组 mutation(createBatch)生成批量 db.insert;可空数组 Xxx[] \| null 判定;Connection pageInfo 用 first+1 探测计算真实 hasNextPage;标量返回(number/boolean)按语义分支处理(count 类返回行数、boolean 操作类返回 true、查询标量读 row.value);remove/delete 支持嵌套 request 包裹 id(如 RemoveBuddy_ExecuteArgs.request.buddyId,修 vars?.id 类型错误);认证类 mutation 防 insert 回归(LoginPayload/RegisterResult/ChallengeResponse 返回改生成 queryOne 预置数据) | ✅ | | v1.4.5 | handler-kind 权威化(G16 对称根治):isMutation 改由 parsedDoc.fields(Query/Mutation const,schema 权威——对齐主包 operationKinds 同源数据)判定,未覆盖字段回退启发式——removeBuddy_Execute/createTask_Execute(Query 根,Remove/Create 前缀)不再生成破坏性 db.remove/db.insert(G16 镜像:主包 SDK 误发 mutation 400、mock 误生成写 handler);mutation 标量返回补操作成功分支(addBuddy/lockX/unlockX/resetX 等 Mutation 根布尔操作类 → return true,不再落 catch-all queryOne 幻影表;delete/remove 前缀标量 mutation 保留实际 db.remove 写语义);动词表统一为共享常量(src/codegen/verbs.ts:DERIVE_ENTITY_VERBS/OP_SUCCESS_VERBS,补 add/lock/unlock/reset/save/upsert,消除双文件漂移) | ✅ 当前版本 | | ~~历史 tag~~ | v1.3.0–v1.9.0 旧历史开发 tag(录制回放/zod/查询增强/关联过滤/双向同步/HTTP server/工厂 DSL) | 已并入 v1.2.2 |

主包 @tkwf/tsclient v1.1.0:DomainHostClientOptions.transport 注入点(另一仓库,独立迭代)。


开发

npm install     # 安装依赖(含 file: 本地 @tkwf/tsclient)
npm test        # vitest 全量测试
npm run build   # tsc 构建 dist/

开发规则见 Agents_TKWF.md。

License

MIT © LoongBa