关于 emulate-seed
这是一项为 emulate 生成和管理种子配置的技能;emulate 是有状态的 API 仿真工具。它帮助开发者通过服务数据、Webhook 投递和 CI 配置,为支持的服务搭建测试环境。
主要功能
- 01根据依赖发现可用仿真服务
- 02生成测试数据种子 YAML
- 03仿真有状态 API 行为
- 04按服务签名投递 Webhook
- 05配置并行 CI 工作进程与端口
- 06覆盖 OAuth、支付和云服务
适用场景
- 01为集成测试配置带种子的 API 服务
- 02测试 Webhook 处理和签名校验
- 03在并行 CI 中运行服务测试
- 04断言捕获的邮件或结账流程
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ yonatangross/ orchestkit --skill emulate-seed安装后在 Claude Code 中输入/emulate-seed确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
test-cases.jsonreferences/api-coverage.mdcli-reference.mddep-to-emulator-map.jsonork-delta.mdupstream-github.mdupstream-google.mdupstream-vercel.mdupstream.mdrules/_sections.md_template.mdauth-tokens.mdparallel-ci.mdseed-config.mdservice-selection.mdwebhook-setup.mdscripts/auto-discover.sh详细介绍
上游版本参考:emulate 0.12.0(2026-09-30)。
Emulate 种子配置
为 emulate(Apache-2.0)生成并管理种子配置——这是 Vercel Labs 的有状态 API 仿真工具。每个类别都有单独的规则文件,存放在 rules/ 中,并按需加载。
配套 Agent: 此技能与
emulate-engineer子 Agent(subagent_type: "ork:emulate-engineer")配合使用。如果任务涉及从头生成完整的 emulate 配置、设置 webhook HMAC、集成 CI 流水线,或隔离并行工作器端口,请启动该 Agent,而不是在此处直接处理——它的上下文中包含完整的 13 个仿真器服务端口矩阵和种子规则。
不是 Mock。 Emulate 提供完整的状态机,支持级联删除、游标分页、webhook 投递和 HMAC 签名验证。通过 API 创建 PR 后,它会出现在 GET /repos/:owner/:repo/pulls 中。删除仓库时,其 issues、PR 和 webhook 也会级联删除。
2026-04 新增(emulate 0.4.x)
- 模块化的
@emulators/*包——每项服务都是独立的包(@emulators/github、@emulators/stripe等);顶层emulate重新导出createEmulator和 CLI。 - 新增 4 项服务(共 12 项):
mongoatlas:4007、okta:4008、resend:4009、stripe:4010,并提供可直接使用的种子 YAML 配置块。 - Resend 本地收件箱——
GET http://localhost:4009/inbox返回捕获的邮件,方便进行断言,无需访问真实服务提供商。 - Stripe 托管结账——真实的会话重定向流程,以及
checkout.session.completed/expiredwebhook 投递,适用于 E2E 支付测试。 - MongoDB Atlas——Admin API v2(项目/集群/数据库用户)和支持完整 CRUD + 聚合操作的 Data API v1。
- Okta OIDC——完整支持 discovery、JWKS、
authorize/token/userinfo/revoke/introspect,以及 Users/Groups/Apps CRUD。 - Entra / Apple / Slack 扩展(v0.4.0)——PKCE + 刷新轮换(Entra)、RS256 JWKS(Apple)、OAuth v2 授权同意界面(Slack)。
@emulators/adapter-next——全捕获 Next.js 路由处理器可在与应用相同的源上运行仿真器;修复 Vercel 预览部署中的 OAuth 回调 URL 漂移问题。
自动发现(M125 #4)
scripts/auto-discover.sh 会扫描项目的 package.json,将依赖与 references/dep-to-emulator-map.json 进行匹配,然后报告匹配结果或写入 emulate.config.yaml。有三种模式:
| 模式 | 行为 |
|---|---|
| (默认) | 在 stderr 上报告匹配的依赖和仿真器并集;不写入文件 |
--json | 输出机器可读的 JSON,而非人类可读的报告 |
--apply | 写入 emulate.config.yaml(未指定 --force 时拒绝覆盖) |
$ bash "${CLAUDE_SKILL_DIR}/scripts/auto-discover.sh"
emulate-seed --auto — scanning /path/to/package.json
Detected:
@octokit/rest → github · Any GitHub API client
next-auth → google-oauth, apple-auth, microsoft-entra · Default OAuth providers
stripe → stripe
@vercel/blob → aws · @vercel/blob is S3-compatible
Union: apple-auth, aws, github, google-oauth, microsoft-entra, stripe
$ bash "${CLAUDE_SKILL_DIR}/scripts/auto-discover.sh" --apply
…
✓ Wrote /path/to/emulate.config.yaml with 6 service(s)
多仿真器依赖默认选择所有合理的服务提供商;之后用户可从 YAML 中删减。未映射的依赖会被静默跳过——扩展覆盖范围只需提交文档 PR(编辑 references/dep-to-emulator-map.json),无需修改代码。
dev 启动时会读取生成的 emulate.config.yaml——参见 src/skills/dev/scripts/boot.sh。
快速参考
| 类别 | 规则 | 影响 | 使用场景 |
|---|---|---|---|
| 种子配置 | 1 | 高 | 为测试环境配置 emulate.config.yaml |
| 服务选择 | 1 | 中 | 为测试选择 GitHub/Vercel/Google |
| Webhook 设置 | 1 | 中 | 使用 HMAC 验证测试 webhook 投递 |
| 并行 CI | 1 | 高 | 并行运行测试,避免端口冲突 |
| 认证令牌 | 1 | 中 | 为仿真用户预置映射后的令牌 |
共计:5 个类别中的 5 条规则
快速入门
# Install (packages published under @emulators/* scope)
npm install --save-dev emulate
# Start all services
npx emulate
# Start specific services with seed data
npx emulate --service github,stripe --seed ./emulate.config.yaml
# Generate a starter config
npx emulate init --service github
服务(0.10.0 — 14 个模拟器)
各版本新增内容:
- 0.5.0 — 新增 Clerk、MongoDB Atlas、Stripe、Resend 和 Okta 模拟器;支持无端口集成(嵌入式模拟器无需专用端口);支持 Google OAuth
hd声明;新增 Stripe Checkout 和 Resend 魔法链接示例;AWS S3 模拟器现在与官方 SDK 的线路格式一致。- 0.6.0 — 扩展 Slack(OAuth v2 授权同意界面、对话/表情回应)。
- 0.6.1 — Vercel Blob 存储。
- 0.7.0 — 新增 Linear(第 13 个提供方):有状态的组织/团队/问题/周期 + Webhook。
- 0.8.0 — 新增 Twilio(第 14 个提供方):账户、电话号码、消息、通话、对话、消息服务、Verify 流程和模拟器端点,并提供 Next.js 短信验证示例。
- 0.9.0 — 新增 Nuxt 模拟器适配器(与 Next.js 适配器并列);提供方数量不变。
- 0.10.0 — GitHub 仓库内容和提交历史改为有状态(
GET /repos/:owner/:repo/readme、GET/PUT/DELETE /repos/:owner/:repo/contents/:path,写入操作会生成真实提交、GET /repos/:owner/:repo/commits,以及通过数字 ID 调用的GET /repositories/:id);Emulator 对象新增只读generatedSecrets数组,并导出新的GeneratedSecret类型;GitHub App JWT 验证现在同时接受 PKCS#8 和 PKCS#1 密钥。提供方数量不变。所有更改均向后兼容,但有一项行为变更值得注意:0.10.0 将 Stripe Webhook 投递切换为 Stripe 自有的
Stripe-Signature标头格式。上游将此归类为错误修复,而非重大变更,但断言 Stripe 投递中旧版 GitHub 风格sha256=标头的测试现在会失败。两种格式请参阅下文的 Webhook 投递。
| 服务 | 默认端口 | 覆盖范围 |
|---|---|---|
| Vercel | :4000 | 项目、部署、域名、环境变量、团队 |
| GitHub | :4001 | 仓库、PR、问题、评论、审查、Actions、Webhook、组织、团队 |
| Google OAuth | :4002 | OAuth 2.0 授权、令牌交换、用户信息 |
| Slack | :4003 | 聊天、对话、用户、表情回应、带授权同意界面的 OAuth v2 |
| Apple Auth | :4004 | 使用 Apple 登录 — OIDC 发现、JWKS(RS256)、授权流程、令牌交换 |
| Microsoft Entra | :4005 | OAuth 2.0/OIDC v2.0、授权码 + PKCE、刷新令牌轮换、v1 令牌端点、Graph /users/{id} |
| AWS | :4006 | S3 存储桶、SQS 队列、IAM 用户/角色、STS 身份 |
| MongoDB Atlas (0.4+) | :4007 | Admin API v2(项目、集群、数据库用户)+ Data API v1(完整 CRUD + 聚合) |
| Okta (0.4+) | :4008 | OIDC 发现、JWKS、授权/令牌/用户信息/撤销/内省、用户/群组/应用 CRUD |
| Resend (0.4+) | :4009 | 发送 + 批量(每请求 100 条)、列出/检索/取消、域名、API 密钥、受众、联系人、本地收件箱(GET /inbox) |
| Stripe (0.4+) | :4010 | 客户、支付方式、客户会话、支付意图、扣款、产品、价格、带 Webhook 投递的托管结账会话 |
| Clerk (0.5+) | (按需) | 用户、会话、组织 |
| Linear (0.7+) | (按需) | 组织、团队、问题、周期、Webhook |
| Twilio (0.8+) | (按需) | 账户、电话号码、消息、通话、对话、消息服务、Verify 流程、模拟器端点 |
完整端点列表请参阅 references/api-coverage.md。
Next.js 适配器(0.4+)— @emulators/adapter-next
通过全捕获路由处理程序,在与 Next.js 应用相同的源站上运行模拟器。解决 Vercel 预览部署中的 OAuth 回调 URL 漂移问题——不再出现与 http://localhost:4001 不匹配的重定向。
// next.config.js
const { withEmulate } = require('@emulators/adapter-next')
module.exports = withEmulate({ /* your next config */ })
// app/api/[...emulate]/route.ts
import { createEmulateHandler } from '@emulators/adapter-next'
export const { GET, POST } = createEmulateHandler({
services: ['github', 'stripe', 'resend'],
persistence: { /* load(), save() or built-in filePersistence */ },
})
Seed Config 结构
Seed Config 会预先填充令牌、用户、仓库和项目,让测试从已知状态开始。
# emulate.config.yaml
tokens:
dev_token:
login: yonatangross
scopes: [repo, workflow, admin:org]
ci_token:
login: ci-bot
scopes: [repo]
github:
users:
- login: yonatangross
name: Yonatan Gross
- login: ci-bot
name: CI Bot
repos:
- owner: yonatangross
name: my-project
private: false
default_branch: main
topics: [typescript, testing]
vercel:
users:
- username: yonatangross
email: [email protected]
projects:
- name: my-docs
framework: next
# NEW in 0.4.x — drop-in seed blocks
okta:
users:
- login: [email protected]
firstName: Alice
lastName: Smith
groups: [{ name: Everyone }, { name: Admins }]
apps: [{ name: My Web App }]
authorization_servers:
- name: default
audiences: ["api://default"]
resend:
domains: [{ name: example.com }]
api_keys: [{ name: default }]
# In tests: GET http://localhost:4009/inbox to assert captured emails
stripe:
customers:
- name: Test Customer
email: [email protected]
products: [{ name: Pro Plan }, { name: Starter Plan }]
prices:
- { product: Pro Plan, unit_amount: 4900, currency: usd, recurring: { interval: month } }
- { product: Starter Plan, unit_amount: 1900, currency: usd, recurring: { interval: month } }
# Webhook delivery fires on checkout.session.completed / expired
mongoatlas:
projects: [{ name: my-project }]
clusters: [{ project: my-project, name: my-cluster }]
database_users: [{ project: my-project, username: app-user }]
完整架构和最佳实践请参阅 rules/seed-config.md。
程序化 SDK
服务包位于
@emulators/*作用域下(例如@emulators/github、@emulators/stripe)。程序化 API(createEmulator)从顶层emulate包导出。
import { createEmulator } from 'emulate'
const github = await createEmulator({ service: 'github', port: 4001 })
// github.url -> 'http://localhost:4001'
// State is real — create a PR and it appears in the list
const res = await fetch(`${github.url}/repos/org/repo/pulls`, {
method: 'POST',
headers: { Authorization: 'Bearer dev_token' },
body: JSON.stringify({ title: 'Test PR', head: 'feature', base: 'main' })
})
const prs = await fetch(`${github.url}/repos/org/repo/pulls`)
// -> includes the PR we just created
// Auto-generated credentials (0.10.0+): readonly GeneratedSecret[], each
// { service, kind, id, label, value }. A GitHub App emulator, for example,
// generates its own RSA key rather than making you supply one.
github.generatedSecrets
// Cleanup
github.reset() // Synchronous state wipe
await github.close() // Shut down server
此处的 seed 是已解析的对象,而不是路径。只有 CLI 的 --seed 标志才接受文件名。
有关多服务设置、生命周期钩子以及 Vitest/Jest 接线方式,请参阅
references/upstream.md。有关 ork 对该 API 的修正,请参阅
references/ork-delta.md。
Webhook 投递
Emulate 会在状态发生变化时,使用 HMAC-SHA256 签名投递真实 webhook。 签名格式因提供方而异,因此一种通用验证器无法覆盖所有服务。 GitHub 格式的标头仍为默认格式;Stripe 自 0.10.0 起使用自有格式。
import crypto from 'crypto'
// GitHub format (the default for most services): sha256=<hmac over the raw body>
function verifyWebhook(payload: string, signature: string, secret: string): boolean {
const expected = 'sha256=' + crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex')
return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected))
}
// Stripe format, as of emulate 0.10.0: Stripe-Signature: t=<timestamp>,v1=<hmac>,
// where the HMAC covers `<timestamp>.<raw body>`, NOT the body alone. Verifying a
// Stripe delivery with the GitHub helper above fails on both counts.
function verifyStripeWebhook(rawBody: string, header: string, secret: string): boolean {
const parts = Object.fromEntries(header.split(',').map((kv) => kv.split('=')))
const expected = crypto
.createHmac('sha256', secret)
.update(`${parts.t}.${rawBody}`)
.digest('hex')
return crypto.timingSafeEqual(Buffer.from(parts.v1), Buffer.from(expected))
}
Webhook 接收器模式请参阅 rules/webhook-setup.md。
CI 集成
# .github/workflows/test.yml
jobs:
test:
steps:
- uses: actions/checkout@v4
- name: Start emulate
run: npx emulate --service github --seed .emulate/ci.yaml &
- name: Wait for emulate
run: sleep 2
- name: Run tests
run: npm test
env:
GITHUB_API_BASE: http://localhost:4001
VERCEL_API_BASE: http://localhost:4000
并行测试执行
每个测试工作进程都会获得独立端口,以避免竞态条件:
// vitest.config.ts
const workerPort = 4001 + parseInt(process.env.VITEST_WORKER_ID || '0')
完整的并行隔离模式请参阅 rules/parallel-ci.md。
决策矩阵
| 工具 | 适用场景 | 有状态? | 平台 |
|---|---|---|---|
| emulate(首选) | GitHub/Vercel/Google/Slack/Apple/Entra/AWS/Okta/Resend/Stripe/MongoDB/Clerk/Linear 测试 | 是 | 全部 13 项服务 |
| Pact | 服务间的契约验证 | 否 | 任意 |
| MSW | 浏览器内/Node HTTP 模拟 | 否 | 任意 |
| Nock | Node.js HTTP 拦截 | 否 | 任意 |
| WireMock | HTTP 模拟服务 | 部分 | 任意 |
在以下情况下使用 emulate:
- 测试调用 GitHub、Vercel、Google、Slack、Apple、Entra、AWS、Okta、Resend、Stripe、MongoDB Atlas、Clerk 或 Linear 的代码
- 需要在一次测试中的多个 API 调用之间持久化状态
- 希望投递带有真实 HMAC 签名的 webhook(GitHub、Stripe)
- 需要断言级联副作用(删除仓库 -> PR 随之级联删除)
- 需要在不访问真实提供方的情况下断言已发送的邮件(Resend 本地
/inbox) - 需要在测试中使用托管的 Stripe 结账会话和真实重定向流程
在以下情况下使用 MSW/Nock:
- 模拟 emulate 未覆盖的任意 HTTP API
- 需要在浏览器内拦截(MSW)
- 测试只需要单个请求/响应对
上游内容覆盖范围(不要重复说明)
此技能是一个封装层,加上我们自己的增量内容。emulate 为每项服务提供了自己的参考文档;把这些文档复制到这里,只会导致内容在下次发布时过时。如果涉及以下主题,请阅读一手资料,而非转述内容。
| 主题 | 一手资料 |
|---|---|
程序化 API(createEmulator、url、reset()、close())、Vitest/Jest 接线、配置自动检测顺序、令牌回退 | references/upstream.md(从 vercel-labs/emulate、skills/emulate/SKILL.md 同步) |
| GitHub 端点示例、GitHub App JWT 预置、Octokit 和 Auth.js 基础 URL 接线、GitHub OAuth 流程 | https://github.com/vercel-labs/emulate/blob/main/skills/github/SKILL.md |
Google OIDC 发现、JWKS、authorize/token/userinfo/revoke、PKCE、google-auth-library、Passport、openid-client | https://github.com/vercel-labs/emulate/blob/main/skills/google/SKILL.md |
| Vercel 端点示例、游标分页、团队范围限定、集成 OAuth 流程 | https://github.com/vercel-labs/emulate/blob/main/skills/vercel/SKILL.md |
| 所有其他模拟器(Slack、Apple、Entra、AWS、Okta、Resend、Stripe、MongoDB Atlas、Clerk、Linear、Twilio) | https://github.com/vercel-labs/emulate/tree/main/skills |
我们保留的内容: references/ork-delta.md(任何供应商文档中都没有的修正和内部约定)、references/cli-reference.md、references/api-coverage.md、references/dep-to-emulator-map.json、scripts/auto-discover.sh,以及 rules/ 中的所有内容。
从供应商文档复制任何代码片段前,请先阅读 references/ork-delta.md。其中记录了供应商文档未明确说明的两个 API 事实(导出的工厂函数是 createEmulator,程序化选项中的 seed 是对象而非路径),以及本仓库使用的 *_API_BASE 环境变量约定,该约定不同于供应商的 *_EMULATOR_URL。
相关技能
testing-integration— 集成测试模式(API 测试优先使用 emulate)testing-e2e— 使用模拟后端的端到端测试模式testing-unit— 单元测试模式(依赖 API 的单元测试使用 emulate)security-patterns— 身份验证令牌模式(使用 emulate 预置令牌)
CLI 参考
所有 CLI 标志和命令请参阅 references/cli-reference.md。