emulate
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseService Emulation with emulate
使用emulate进行服务模拟
Local drop-in replacement services for CI and no-network sandboxes. Fully stateful, production-fidelity API emulation, not mocks.
适用于CI环境和无网络沙箱的本地可直接替代服务。具备完整状态、与生产环境一致的API模拟,而非简单Mock。
Quick Start
快速开始
bash
npx emulateAll services start with sensible defaults:
| Service | Default Port |
|---|---|
| Vercel | 4000 |
| GitHub | 4001 |
| 4002 | |
| Slack | 4003 |
| Apple | 4004 |
| Microsoft | 4005 |
| AWS | 4006 |
bash
npx emulate所有服务均以合理默认配置启动:
| Service | 默认端口 |
|---|---|
| Vercel | 4000 |
| GitHub | 4001 |
| 4002 | |
| Slack | 4003 |
| Apple | 4004 |
| Microsoft | 4005 |
| AWS | 4006 |
CLI
CLI 命令
bash
undefinedbash
undefinedStart all services (zero-config)
启动所有服务(零配置)
emulate
emulate
Start specific services
启动指定服务
emulate --service vercel,github
emulate --service vercel,github
Custom base port (auto-increments per service)
自定义基础端口(每个服务自动递增)
emulate --port 3000
emulate --port 3000
Use a seed config file
使用种子配置文件
emulate --seed config.yaml
emulate --seed config.yaml
Generate a starter config
生成初始配置
emulate init
emulate init
Generate config for a specific service
生成指定服务的配置
emulate init --service vercel
emulate init --service vercel
List available services
列出可用服务
emulate list
undefinedemulate list
undefinedOptions
选项说明
| Flag | Default | Description |
|---|---|---|
| | Base port (auto-increments per service) |
| all | Comma-separated services to enable |
| auto-detect | Path to seed config (YAML or JSON) |
The port can also be set via or environment variables.
EMULATE_PORTPORT| 标识 | 默认值 | 描述 |
|---|---|---|
| | 基础端口(每个服务自动递增) |
| 全部 | 启用的服务列表,以逗号分隔 |
| 自动检测 | 种子配置文件路径(YAML或JSON格式) |
端口也可通过环境变量 或 设置。
EMULATE_PORTPORTProgrammatic API
编程式API
bash
npm install emulateEach call to starts a single service:
createEmulatortypescript
import { createEmulator } from 'emulate'
const github = await createEmulator({ service: 'github', port: 4001 })
const vercel = await createEmulator({ service: 'vercel', port: 4002 })
github.url // 'http://localhost:4001'
vercel.url // 'http://localhost:4002'
await github.close()
await vercel.close()bash
npm install emulate每次调用 会启动单个服务:
createEmulatortypescript
import { createEmulator } from 'emulate'
const github = await createEmulator({ service: 'github', port: 4001 })
const vercel = await createEmulator({ service: 'vercel', port: 4002 })
github.url // 'http://localhost:4001'
vercel.url // 'http://localhost:4002'
await github.close()
await vercel.close()Options
选项说明
| Option | Default | Description |
|---|---|---|
| (required) | |
| | Port for the HTTP server |
| none | Inline seed data (same shape as YAML config) |
| 选项 | 默认值 | 描述 |
|---|---|---|
| 必填 | |
| | HTTP服务器端口 |
| 无 | 内联种子数据(与YAML配置结构一致) |
Instance Methods
实例方法
| Method | Description |
|---|---|
| Base URL of the running server |
| Wipe the store and replay seed data |
| Shut down the HTTP server, returns a Promise |
| 方法 | 描述 |
|---|---|
| 运行中服务器的基础URL |
| 清空存储并重新加载种子数据 |
| 关闭HTTP服务器,返回Promise |
Vitest / Jest Setup
Vitest / Jest 配置
typescript
import { createEmulator, type Emulator } from 'emulate'
let github: Emulator
let vercel: Emulator
beforeAll(async () => {
;[github, vercel] = await Promise.all([
createEmulator({ service: 'github', port: 4001 }),
createEmulator({ service: 'vercel', port: 4002 }),
])
process.env.GITHUB_EMULATOR_URL = github.url
process.env.VERCEL_EMULATOR_URL = vercel.url
})
afterEach(() => { github.reset(); vercel.reset() })
afterAll(() => Promise.all([github.close(), vercel.close()]))typescript
import { createEmulator, type Emulator } from 'emulate'
let github: Emulator
let vercel: Emulator
beforeAll(async () => {
;[github, vercel] = await Promise.all([
createEmulator({ service: 'github', port: 4001 }),
createEmulator({ service: 'vercel', port: 4002 }),
])
process.env.GITHUB_EMULATOR_URL = github.url
process.env.VERCEL_EMULATOR_URL = vercel.url
})
afterEach(() => { github.reset(); vercel.reset() })
afterAll(() => Promise.all([github.close(), vercel.close()]))Configuration
配置说明
Configuration is optional. The CLI auto-detects config files in this order:
- /
emulate.config.yaml.yml emulate.config.json- /
service-emulator.config.yaml.yml service-emulator.config.json
Or pass explicitly. Run to generate a starter file.
--seed <file>emulate init配置为可选操作。CLI会按以下顺序自动检测配置文件:
- /
emulate.config.yaml.yml emulate.config.json- /
service-emulator.config.yaml.yml service-emulator.config.json
也可通过 显式指定配置文件。运行 可生成初始配置文件。
--seed <file>emulate initConfig Structure
配置结构
yaml
tokens:
my_token:
login: admin
scopes: [repo, user]
vercel:
users:
- username: developer
name: Developer
email: dev@example.com
teams:
- slug: my-team
name: My Team
projects:
- name: my-app
team: my-team
framework: nextjs
integrations:
- client_id: oac_abc123
client_secret: secret_abc123
name: My Vercel App
redirect_uris:
- http://localhost:3000/api/auth/callback/vercel
github:
users:
- login: octocat
name: The Octocat
email: octocat@github.com
orgs:
- login: my-org
name: My Organization
repos:
- owner: octocat
name: hello-world
language: JavaScript
auto_init: true
oauth_apps:
- client_id: Iv1.abc123
client_secret: secret_abc123
name: My Web App
redirect_uris:
- http://localhost:3000/api/auth/callback/github
google:
users:
- email: testuser@example.com
name: Test User
oauth_clients:
- client_id: my-client-id.apps.googleusercontent.com
client_secret: GOCSPX-secret
redirect_uris:
- http://localhost:3000/api/auth/callback/google
slack:
team:
name: My Workspace
domain: my-workspace
users:
- name: developer
real_name: Developer
email: dev@example.com
channels:
- name: general
topic: General discussion
bots:
- name: my-bot
oauth_apps:
- client_id: "12345.67890"
client_secret: example_client_secret
name: My Slack App
redirect_uris:
- http://localhost:3000/api/auth/callback/slack
apple:
users:
- email: testuser@icloud.com
name: Test User
oauth_clients:
- client_id: com.example.app
team_id: TEAM001
name: My Apple App
redirect_uris:
- http://localhost:3000/api/auth/callback/apple
microsoft:
users:
- email: testuser@outlook.com
name: Test User
oauth_clients:
- client_id: example-client-id
client_secret: example-client-secret
name: My Microsoft App
redirect_uris:
- http://localhost:3000/api/auth/callback/microsoft-entra-id
aws:
region: us-east-1
s3:
buckets:
- name: my-app-bucket
sqs:
queues:
- name: my-app-events
iam:
users:
- user_name: developer
create_access_key: true
roles:
- role_name: lambda-execution-roleyaml
tokens:
my_token:
login: admin
scopes: [repo, user]
vercel:
users:
- username: developer
name: Developer
email: dev@example.com
teams:
- slug: my-team
name: My Team
projects:
- name: my-app
team: my-team
framework: nextjs
integrations:
- client_id: oac_abc123
client_secret: secret_abc123
name: My Vercel App
redirect_uris:
- http://localhost:3000/api/auth/callback/vercel
github:
users:
- login: octocat
name: The Octocat
email: octocat@github.com
orgs:
- login: my-org
name: My Organization
repos:
- owner: octocat
name: hello-world
language: JavaScript
auto_init: true
oauth_apps:
- client_id: Iv1.abc123
client_secret: secret_abc123
name: My Web App
redirect_uris:
- http://localhost:3000/api/auth/callback/github
google:
users:
- email: testuser@example.com
name: Test User
oauth_clients:
- client_id: my-client-id.apps.googleusercontent.com
client_secret: GOCSPX-secret
redirect_uris:
- http://localhost:3000/api/auth/callback/google
slack:
team:
name: My Workspace
domain: my-workspace
users:
- name: developer
real_name: Developer
email: dev@example.com
channels:
- name: general
topic: General discussion
bots:
- name: my-bot
oauth_apps:
- client_id: "12345.67890"
client_secret: example_client_secret
name: My Slack App
redirect_uris:
- http://localhost:3000/api/auth/callback/slack
apple:
users:
- email: testuser@icloud.com
name: Test User
oauth_clients:
- client_id: com.example.app
team_id: TEAM001
name: My Apple App
redirect_uris:
- http://localhost:3000/api/auth/callback/apple
microsoft:
users:
- email: testuser@outlook.com
name: Test User
oauth_clients:
- client_id: example-client-id
client_secret: example-client-secret
name: My Microsoft App
redirect_uris:
- http://localhost:3000/api/auth/callback/microsoft-entra-id
aws:
region: us-east-1
s3:
buckets:
- name: my-app-bucket
sqs:
queues:
- name: my-app-events
iam:
users:
- user_name: developer
create_access_key: true
roles:
- role_name: lambda-execution-roleAuth
认证机制
Tokens map to users. Pass them as or . When no tokens are configured, a default is created for the user.
Authorization: Bearer <token>Authorization: token <token>test_token_adminadminEach service also has a fallback user. If no token is provided, requests authenticate as the first seeded user.
令牌与用户绑定。可通过 或 传递。未配置令牌时,系统会为 用户创建默认令牌 。
Authorization: Bearer <token>Authorization: token <token>admintest_token_admin每个服务还包含一个备用用户。若未提供令牌,请求会自动认证为第一个种子用户。
Pointing Your App at the Emulator
将应用指向模拟器
Set environment variables to override real service URLs:
bash
VERCEL_EMULATOR_URL=http://localhost:4000
GITHUB_EMULATOR_URL=http://localhost:4001
GOOGLE_EMULATOR_URL=http://localhost:4002
SLACK_EMULATOR_URL=http://localhost:4003
APPLE_EMULATOR_URL=http://localhost:4004
MICROSOFT_EMULATOR_URL=http://localhost:4005
AWS_EMULATOR_URL=http://localhost:4006Then use these in your app to construct API and OAuth URLs. See each service's skill for SDK-specific override instructions.
设置环境变量以覆盖真实服务URL:
bash
VERCEL_EMULATOR_URL=http://localhost:4000
GITHUB_EMULATOR_URL=http://localhost:4001
GOOGLE_EMULATOR_URL=http://localhost:4002
SLACK_EMULATOR_URL=http://localhost:4003
APPLE_EMULATOR_URL=http://localhost:4004
MICROSOFT_EMULATOR_URL=http://localhost:4005
AWS_EMULATOR_URL=http://localhost:4006随后在应用中使用这些变量构建API和OAuth URL。具体SDK的覆盖方式可参考各服务对应的技能文档。
Next.js Integration (Embedded Mode)
Next.js 集成(嵌入模式)
The package embeds emulators directly into a Next.js app on the same origin. See the next skill () for full setup, Auth.js configuration, persistence, and font tracing details.
@emulators/adapter-nextskills/next/SKILL.md@emulators/adapter-nextskills/next/SKILL.mdPersistence
持久化
By default, all emulator state is in-memory. For persistence across process restarts and serverless cold starts, use a .
PersistenceAdapter默认情况下,所有模拟器状态均存储在内存中。若需跨进程重启或无服务器冷启动保留状态,可使用 。
PersistenceAdapterBuilt-in file persistence
内置文件持久化
typescript
import { filePersistence } from '@emulators/core'
// CLI or local dev: persists to a JSON file
const adapter = filePersistence('.emulate/state.json')typescript
import { filePersistence } from '@emulators/core'
// CLI或本地开发:持久化至JSON文件
const adapter = filePersistence('.emulate/state.json')Custom adapters
自定义适配器
typescript
import type { PersistenceAdapter } from '@emulators/core'
const kvAdapter: PersistenceAdapter = {
async load() { return await kv.get('emulate-state') },
async save(data) { await kv.set('emulate-state', data) },
}State is loaded on cold start and saved after every mutating request (POST, PUT, PATCH, DELETE). Saves are serialized to prevent race conditions.
typescript
import type { PersistenceAdapter } from '@emulators/core'
const kvAdapter: PersistenceAdapter = {
async load() { return await kv.get('emulate-state') },
async save(data) { await kv.set('emulate-state', data) },
}状态会在冷启动时加载,并在每次变更请求(POST、PUT、PATCH、DELETE)后保存。保存操作会序列化执行,以避免竞争条件。
Architecture
架构
packages/
emulate/ # CLI entry point + programmatic API
@emulators/
core/ # HTTP server (Hono), Store, plugin interface, middleware
adapter-next/ # Next.js App Router integration
vercel/ # Vercel API service plugin
github/ # GitHub API service plugin
google/ # Google OAuth 2.0 / OIDC plugin
slack/ # Slack Web API, OAuth, incoming webhooks plugin
apple/ # Sign in with Apple / OIDC plugin
microsoft/ # Microsoft Entra ID OAuth 2.0 / OIDC plugin
aws/ # AWS S3, SQS, IAM, STS pluginThe core provides a generic with typed instances supporting CRUD, indexing, filtering, and pagination. Each service plugin registers routes on the shared Hono app and uses the store for state.
StoreCollection<T>packages/
emulate/ # CLI入口 + 编程式API
@emulators/
core/ # HTTP服务器(Hono)、存储、插件接口、中间件
adapter-next/ # Next.js App Router集成
vercel/ # Vercel API服务插件
github/ # GitHub API服务插件
google/ # Google OAuth 2.0 / OIDC插件
slack/ # Slack Web API、OAuth、入站Webhook插件
apple/ # Apple登录 / OIDC插件
microsoft/ # Microsoft Entra ID OAuth 2.0 / OIDC插件
aws/ # AWS S3、SQS、IAM、STS插件核心模块提供通用 ,包含支持CRUD、索引、筛选和分页的类型化 实例。每个服务插件会在共享Hono应用上注册路由,并使用存储模块管理状态。
StoreCollection<T>