emulate 0.1.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +125 -5
- package/dist/api.d.ts +23 -0
- package/dist/api.js +713 -0
- package/dist/api.js.map +1 -0
- package/dist/chunk-D6EKRYGP.js +1615 -0
- package/dist/chunk-D6EKRYGP.js.map +1 -0
- package/dist/chunk-TEPNEZ63.js +2143 -0
- package/dist/chunk-TEPNEZ63.js.map +1 -0
- package/dist/dist-BKXG6HVH.js +3641 -0
- package/dist/dist-BKXG6HVH.js.map +1 -0
- package/dist/dist-DSSB3LYT.js +788 -0
- package/dist/dist-DSSB3LYT.js.map +1 -0
- package/dist/dist-JYDZIVC6.js +2684 -0
- package/dist/dist-JYDZIVC6.js.map +1 -0
- package/dist/dist-O4KFIBVU.js +626 -0
- package/dist/dist-O4KFIBVU.js.map +1 -0
- package/dist/dist-OCDKIMRJ.js +10586 -0
- package/dist/dist-OCDKIMRJ.js.map +1 -0
- package/dist/dist-UZSUUE3Y.js +1287 -0
- package/dist/dist-UZSUUE3Y.js.map +1 -0
- package/dist/dist-VVXVP5EZ.js +1199 -0
- package/dist/dist-VVXVP5EZ.js.map +1 -0
- package/dist/fonts/GeistPixel-Square.woff2 +0 -0
- package/dist/fonts/geist-sans.woff2 +0 -0
- package/dist/index.js +615 -17326
- package/dist/index.js.map +1 -1
- package/package.json +21 -5
package/README.md
CHANGED
|
@@ -49,6 +49,65 @@ emulate list
|
|
|
49
49
|
|
|
50
50
|
The port can also be set via `EMULATE_PORT` or `PORT` environment variables.
|
|
51
51
|
|
|
52
|
+
## Programmatic API
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
npm install emulate
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Each call to `createEmulator` starts a single service:
|
|
59
|
+
|
|
60
|
+
```typescript
|
|
61
|
+
import { createEmulator } from 'emulate'
|
|
62
|
+
|
|
63
|
+
const github = await createEmulator({ service: 'github', port: 4001 })
|
|
64
|
+
const vercel = await createEmulator({ service: 'vercel', port: 4002 })
|
|
65
|
+
|
|
66
|
+
github.url // 'http://localhost:4001'
|
|
67
|
+
vercel.url // 'http://localhost:4002'
|
|
68
|
+
|
|
69
|
+
await github.close()
|
|
70
|
+
await vercel.close()
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Vitest / Jest setup
|
|
74
|
+
|
|
75
|
+
```typescript
|
|
76
|
+
// vitest.setup.ts
|
|
77
|
+
import { createEmulator, type Emulator } from 'emulate'
|
|
78
|
+
|
|
79
|
+
let github: Emulator
|
|
80
|
+
let vercel: Emulator
|
|
81
|
+
|
|
82
|
+
beforeAll(async () => {
|
|
83
|
+
;[github, vercel] = await Promise.all([
|
|
84
|
+
createEmulator({ service: 'github', port: 4001 }),
|
|
85
|
+
createEmulator({ service: 'vercel', port: 4002 }),
|
|
86
|
+
])
|
|
87
|
+
process.env.GITHUB_URL = github.url
|
|
88
|
+
process.env.VERCEL_URL = vercel.url
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
afterEach(() => { github.reset(); vercel.reset() })
|
|
92
|
+
afterAll(() => Promise.all([github.close(), vercel.close()]))
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Options
|
|
96
|
+
|
|
97
|
+
| Option | Default | Description |
|
|
98
|
+
|--------|---------|-------------|
|
|
99
|
+
| `service` | *(required)* | Service to emulate: `'github'`, `'vercel'`, or `'google'` |
|
|
100
|
+
| `port` | `4000` | Port for the HTTP server |
|
|
101
|
+
| `seed` | none | Inline seed data (same shape as YAML config) |
|
|
102
|
+
|
|
103
|
+
### Instance methods
|
|
104
|
+
|
|
105
|
+
| Method | Description |
|
|
106
|
+
|--------|-------------|
|
|
107
|
+
| `url` | Base URL of the running server |
|
|
108
|
+
| `reset()` | Wipe the store and replay seed data |
|
|
109
|
+
| `close()` | Shut down the HTTP server, returns a Promise |
|
|
110
|
+
|
|
52
111
|
## Configuration
|
|
53
112
|
|
|
54
113
|
Configuration is optional. To customize seed data, create `emulate.config.yaml` in your project root (or pass `--seed`):
|
|
@@ -95,6 +154,40 @@ google:
|
|
|
95
154
|
client_secret: GOCSPX-secret
|
|
96
155
|
redirect_uris:
|
|
97
156
|
- http://localhost:3000/api/auth/callback/google
|
|
157
|
+
labels:
|
|
158
|
+
- id: Label_ops
|
|
159
|
+
user_email: testuser@example.com
|
|
160
|
+
name: Ops/Review
|
|
161
|
+
color_background: "#DDEEFF"
|
|
162
|
+
color_text: "#111111"
|
|
163
|
+
messages:
|
|
164
|
+
- id: msg_welcome
|
|
165
|
+
user_email: testuser@example.com
|
|
166
|
+
from: welcome@example.com
|
|
167
|
+
to: testuser@example.com
|
|
168
|
+
subject: Welcome to the Gmail emulator
|
|
169
|
+
body_text: You can now test Gmail, Calendar, and Drive flows locally.
|
|
170
|
+
label_ids: [INBOX, UNREAD, CATEGORY_UPDATES]
|
|
171
|
+
calendars:
|
|
172
|
+
- id: primary
|
|
173
|
+
user_email: testuser@example.com
|
|
174
|
+
summary: testuser@example.com
|
|
175
|
+
primary: true
|
|
176
|
+
selected: true
|
|
177
|
+
time_zone: UTC
|
|
178
|
+
calendar_events:
|
|
179
|
+
- id: evt_kickoff
|
|
180
|
+
user_email: testuser@example.com
|
|
181
|
+
calendar_id: primary
|
|
182
|
+
summary: Project Kickoff
|
|
183
|
+
start_date_time: 2025-01-10T09:00:00.000Z
|
|
184
|
+
end_date_time: 2025-01-10T09:30:00.000Z
|
|
185
|
+
drive_items:
|
|
186
|
+
- id: drv_docs
|
|
187
|
+
user_email: testuser@example.com
|
|
188
|
+
name: Docs
|
|
189
|
+
mime_type: application/vnd.google-apps.folder
|
|
190
|
+
parent_ids: [root]
|
|
98
191
|
```
|
|
99
192
|
|
|
100
193
|
## OAuth & Integrations
|
|
@@ -145,6 +238,8 @@ github:
|
|
|
145
238
|
contents: read
|
|
146
239
|
issues: write
|
|
147
240
|
events: [push, pull_request]
|
|
241
|
+
webhook_url: "http://localhost:3000/webhooks/github"
|
|
242
|
+
webhook_secret: "my-secret"
|
|
148
243
|
installations:
|
|
149
244
|
- installation_id: 100
|
|
150
245
|
account: my-org
|
|
@@ -153,6 +248,10 @@ github:
|
|
|
153
248
|
|
|
154
249
|
JWT authentication: sign a JWT with `{ iss: "<app_id>" }` using the app's private key (RS256). The emulator verifies the signature and resolves the app.
|
|
155
250
|
|
|
251
|
+
**App webhook delivery**: When events occur on repos where a GitHub App is installed, the emulator mirrors real GitHub behavior:
|
|
252
|
+
- All webhook payloads (including repo and org hooks) include an `installation` field with `{ id, node_id }`.
|
|
253
|
+
- If the app has a `webhook_url`, the emulator delivers the event there with the `installation` field and (if configured) an `X-Hub-Signature-256` header signed with `webhook_secret`.
|
|
254
|
+
|
|
156
255
|
## Vercel API
|
|
157
256
|
|
|
158
257
|
Every endpoint below is fully stateful with Vercel-style JSON responses and cursor-based pagination.
|
|
@@ -322,26 +421,47 @@ Every endpoint below is fully stateful. Creates, updates, and deletes persist in
|
|
|
322
421
|
- `GET /zen` - random zen phrase
|
|
323
422
|
- `GET /versions` - API versions
|
|
324
423
|
|
|
325
|
-
## Google
|
|
424
|
+
## Google OAuth + Gmail, Calendar, and Drive APIs
|
|
326
425
|
|
|
327
|
-
OAuth 2.0
|
|
426
|
+
OAuth 2.0, OpenID Connect, and mutable Google Workspace-style surfaces for local inbox, calendar, and drive flows.
|
|
427
|
+
This stays under a single `google:` service because the Gmail API is used by both consumer Google accounts and Google Workspace accounts. A separate Workspace-specific service would only make sense once we add admin or tenant-level APIs that do not belong in the basic Google/Gmail emulator.
|
|
328
428
|
|
|
329
429
|
- `GET /o/oauth2/v2/auth` - authorization endpoint
|
|
330
|
-
- `POST /oauth2/
|
|
430
|
+
- `POST /oauth2/token` - token exchange
|
|
331
431
|
- `GET /oauth2/v2/userinfo` - get user info
|
|
332
432
|
- `GET /.well-known/openid-configuration` - OIDC discovery document
|
|
333
433
|
- `GET /oauth2/v3/certs` - JSON Web Key Set (JWKS)
|
|
434
|
+
- `GET /gmail/v1/users/:userId/messages` - list messages with `q`, `labelIds`, `maxResults`, and `pageToken`
|
|
435
|
+
- `GET /gmail/v1/users/:userId/messages/:id` - fetch a Gmail-style message payload in `full`, `metadata`, `minimal`, or `raw` formats
|
|
436
|
+
- `GET /gmail/v1/users/:userId/messages/:messageId/attachments/:id` - fetch attachment bodies
|
|
437
|
+
- `POST /gmail/v1/users/:userId/messages/send` - create sent mail from `raw` MIME or structured fields
|
|
438
|
+
- `POST /gmail/v1/users/:userId/messages/import` - import inbox mail
|
|
439
|
+
- `POST /gmail/v1/users/:userId/messages` - insert a message directly
|
|
440
|
+
- `POST /gmail/v1/users/:userId/messages/:id/modify` - add/remove labels on one message
|
|
441
|
+
- `POST /gmail/v1/users/:userId/messages/batchModify` - add/remove labels across many messages
|
|
442
|
+
- `POST /gmail/v1/users/:userId/messages/:id/trash` and `POST /gmail/v1/users/:userId/messages/:id/untrash`
|
|
443
|
+
- `GET /gmail/v1/users/:userId/drafts`, `POST /gmail/v1/users/:userId/drafts`, `GET /gmail/v1/users/:userId/drafts/:id`, `PUT /gmail/v1/users/:userId/drafts/:id`, `POST /gmail/v1/users/:userId/drafts/:id/send`, `DELETE /gmail/v1/users/:userId/drafts/:id`
|
|
444
|
+
- `POST /gmail/v1/users/:userId/threads/:id/modify` - add/remove labels across a thread
|
|
445
|
+
- `GET /gmail/v1/users/:userId/threads` and `GET /gmail/v1/users/:userId/threads/:id`
|
|
446
|
+
- `GET /gmail/v1/users/:userId/labels`, `POST /gmail/v1/users/:userId/labels`, `PATCH /gmail/v1/users/:userId/labels/:id`, `DELETE /gmail/v1/users/:userId/labels/:id`
|
|
447
|
+
- `GET /gmail/v1/users/:userId/history`, `POST /gmail/v1/users/:userId/watch`, `POST /gmail/v1/users/:userId/stop`
|
|
448
|
+
- `GET /gmail/v1/users/:userId/settings/filters`, `POST /gmail/v1/users/:userId/settings/filters`, `DELETE /gmail/v1/users/:userId/settings/filters/:id`
|
|
449
|
+
- `GET /gmail/v1/users/:userId/settings/forwardingAddresses`, `GET /gmail/v1/users/:userId/settings/sendAs`
|
|
450
|
+
- `GET /calendar/v3/users/:userId/calendarList`, `GET /calendar/v3/calendars/:calendarId/events`, `POST /calendar/v3/calendars/:calendarId/events`, `DELETE /calendar/v3/calendars/:calendarId/events/:eventId`, `POST /calendar/v3/freeBusy`
|
|
451
|
+
- `GET /drive/v3/files`, `GET /drive/v3/files/:fileId`, `POST /drive/v3/files`, `PATCH /drive/v3/files/:fileId`, `PUT /drive/v3/files/:fileId`, `POST /upload/drive/v3/files`
|
|
452
|
+
|
|
453
|
+
The Google plugin still does not cover every Google API edge case, but Gmail, Calendar, and Drive now have enough mutable surface to support realistic local automation flows without stuffing everything into static seed config.
|
|
334
454
|
|
|
335
455
|
## Architecture
|
|
336
456
|
|
|
337
457
|
```
|
|
338
458
|
packages/
|
|
339
459
|
emulate/ # CLI entry point (commander)
|
|
340
|
-
@
|
|
460
|
+
@emulators/
|
|
341
461
|
core/ # HTTP server, in-memory store, plugin interface, middleware
|
|
342
462
|
vercel/ # Vercel API service
|
|
343
463
|
github/ # GitHub API service
|
|
344
|
-
google/ # Google OAuth 2.0 / OIDC
|
|
464
|
+
google/ # Google OAuth 2.0 / OIDC + Gmail, Calendar, and Drive APIs
|
|
345
465
|
apps/
|
|
346
466
|
web/ # Documentation site (Next.js)
|
|
347
467
|
```
|
package/dist/api.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
declare const SERVICE_NAME_LIST: readonly ["vercel", "github", "google", "slack", "apple", "microsoft", "aws"];
|
|
2
|
+
type ServiceName = (typeof SERVICE_NAME_LIST)[number];
|
|
3
|
+
|
|
4
|
+
interface SeedConfig {
|
|
5
|
+
tokens?: Record<string, {
|
|
6
|
+
login: string;
|
|
7
|
+
scopes?: string[];
|
|
8
|
+
}>;
|
|
9
|
+
[service: string]: unknown;
|
|
10
|
+
}
|
|
11
|
+
interface EmulatorOptions {
|
|
12
|
+
service: ServiceName;
|
|
13
|
+
port?: number;
|
|
14
|
+
seed?: SeedConfig;
|
|
15
|
+
}
|
|
16
|
+
interface Emulator {
|
|
17
|
+
url: string;
|
|
18
|
+
reset(): void;
|
|
19
|
+
close(): Promise<void>;
|
|
20
|
+
}
|
|
21
|
+
declare function createEmulator(options: EmulatorOptions): Promise<Emulator>;
|
|
22
|
+
|
|
23
|
+
export { type Emulator, type EmulatorOptions, type SeedConfig, type ServiceName, createEmulator };
|