emulate について
emulate は、CI やネットワークのないサンドボックス向けに、複数の API をローカルで状態付きエミュレートします。CLI またはプログラム API から起動でき、シードデータでテスト環境を構成できます。
主な機能
- 01複数のローカル API エミュレーターを起動
- 02CLI でサービスを選択・設定
- 03プログラム API で個別サービスを作成
- 04シードデータから状態を初期化
- 05ファイルまたはカスタム永続化アダプターを使用
- 06カスタムエミュレーターをひな形から作成
活用シーン
- 01CI で外部 API に依存するアプリをテスト
- 02ネットワークなしで統合テストを実行
- 03OAuth と API テスト用のローカルデータを準備
- 04サードパーティ API エミュレーターを開発・テスト
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ vercel-labs/ emulate --skill emulateインストール後、Claude Code で/emulateを入力して読み込まれたか確認します。
詳細
emulate によるサービスエミュレーション
CI やネットワークに接続できないサンドボックスで利用できる、ローカル環境向けのドロップイン置換サービスです。モックではなく、本番環境に忠実な、完全な状態管理に対応する API エミュレーションです。
クイックスタート
npx emulate
すべてのサービスは、デフォルトで IPv4 ループバック(127.0.0.1)でリッスンします。
| サービス | デフォルトポート |
|---|---|
| Vercel | 4000 |
| GitHub | 4001 |
| 4002 | |
| Slack | 4003 |
| Apple | 4004 |
| Microsoft | 4005 |
| Okta | 4006 |
| AWS | 4007 |
| Resend | 4008 |
| Stripe | 4009 |
| MongoDB Atlas | 4010 |
| Clerk | 4011 |
| Linear | 4012 |
| Twilio | 4013 |
CLI
# Start all services (zero-config)
npx emulate
# Start specific services
npx emulate --service vercel,github
# Custom base port (auto-increments per service)
npx emulate --port 3000
# Use a seed config file
npx emulate --seed config.yaml
# Generate omitted service secrets into a private file
npx emulate start --seed config.yaml --generated-secrets-file .emulate-secrets.json
# Generate a starter config
npx emulate init
# Generate config for a specific service
npx emulate init --service vercel
# List available services
npx emulate list
オプション
| フラグ | デフォルト | 説明 |
|---|---|---|
-p, --port | 4000 | ベースポート(サービスごとに自動でインクリメントされます) |
--host | 127.0.0.1 | リッスンアドレス。ネットワークアクセスを許可するには 0.0.0.0 を指定します |
-s, --service | all | 有効にするサービスをカンマ区切りで指定します |
--seed | auto-detect | シード設定ファイルのパス(YAML または JSON) |
--base-url | none | 公開するベース URL を上書きします({service} テンプレートに対応) |
--portless | off | portless 経由で HTTPS を提供します(エイリアスを自動登録します) |
--generated-secrets-file | none | 省略されたサービスシークレットを生成し、新しい所有者のみがアクセスできる JSON ファイルに書き込みます |
ポートは、環境変数 EMULATE_PORT または PORT でも設定できます。
コンテナーや別のマシンからアクセスするには、npx emulate start --host 0.0.0.0 を使用します。OAuth リダイレクトやその他の公開 URL を使用する場合は、クライアントから到達できる URL を --base-url に設定してください。
生成されるシークレットの保存先は、存在していてはなりません。emulate は継承された ACL を削除し、実効アクセス権が所有者のみに制限されていることを検証したうえで、リスナーの起動や portless の設定を行う前に完全な JSON を書き込みます。処理済みの起動エラーが発生した場合は、その実行で作成されたファイルを削除します。強制終了した場合は完全なファイルが残ることがあります。その場合は、いずれの実行も使用していないことを確認してから手動で削除してください。ファイルにはサービスによって生成された値のみが含まれます。Linux では、acl パッケージの setfacl と getfacl が必要です。アクセス制御を検証できない場合、このフラグは安全のため処理を中止し、Windows ではサポートされていません。
公開ベース URL(OAuth リダイレクト、Webhook URL などで使用)は、--base-url、環境変数 EMULATE_BASE_URL({service} テンプレートに対応)、またはシード設定内のサービスごとの baseUrl で上書きできます。portless の実行時には、環境変数 PORTLESS_URL も自動的に検出されます。
プログラムからの API 利用
npm install emulate
createEmulator を呼び出すたびに、単一のサービスが起動します。
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()
GitHub App のテストでは、GET /_emulate/installation-tokens で、シークレットを含まない発行済みインストールトークンのメタデータを確認できます。
オプション
| オプション | デフォルト | 説明 |
|---|---|---|
service | (必須) | 'vercel'、'github'、'google'、'slack'、'apple'、'microsoft'、'okta'、'aws'、'resend'、'stripe'、'mongoatlas'、'clerk'、'linear'、または 'twilio' |
port | 4000 | HTTP サーバーのポート |
hostname | 127.0.0.1 | 組み込みエミュレーターおよびカスタムエミュレーターのリッスンアドレス |
seed | none | インラインのシードデータ(YAML 設定と同じ形式) |
baseUrl | none | 公開ベース URL を上書きします。優先順位は、シード設定内のサービスごとの baseUrl、このオプション、環境変数 EMULATE_BASE_URL({service} に対応)、PORTLESS_URL({service} に対応し、portless CLI ラッパーによって自動設定)、http://localhost:<port> の順です。 |
コンテナーや別のマシンからの接続を許可するには hostname: '0.0.0.0' を使用し、それらのクライアントに公開する URL を指定するには baseUrl を使用します。
インスタンスメソッド
| メソッド | 説明 |
|---|---|
url | 実行中サーバーのベース URL |
reset() | ストアを消去し、シードデータを再適用します |
close() | HTTP サーバーを停止し、Promise を返します |
Vitest / Jest の設定
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()]))
設定
設定は任意です。CLI は次の順序で設定ファイルを自動検出します。
emulate.config.yaml/.ymlemulate.config.jsonservice-emulator.config.yaml/.ymlservice-emulator.config.json
または、--seed <file> を明示的に渡してください。npx emulate init を実行すると、ひな形ファイルが生成されます。
設定の構造
tokens:
my_token:
login: admin
scopes: [repo, user]
vercel:
users:
- username: developer
name: Developer
email: [email protected]
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: [email protected]
orgs:
- login: my-org
name: My Organization
members:
- login: octocat
role: admin
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: [email protected]
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: [email protected]
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
signing_secret: my_signing_secret
linear:
organization:
name: Acme
url_key: acme
users:
- email: [email protected]
name: Admin User
admin: true
- email: [email protected]
name: Developer
teams:
- key: ENG
name: Engineering
states:
- name: Backlog
type: backlog
- name: Todo
type: unstarted
- name: In Progress
type: started
- name: Done
type: completed
labels:
- name: Bug
color: "#d92d20"
team: ENG
- name: Feature
color: "#2563eb"
team: ENG
issues:
- team: ENG
title: Fix local checkout test
description: Reproduce and fix the checkout failure.
state: Todo
assignee: [email protected]
labels: [Bug]
oauth_apps:
- client_id: lin_example_client_id
client_secret: example_client_secret
name: My Linear App
redirect_uris:
- http://localhost:3000/api/auth/callback/linear
scopes: [read, write, issues:create, comments:create]
actor: user
tokens:
- token: lin_test_admin
user: [email protected]
scopes: [read, write, issues:create, comments:create, admin]
strict_scopes: false
apple:
users:
- email: [email protected]
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: [email protected]
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-role
description: Role for Lambda function execution
okta:
users:
- login: [email protected]
email: [email protected]
first_name: Test
last_name: User
groups:
- name: Everyone
description: All users
type: BUILT_IN
okta_id: 00g_everyone
authorization_servers:
- id: default
name: default
audiences: [api://default]
oauth_clients:
- client_id: okta-test-client
client_secret: okta-test-secret
name: Sample OIDC Client
redirect_uris:
- http://localhost:3000/callback
auth_server_id: default
resend:
domains:
- name: example.com
region: us-east-1
contacts:
- email: [email protected]
first_name: Test
last_name: User
stripe:
customers:
- email: [email protected]
name: Test Customer
products:
- name: Pro Plan
description: Monthly pro subscription
prices:
- product_name: Pro Plan
currency: usd
unit_amount: 2000
mongoatlas:
projects:
- name: Project0
clusters:
- name: Cluster0
project: Project0
database_users:
- username: admin
project: Project0
databases:
- cluster: Cluster0
name: test
collections: [items]
clerk:
users:
- first_name: Test
last_name: User
email_addresses: [[email protected]]
password: clerk_test_password
organizations:
- name: My Company
slug: my-company
members:
- email: [email protected]
role: admin
oauth_applications:
- client_id: clerk_emulate_client
client_secret: clerk_emulate_secret
name: Emulate App
redirect_uris:
- http://localhost:3000/api/auth/callback/clerk
twilio:
account:
sid: AC00000000000000000000000000000000
auth_token: twilio_test_auth_token
friendly_name: Local Twilio Account
api_keys:
- sid: SK00000000000000000000000000000000
secret: twilio_test_api_secret
friendly_name: Local API Key
phone_numbers:
- phone_number: "+15551234567"
friendly_name: Local SMS and Voice Number
sms_url: http://localhost:3000/api/twilio/sms
voice_url: http://localhost:3000/api/twilio/voice
messaging_services:
- friendly_name: Local Messaging Service
phone_numbers: ["+15551234567"]
verify_services:
- friendly_name: Local Verify Service
code: "123456"
default_channel: sms
conversations:
services:
- friendly_name: Local Conversations
slack.signing_secret は、すべての送信イベントサブスクリプションコールバックに署名します。署名付きコールバックには X-Slack-Request-Timestamp と X-Slack-Signature が含まれ、正確にシリアライズされたコールバック本文に対して v0=<HMAC-SHA256(secret, "v0:<timestamp>:<raw-body>")> として計算されます。受信側には同じシークレットを設定し、解析前のリクエスト本文を検証してください。シークレットが未設定または空の場合、コールバックには署名が付与されません。
GitHub App の private_key の値は、意図的にひな形の設定から省略されています。プログラムから createEmulator を呼び出すと、RSA キーが生成され、generatedSecrets を通じて公開されます。CLI の起動時に省略されたキーが生成されるのは、--generated-secrets-file <path> が指定されている場合のみです。それ以外の場合、シードには有効な秘密鍵を明示的に含める必要があります。プレースホルダーの PEM 値は決して使用しないでください。
GitHub 組織の members は任意です。エントリでは、login によってシード済みユーザーを参照します。role の既定値は member で、admin を指定すると組織の管理者になります。不明なユーザーは無視されます。
認証
トークンはユーザーに対応付けられます。Authorization: Bearer <token> または Authorization: token <token> として渡してください。トークンが設定されていない場合は、admin ユーザー用に既定の test_token_admin が作成されます。
各サービスにはフォールバックユーザーもあります。トークンが指定されていない場合、リクエストは最初にシードされたユーザーとして認証されます。
portless を使った HTTPS
portless を使うと、自動生成された証明書を用いて、エミュレーターに信頼済みの HTTPS URL を割り当てられます。--portless フラグを使用すると、各サービスが portless エイリアスとして自動登録されます。
npx emulate start --portless
# github https://github.emulate.localhost
# google https://google.emulate.localhost
# ...
これには portless プロキシが起動している必要があります(portless proxy start)。portless がインストールされていない場合、emulate からインストールを促されます。
--portless フラグを指定すると、*.emulate に一致する既存の portless エイリアスは上書きされます。エイリアスは emulate の終了時に自動的に削除されます。
portless の背後で単一のサービスを実行する場合:
portless github.emulate emulate start --service github
portless を使わずにカスタムのベース URL を設定する場合(任意のリバースプロキシ):
npx emulate start --base-url "https://{service}.myproxy.test"
# or
EMULATE_BASE_URL="https://{service}.myproxy.test" npx emulate start
portless CLI ラッパーを通じてコマンドを実行すると(例:portless github.emulate emulate start)、PORTLESS_URL 環境変数が自動的に設定されます。通常、値は https://{service}.emulate.localhost のようになります。--base-url および EMULATE_BASE_URL と同様に、{service} の埋め込みに対応しています。明示的な baseUrl が指定されていない場合、フォールバックとして使用されます。
シード設定でのサービスごとのオーバーライド(ほかのすべてのベース URL の指定元よりも優先されます):
github:
baseUrl: https://github.emulate.localhost
google:
baseUrl: https://google.emulate.localhost
アプリからエミュレーターを参照する
環境変数を設定して、実際のサービス URL を上書きします。
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:4007
LINEAR_EMULATOR_URL=http://localhost:4012
これらをアプリで使用して、API URL と OAuth URL を構築してください。SDK 固有のオーバーライド手順については、各サービスのスキルを参照してください。
フレームワークとの統合(埋め込みモード)
@emulators/adapter-next パッケージを使うと、同じオリジン上でエミュレーターを Next.js アプリに直接埋め込めます。詳しい設定、Auth.js の構成、永続化、フォントのトレースについては、next スキル(skills/next/SKILL.md)を参照してください。
@emulators/adapter-nuxt パッケージを使うと、同じオリジン上でエミュレーターを Nuxt アプリに直接埋め込めます。サーバールート、Nuxt の設定、OAuth の設定、永続化の設定については、nuxt スキル(skills/nuxt/SKILL.md)を参照してください。
永続化
既定では、すべてのエミュレーター状態はメモリ内に保存されます。プロセスの再起動やサーバーレスのコールドスタートをまたいで状態を永続化するには、PersistenceAdapter を使用してください。
組み込みのファイル永続化
import { filePersistence } from '@emulators/core'
// CLI or local dev: persists to a JSON file
const adapter = filePersistence('.emulate/state.json')
カスタムアダプター
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)のたびに保存されます。保存は競合状態を防ぐために直列化されます。生成された GitHub App アイデンティティでは、initialize が初期値をアトミックに作成するか、別のインスタンスが先に作成した値を返す必要があります。
アーキテクチャ
packages/
emulate/ # CLI entry point + programmatic API
@emulators/
core/ # HTTP server, Store, plugin interface, middleware
adapter-next/ # Next.js App Router integration
adapter-nuxt/ # Nuxt server route 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
linear/ # Linear GraphQL API, OAuth, webhooks plugin
twilio/ # Twilio Messaging, Verify, Voice, webhooks plugin
apple/ # Sign in with Apple / OIDC plugin
microsoft/ # Microsoft Entra ID OAuth 2.0 / OIDC plugin
aws/ # AWS S3, SQS, IAM, STS plugin
コアは、CRUD、インデックス作成、フィルタリング、ページネーションをサポートする型付き Collection<T> インスタンスを備えた汎用の Store を提供します。各サービスプラグインは、共有の内部アプリにルートを登録し、状態のためにストアを使用します。
ビルトインと併用するカスタムエミュレーター
npx emulate init --custom inventory を使用して、サードパーティ API エミュレーターをスキャフォールドし、テストします。このコマンドは、検出された YAML、JSON、TypeScript、または JavaScript の設定にそれを登録します。既存のサービスを含む設定も対象です。通常とは異なる実行可能な設定については、手動での登録手順が表示されます。npx emulate start --watch を実行してインポートを再読み込みします。ポートは設定に依存するため、リクエストには起動バナーに表示されるサービス URL と Inspector リンクを使用してください。設定ディレクトリ外に存在しないローカルインポートを作成すると、失敗した再読み込みも再試行されます。再読み込みに成功すると、実行はシードにリセットされます。既存のフラットなシード設定も引き続き機能します。--config は明示的なファイルを選択します。Node 26 は消去可能な TypeScript をロードします。enum とパラメータープロパティは先に JavaScript へコンパイルしてください。Node 24 もネイティブの TypeScript トランスフォームをサポートしています。サードパーティ API エミュレーターの作成とテストについては、https://emulate.dev/docs/custom-emulators を参照してください。