emulate

GitHub

提供16种服务的生产级仿真器,支持真实SDK测试、OAuth流程及OpenAPI规范对接。

.claude/skills/emulate/SKILL.md UsefulSoftwareCo/executor

触发场景

需要模拟GitHub、Stripe等第三方API进行测试 验证OAuth或OIDC身份认证流程 生成OpenAPI规范供集成使用 断言请求是否成功发送

安装

npx skills add UsefulSoftwareCo/executor --skill emulate -g -y
更多选项

非标准路径

npx skills add https://github.com/UsefulSoftwareCo/executor/tree/main/.claude/skills/emulate -g -y

不安装直接使用

npx skills use UsefulSoftwareCo/executor@emulate

指定 Agent (Claude Code)

npx skills add UsefulSoftwareCo/executor --skill emulate -a claude-code -g -y

安装 repo 全部 skill

npx skills add UsefulSoftwareCo/executor --all -g -y

预览 repo 内 skill

npx skills add UsefulSoftwareCo/executor --list

SKILL.md

Frontmatter
{
    "name": "emulate",
    "description": "Use the @executor-js\/emulate service emulators (GitHub, Google, Stripe, Resend, WorkOS, …) to test integrations for real — full OpenAPI specs, working OAuth flows, mintable credentials, and a request ledger for assertions. Use when a test or demo needs a real-shaped upstream API, an OAuth\/OIDC provider, a spec to feed addSpec, or proof that a request actually landed."
}

Emulate: production-fidelity service emulators

@executor-js/emulate (our fork of Vercel Labs' emulate) provides stateful, wire-level emulators for 16 services: github vercel google okta microsoft spotify slack apple aws resend stripe mongoatlas clerk x workos autumn. These are not mocks: real SDKs and real product code run against them unmodified — the cloud e2e target points the actual WorkOS SDK (sealed sessions, JWKS, hosted AuthKit login) and Autumn billing at emulators and exercises the product's real auth code.

This repo only consumes the published npm package. There is no vendor/emulate submodule — everything imports @executor-js/emulate from npm. The emulator source is its own standalone project; to change or deploy an emulator, see "Changing or deploying an emulator" at the bottom.

Two ways to get one

Local, programmatic (what e2e/setup/cloud.boot.ts does):

import { createEmulator } from "@executor-js/emulate";
const github = await createEmulator({ service: "github", port: 4501 });
// github.url, await github.close() — plus the full typed client below

baseUrl sets the advertised origin (redirects, form actions, spec servers) when a proxy fronts the emulator — the bind stays on port.

Attach to a running one (another process, or hosted on Cloudflare with Durable Object state at https://<service>.<instance>.emulators.dev — catalog at GET https://emulators.dev/_emulate/services). Service hosts (https://<service>.emulators.dev) are control plane only, with no shared default instance behind them: create a private instance first and connect to the returned providerBaseUrl.

import { connectEmulator } from "@executor-js/emulate";
const created = await fetch("https://resend.emulators.dev/_emulate/instances", { method: "POST" });
const { providerBaseUrl } = await created.json();
const resend = await connectEmulator({ baseUrl: providerBaseUrl });
// optional: { service: "resend" } verifies the manifest on connect

In e2e scenarios use createEmulatorInstance from e2e/src/emulator-instance.ts, which wraps this.

The typed control-plane client

Both createEmulator and connectEmulator return the same EmulatorClient surface (since 0.7.0) — use it instead of hand-rolling /_emulate fetches:

Call Use
client.openapiUrl The spec URL — feed it straight to Executor's addSpec to register the emulator as an integration
client.credentials.mint({type:"api-key"}) IssuedCredential in the service's real shape: API keys, bearer tokens, OAuth/OIDC clients, client-credentials apps
client.ledger.list() / .clear() LedgerEntry[]: matched operationId, sanitized headers/body, auth identity, response status, webhook deliveries
client.seed({...}) Add state via the service's seed schema (e.g. WorkOS {oauth:{default_access_token_ttl_seconds:60}} to compress token expiry)
client.reset() Reset state + logs, replay seed — works remotely, unlike the old local-only reset
client.manifest() / .quickstart() / .specs() / .coverage() What the service is, which operations are real vs partial
client.state() / .logs() / .connections() Store snapshot, webhook deliveries, copyable SDK/env/curl snippets

The same routes exist as raw HTTP under /_emulate/* (start at GET /_emulate/quickstart, written for agents) for curl/browser use — but in TypeScript, reach for the client; the types are the point.

Recipes

Test an integration end-to-end for real (the connect-handoff pattern): client.credentials.mint(...) → register client.openapiUrl with the product → invoke a tool through the product → find the call in client.ledger.list() (match on entry.request.body / operationId). The ledger is the proof — "the product made this exact upstream call with this auth" — which beats asserting on the product's own response.

Real OAuth/OIDC flows: google/okta/microsoft/apple/clerk/workos mint OAuth clients and run real authorize/token endpoints. The WorkOS emulator additionally serves hosted AuthKit login pages (any email signs in — users are minted on the fly, no password), an OAuth authorization server for MCP clients, and Vault KV. Real SDK + WORKOS_API_URL override = the product's untouched auth code against it. Set EMULATE_WORKOS_AUDIENCE=<client_id> before createEmulator so minted MCP access tokens carry the right audience.

A live, human-pokeable cloud instance with zero .env: cd e2e && bun run cli up cloud --share — WorkOS + Autumn emulators + the app's real dev stack (recipe in e2e/setup/cloud.boot.ts), fronted with tailscale HTTPS.

Changing or deploying an emulator

The emulators live in their own repo — not in executor and not a submodule: github.com/UsefulSoftwareCo/emulate (clone it as a sibling of executor). It's a pnpm + turbo monorepo on node ≥ 24 — a different toolchain from executor's bun, which is exactly why it's standalone rather than vendored here.

You have full autonomy over it: work directly on main, and commit, push, publish, and deploy without asking. The loop:

  1. Edit in the emulate repo, then rebuild the package you changed. It resolves through built dist, so a source-only edit does nothing until you build it — this is the single most common mistake. @emulators/* packages are a workspace:* graph, so adding or renaming one needs an install + rebuild too.
  2. Publish a version bump of @executor-js/emulate to npm.
  3. Deploy the hosted Cloudflare emulators (the emulate-hosts worker behind *.emulators.dev) when behavior the hosted instances serve has changed.
  4. Back in executor, bump the @executor-js/emulate dependency to the version you just published. Never point a consumer at a local checkout to ship — publish, then bump.

The emulate repo's own AGENTS.md / README.md carry the current build, publish, and deploy commands (npm + Cloudflare creds are in 1Password). Read them there rather than memorizing flags here — they move.

A hot deploy can redden other people's e2e. The emulate-hosts worker behind *.emulators.dev is shared infrastructure; a control-plane regression there has failed unrelated PRs' suites before. Scenarios always run on private per-run instances (POST /_emulate/instances); when a scenario needs behavior that isn't deployed yet, pin to a published package version.

Gotchas

  • Secure cookies need HTTPS off-localhost. Browser-driven flows work on 127.0.0.1, but from another device (tailnet) the app's secure: true auth cookies are dropped over http → "Invalid login state". Front BOTH the app and the emulator with HTTPS (tailscale serve), and give the emulator its public origin via baseUrl AND the app's WORKOS_API_URL — the authorize URL the browser follows is derived from the latter.
  • State is per-process and id counters restart. The WorkOS emulator mints org ids from a per-boot counter — a persisted app DB from a previous boot collides with new ids. Wipe the app's data dir when you restart the emulator (the e2e globalsetup and cloud-demo both do).
  • Don't hand-write fake upstreams. If a scenario needs an upstream API, OAuth provider, or webhook source, reach for an emulator before writing a bespoke stub server — you get specs, auth, and the ledger for free, and the e2e AGENTS.md "never modify product code or stubs" rule stays intact.

版本历史

  • 8bc037d 当前 2026-07-11 18:48

    更新托管服务逻辑,移除共享默认实例,改为通过辅助函数创建独立实例以隔离账本断言并优化场景运行。

  • fd4fb02 2026-07-05 10:55

同 Skill 集合

.agents/skills/stack/SKILL.md
.agents/skills/wrdn-effect-atom-optimistic/SKILL.md
.agents/skills/wrdn-effect-atom-reactivity-keys/SKILL.md
.agents/skills/wrdn-effect-promise-exit/SKILL.md
.agents/skills/wrdn-effect-raw-fetch-boundary/SKILL.md
.agents/skills/wrdn-effect-schema-boundaries/SKILL.md
.agents/skills/wrdn-effect-schema-inferred-types/SKILL.md
.agents/skills/wrdn-effect-typed-errors/SKILL.md
.agents/skills/wrdn-effect-value-inferred-types/SKILL.md
.agents/skills/wrdn-effect-vitest-tests/SKILL.md
.agents/skills/wrdn-package-boundaries/SKILL.md
.agents/skills/wrdn-typescript-type-safety/SKILL.md
.claude/skills/prod-telemetry/SKILL.md
.claude/skills/self-contained-modals/SKILL.md
.skills/cli-release/SKILL.md
.skills/effect-atom-optimistic-updates/SKILL.md
.skills/effect-http-testing/SKILL.md
.skills/effect-use-pattern/SKILL.md
.skills/graphite/SKILL.md
.skills/warden-security-review/SKILL.md

元信息

文件数
0
版本
8bc037d
Hash
72b86bc7
收录时间
2026-07-05 10:55

首页 - Wiki
Copyright © 2011-2026 iteam. Current version is 2.155.2. UTC+08:00, 2026-07-17 19:35
浙ICP备14020137号-1 $访客地图$