Skip to content

Commit 9d10510

Browse files
authored
feat(emulate): add Emulate plugin to marketplace (#144)
Add local drop-in API emulator for Vercel, GitHub, Google, Slack, Apple, Microsoft, and AWS to the plugin marketplace.
1 parent 09d8c89 commit 9d10510

6 files changed

Lines changed: 329 additions & 0 deletions

File tree

.claude-plugin/marketplace.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -535,6 +535,14 @@
535535
"keywords": ["tiptap", "rich-text-editor", "prosemirror", "wysiwyg"],
536536
"tags": ["framework", "editor"],
537537
"source": "./plugins/tiptap"
538+
},
539+
{
540+
"name": "emulate",
541+
"description": "Local drop-in API emulator for Vercel, GitHub, Google, Slack, Apple, Microsoft, and AWS",
542+
"category": "development",
543+
"keywords": ["emulate", "api-emulation", "local-development", "testing"],
544+
"tags": ["tooling", "testing"],
545+
"source": "./plugins/emulate"
538546
}
539547
]
540548
}

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,11 @@ Helps coding agents integrate and work with the Tiptap rich text editor — exte
267267

268268
**Install:** `/plugin install tiptap@pleaseai` | **Source:** [plugins/tiptap](https://github.com/pleaseai/claude-code-plugins/tree/main/plugins/tiptap)
269269

270+
#### Emulate
271+
Local drop-in API emulator for Vercel, GitHub, Google, Slack, Apple, Microsoft, and AWS.
272+
273+
**Install:** `/plugin install emulate@pleaseai` | **Source:** [plugins/emulate](https://github.com/pleaseai/claude-code-plugins/tree/main/plugins/emulate)
274+
270275
## Quick Start
271276

272277
The fastest way to get started — install the marketplace and let the plugin recommender auto-detect what you need:
@@ -349,6 +354,7 @@ Once the marketplace is added, install any plugin individually:
349354
/plugin install next@pleaseai
350355
/plugin install react@pleaseai
351356
/plugin install react-native@pleaseai
357+
/plugin install emulate@pleaseai
352358
```
353359

354360
## What Are Claude Code Plugins?
Lines changed: 286 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,286 @@
1+
---
2+
name: emulate
3+
description: Local drop-in API emulator for Vercel, GitHub, Google, Slack, Apple, Microsoft, and AWS. Use when the user needs to start emulated services, configure seed data, write tests against local APIs, set up CI without network access, or work with the emulate CLI or programmatic API. Triggers include "start the emulator", "emulate services", "mock API locally", "create emulator config", "test against local API", "npx emulate", or any task requiring local service emulation.
4+
allowed-tools: Bash(npx emulate:*), Bash(emulate:*)
5+
---
6+
7+
# Service Emulation with emulate
8+
9+
Local drop-in replacement services for CI and no-network sandboxes. Fully stateful, production-fidelity API emulation, not mocks.
10+
11+
## Quick Start
12+
13+
```bash
14+
npx emulate
15+
```
16+
17+
All services start with sensible defaults:
18+
19+
| Service | Default Port |
20+
|-----------|-------------|
21+
| Vercel | 4000 |
22+
| GitHub | 4001 |
23+
| Google | 4002 |
24+
| Slack | 4003 |
25+
| Apple | 4004 |
26+
| Microsoft | 4005 |
27+
| AWS | 4006 |
28+
29+
## CLI
30+
31+
```bash
32+
# Start all services (zero-config)
33+
emulate
34+
35+
# Start specific services
36+
emulate --service vercel,github
37+
38+
# Custom base port (auto-increments per service)
39+
emulate --port 3000
40+
41+
# Use a seed config file
42+
emulate --seed config.yaml
43+
44+
# Generate a starter config
45+
emulate init
46+
47+
# Generate config for a specific service
48+
emulate init --service vercel
49+
50+
# List available services
51+
emulate list
52+
```
53+
54+
### Options
55+
56+
| Flag | Default | Description |
57+
|------|---------|-------------|
58+
| `-p, --port` | `4000` | Base port (auto-increments per service) |
59+
| `-s, --service` | all | Comma-separated services to enable |
60+
| `--seed` | auto-detect | Path to seed config (YAML or JSON) |
61+
62+
The port can also be set via `EMULATE_PORT` or `PORT` environment variables.
63+
64+
## Programmatic API
65+
66+
```bash
67+
npm install emulate
68+
```
69+
70+
Each call to `createEmulator` starts a single service:
71+
72+
```typescript
73+
import { createEmulator } from 'emulate'
74+
75+
const github = await createEmulator({ service: 'github', port: 4001 })
76+
const vercel = await createEmulator({ service: 'vercel', port: 4002 })
77+
78+
github.url // 'http://localhost:4001'
79+
vercel.url // 'http://localhost:4002'
80+
81+
await github.close()
82+
await vercel.close()
83+
```
84+
85+
### Options
86+
87+
| Option | Default | Description |
88+
|--------|---------|-------------|
89+
| `service` | *(required)* | `'vercel'`, `'github'`, `'google'`, `'slack'`, `'apple'`, `'microsoft'`, or `'aws'` |
90+
| `port` | `4000` | Port for the HTTP server |
91+
| `seed` | none | Inline seed data (same shape as YAML config) |
92+
93+
### Instance Methods
94+
95+
| Method | Description |
96+
|--------|-------------|
97+
| `url` | Base URL of the running server |
98+
| `reset()` | Wipe the store and replay seed data |
99+
| `close()` | Shut down the HTTP server, returns a Promise |
100+
101+
## Vitest / Jest Setup
102+
103+
```typescript
104+
import { createEmulator, type Emulator } from 'emulate'
105+
106+
let github: Emulator
107+
let vercel: Emulator
108+
109+
beforeAll(async () => {
110+
;[github, vercel] = await Promise.all([
111+
createEmulator({ service: 'github', port: 4001 }),
112+
createEmulator({ service: 'vercel', port: 4002 }),
113+
])
114+
process.env.GITHUB_URL = github.url
115+
process.env.VERCEL_URL = vercel.url
116+
})
117+
118+
afterEach(() => { github.reset(); vercel.reset() })
119+
afterAll(() => Promise.all([github.close(), vercel.close()]))
120+
```
121+
122+
## Configuration
123+
124+
Configuration is optional. The CLI auto-detects config files in this order:
125+
126+
1. `emulate.config.yaml` / `.yml`
127+
2. `emulate.config.json`
128+
3. `service-emulator.config.yaml` / `.yml`
129+
4. `service-emulator.config.json`
130+
131+
Or pass `--seed <file>` explicitly. Run `emulate init` to generate a starter file.
132+
133+
### Config Structure
134+
135+
```yaml
136+
tokens:
137+
my_token:
138+
login: admin
139+
scopes: [repo, user]
140+
141+
vercel:
142+
users:
143+
- username: developer
144+
name: Developer
145+
email: dev@example.com
146+
teams:
147+
- slug: my-team
148+
name: My Team
149+
projects:
150+
- name: my-app
151+
team: my-team
152+
framework: nextjs
153+
integrations:
154+
- client_id: oac_abc123
155+
client_secret: secret_abc123
156+
name: My Vercel App
157+
redirect_uris:
158+
- http://localhost:3000/api/auth/callback/vercel
159+
160+
github:
161+
users:
162+
- login: octocat
163+
name: The Octocat
164+
email: octocat@github.com
165+
orgs:
166+
- login: my-org
167+
name: My Organization
168+
repos:
169+
- owner: octocat
170+
name: hello-world
171+
language: JavaScript
172+
auto_init: true
173+
oauth_apps:
174+
- client_id: Iv1.abc123
175+
client_secret: secret_abc123
176+
name: My Web App
177+
redirect_uris:
178+
- http://localhost:3000/api/auth/callback/github
179+
180+
google:
181+
users:
182+
- email: testuser@example.com
183+
name: Test User
184+
oauth_clients:
185+
- client_id: my-client-id.apps.googleusercontent.com
186+
client_secret: GOCSPX-secret
187+
redirect_uris:
188+
- http://localhost:3000/api/auth/callback/google
189+
190+
slack:
191+
team:
192+
name: My Workspace
193+
domain: my-workspace
194+
users:
195+
- name: developer
196+
real_name: Developer
197+
email: dev@example.com
198+
channels:
199+
- name: general
200+
topic: General discussion
201+
bots:
202+
- name: my-bot
203+
oauth_apps:
204+
- client_id: "12345.67890"
205+
client_secret: example_client_secret
206+
name: My Slack App
207+
redirect_uris:
208+
- http://localhost:3000/api/auth/callback/slack
209+
210+
apple:
211+
users:
212+
- email: testuser@icloud.com
213+
name: Test User
214+
oauth_clients:
215+
- client_id: com.example.app
216+
team_id: TEAM001
217+
name: My Apple App
218+
redirect_uris:
219+
- http://localhost:3000/api/auth/callback/apple
220+
221+
microsoft:
222+
users:
223+
- email: testuser@outlook.com
224+
name: Test User
225+
oauth_clients:
226+
- client_id: example-client-id
227+
client_secret: example-client-secret
228+
name: My Microsoft App
229+
redirect_uris:
230+
- http://localhost:3000/api/auth/callback/microsoft-entra-id
231+
232+
aws:
233+
region: us-east-1
234+
s3:
235+
buckets:
236+
- name: my-app-bucket
237+
sqs:
238+
queues:
239+
- name: my-app-events
240+
iam:
241+
users:
242+
- user_name: developer
243+
create_access_key: true
244+
roles:
245+
- role_name: lambda-execution-role
246+
```
247+
248+
### Auth
249+
250+
Tokens map to users. Pass them as `Authorization: Bearer <token>` or `Authorization: token <token>`. When no tokens are configured, a default `test_token_admin` is created for the `admin` user.
251+
252+
Each service also has a fallback user. If no token is provided, requests authenticate as the first seeded user.
253+
254+
## Pointing Your App at the Emulator
255+
256+
Set environment variables to override real service URLs:
257+
258+
```bash
259+
VERCEL_EMULATOR_URL=http://localhost:4000
260+
GITHUB_EMULATOR_URL=http://localhost:4001
261+
GOOGLE_EMULATOR_URL=http://localhost:4002
262+
SLACK_EMULATOR_URL=http://localhost:4003
263+
APPLE_EMULATOR_URL=http://localhost:4004
264+
MICROSOFT_EMULATOR_URL=http://localhost:4005
265+
AWS_EMULATOR_URL=http://localhost:4006
266+
```
267+
268+
Then use these in your app to construct API and OAuth URLs. See each service's skill for SDK-specific override instructions.
269+
270+
## Architecture
271+
272+
```
273+
packages/
274+
emulate/ # CLI entry point + programmatic API
275+
@emulators/
276+
core/ # HTTP server (Hono), Store, plugin interface, middleware
277+
vercel/ # Vercel API service plugin
278+
github/ # GitHub API service plugin
279+
google/ # Google OAuth 2.0 / OIDC plugin
280+
slack/ # Slack Web API, OAuth, incoming webhooks plugin
281+
apple/ # Sign in with Apple / OIDC plugin
282+
microsoft/ # Microsoft Entra ID OAuth 2.0 / OIDC plugin
283+
aws/ # AWS S3, SQS, IAM, STS plugin
284+
```
285+
286+
The core provides a generic `Store` with typed `Collection<T>` instances supporting CRUD, indexing, filtering, and pagination. Each service plugin registers routes on the shared Hono app and uses the store for state.
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"name": "emulate",
3+
"version": "1.0.0",
4+
"description": "Local drop-in API emulator for Vercel, GitHub, Google, Slack, Apple, Microsoft, and AWS",
5+
"license": "Apache-2.0",
6+
"keywords": ["emulate", "api-emulation", "local-development", "testing"],
7+
"skills": "./.agents/skills/"
8+
}

plugins/emulate/skills-lock.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"version": 1,
3+
"skills": {
4+
"emulate": {
5+
"source": "vercel-labs/emulate",
6+
"sourceType": "github",
7+
"computedHash": "c71f52c30b0bdfdccf008c89f0c2347e532686fe4a34b23abcc21343eb7de5dc"
8+
}
9+
}
10+
}

release-please-config.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,17 @@
438438
"jsonpath": "$.version"
439439
}
440440
]
441+
},
442+
"plugins/emulate": {
443+
"release-type": "simple",
444+
"component": "emulate",
445+
"extra-files": [
446+
{
447+
"type": "json",
448+
"path": ".claude-plugin/plugin.json",
449+
"jsonpath": "$.version"
450+
}
451+
]
441452
}
442453
},
443454
"release-type": "node",

0 commit comments

Comments
 (0)