# The One Map to Keep — Core Ideas Recapped

> A single-page recap: the core idea in one sentence, the three moving parts every developer must know (Store, ServicePlugin, registry entry), the analogy that holds, important caveats about what emulate is NOT, and where to go next.

- Repository: vercel-labs/emulate
- GitHub: https://github.com/vercel-labs/emulate
- Human wiki: https://grok-wiki.com/public/wiki/vercel-labs-emulate-ddc6091d171d
- Complete Markdown: https://grok-wiki.com/public/wiki/vercel-labs-emulate-ddc6091d171d/llms-full.txt

## Source Files

- `README.md`
- `packages/emulate/src/api.ts`
- `packages/@emulators/core/src/plugin.ts`
- `packages/emulate/src/registry.ts`

---

<details>
<summary>Relevant source files</summary>
The following files were used as context for generating this wiki page:

- [README.md](README.md)
- [packages/emulate/src/api.ts](packages/emulate/src/api.ts)
- [packages/emulate/src/registry.ts](packages/emulate/src/registry.ts)
- [packages/@emulators/core/src/plugin.ts](packages/@emulators/core/src/plugin.ts)
- [packages/@emulators/core/src/store.ts](packages/@emulators/core/src/store.ts)
- [packages/@emulators/core/src/server.ts](packages/@emulators/core/src/server.ts)
</details>

# The One Map to Keep — Core Ideas Recapped

This page is the cheat sheet you keep open when everything else is closed. It answers four questions at once: what emulate *actually does* in one sentence, which three moving parts every developer must understand to contribute or consume it, what analogy holds up under scrutiny, and what emulate explicitly is *not*. Once you hold this map, the rest of the codebase slots into place.

Read this page first. Read the other wiki pages when you need depth on a specific service or integration pattern.

---

## The Core Idea in One Sentence

**emulate runs fully-stateful, production-fidelity HTTP servers on your laptop that impersonate real third-party APIs — so your tests, CI jobs, and preview deployments never touch the real internet.**

That is the whole idea. Every architectural choice in the repository exists in service of that one sentence.

Sources: [README.md:1-3]()

---

## The Three Moving Parts

Everything in the codebase is an expression of three abstractions. Learn these three; derive everything else.

### 1. `Store` — the shared in-memory database

`Store` is a simple, typed key-value database that lives entirely in process memory. It has no external dependency.

Each service plugin creates typed sub-stores by calling `store.collection<T>(name, indexFields)`. A collection is an in-memory table: it auto-assigns IDs, maintains field-level indexes for fast lookup, and supports CRUD plus paginated queries.

```typescript
// packages/@emulators/core/src/store.ts:221-241
export class Store {
  private collections = new Map<string, Collection<any>>();
  private _data = new Map<string, unknown>();

  collection<T extends Entity>(name: string, indexFields: (keyof T)[] = []): Collection<T> {
    // returns existing collection or creates new one
  }
}
```

The `Store` also exposes `snapshot()` and `restore()` for the optional persistence layer, and a `reset()` that wipes all collections so test suites can start fresh between runs.

Sources: [packages/@emulators/core/src/store.ts:221-287]()

---

### 2. `ServicePlugin` — the contract every service implements

A `ServicePlugin` is a plain TypeScript interface with three fields:

```typescript
// packages/@emulators/core/src/plugin.ts:14-18
export interface ServicePlugin {
  name: string;
  register(app: Hono<AppEnv>, store: Store, webhooks: WebhookDispatcher, baseUrl: string, tokenMap?: TokenMap): void;
  seed?(store: Store, baseUrl: string): void;
}
```

- `name` — identifies the service (used in error messages and docs URLs).
- `register` — the method where the service mounts all its HTTP routes onto the shared Hono app. This is the only place routes exist; there is no route auto-discovery or convention magic.
- `seed` (optional) — populates the store with default data before any request arrives (for example, a default branch or a built-in OAuth scope list).

Every concrete emulator — `githubPlugin`, `vercelPlugin`, `slackPlugin`, etc. — satisfies exactly this interface. The core knows nothing about GitHub or Slack; it only knows `ServicePlugin`.

Sources: [packages/@emulators/core/src/plugin.ts:14-18]()

---

### 3. `ServiceEntry` (registry entry) — the lazy loader and metadata record

The registry maps service names to `ServiceEntry` objects. An entry is not the plugin itself; it is a descriptor that knows *how to load* the plugin package on demand, plus the metadata needed before loading happens.

```typescript
// packages/emulate/src/registry.ts:9-15
export interface ServiceEntry {
  label: string;
  endpoints: string;
  load(): Promise<LoadedService>;
  defaultFallback(svcSeedConfig?: Record<string, unknown>): AuthFallback;
  initConfig: Record<string, unknown>;
}
```

The `load()` method is a dynamic `import()`. The GitHub entry, for example, does:

```typescript
// packages/emulate/src/registry.ts:69-78
async load() {
  const mod = await import("@emulators/github");
  return {
    plugin: mod.githubPlugin,
    seedFromConfig: mod.seedFromConfig,
    createAppKeyResolver(store: Store): AppKeyResolver { ... },
  };
},
```

This means service packages (`@emulators/github`, `@emulators/slack`, …) are tree-shaken and only loaded if the user requests them. If you run `npx emulate --service github`, the AWS package is never loaded.

Sources: [packages/emulate/src/registry.ts:9-15](), [packages/emulate/src/registry.ts:63-85]()

---

## How the Three Parts Fit Together

When `createEmulator({ service: 'github', port: 4001 })` is called:

```
┌─────────────────────────────────────────────────────────────────┐
│  createEmulator (api.ts)                                        │
│                                                                 │
│  1. Look up SERVICE_REGISTRY['github']  →  ServiceEntry        │
│  2. entry.load()                        →  ServicePlugin + seed │
│  3. createServer(plugin, options)       →  Hono app + Store     │
│  4. plugin.register(app, store, …)      →  HTTP routes mounted  │
│  5. plugin.seed(store, baseUrl)         →  default data seeded  │
│  6. seedFromConfig(store, …, config)    →  user seed data added │
│  7. serve({ fetch: app.fetch, port })   →  HTTP server starts   │
│                                                                 │
│  Returns: { url, reset(), close() }                             │
└─────────────────────────────────────────────────────────────────┘
```

`createServer` builds the shared Hono application, attaches auth middleware, rate-limit middleware, and CORS, then hands the `store` and `webhooks` dispatcher to `plugin.register`. The plugin owns what routes exist; the core owns how requests are authenticated and errors are formatted.

Sources: [packages/emulate/src/api.ts:25-86](), [packages/@emulators/core/src/server.ts:24-104]()

---

## The Analogy That Holds

Think of emulate as a **flight simulator for HTTP integrations**.

| Flight simulator | emulate |
|-----------------|---------|
| Simulates cockpit physics locally | Simulates API wire protocol locally |
| Doesn't connect to real aircraft systems | Doesn't connect to GitHub / Stripe / etc. |
| State is in memory; reset between sessions | `store.reset()` wipes state between tests |
| Instruments respond faithfully to inputs | Full CRUD: creates/updates persist and affect related entities |
| Can be seeded with a scenario (weather, flight plan) | Seed config pre-populates users, repos, tokens |
| You control time and conditions | You control auth, scopes, pagination, webhook delivery |

The analogy holds because both systems reproduce the *behavior* of the real thing without touching it. Seed data is the scenario; the `Store` is the simulated world state; the plugin routes are the instruments.

---

## What emulate Is NOT

These are explicit non-goals, grounded in what the codebase does and does not contain.

**Not a mock library.** There is no `jest.mock()` or stubbing layer. emulate is a real HTTP server. Your code talks to `http://localhost:4001` exactly as it would talk to `https://api.github.com`. No monkey-patching, no import interception.

**Not a record-and-replay proxy.** emulate does not record real API traffic and replay it. All responses are synthesized from the in-memory `Store`. This means you get consistent, deterministic behavior but also means edge cases specific to a real API's current data are not captured.

**Not a contract test tool.** emulate does not verify that its responses match the real API's current schema. It is maintained separately. If GitHub deprecates a field, emulate will not automatically detect the drift.

**Not persistent by default.** The `Store` is in-memory. Every restart (or `reset()` call) wipes it. Persistence across restarts requires an explicit adapter passed at construction time.

**Not a complete API mirror.** The README documents specific gaps — for example, Slack Connect, Enterprise Grid admin APIs, and Socket Mode are not implemented. Assume "production-fidelity" means the common request paths, not every edge case.

Sources: [README.md:1-3](), [README.md:752-754](), [packages/@emulators/core/src/store.ts:251-256]()

---

## A Quick Class Model

```text
@emulators/core
┌─────────────────────────────────────────────────────────┐
│ ServicePlugin (interface)                               │
│   name: string                                          │
│   register(app, store, webhooks, baseUrl, tokenMap)     │
│   seed?(store, baseUrl)                                 │
└────────────────────┬────────────────────────────────────┘
                     │ implements
       ┌─────────────┼───────────────┐
  githubPlugin  vercelPlugin  slackPlugin  …

@emulators/core
┌─────────────────────────────────────────────────────────┐
│ Store                                                   │
│   collection<T>(name, indexFields) → Collection<T>      │
│   reset()                                               │
│   snapshot() / restore()                               │
│                                                         │
│   Collection<T>                                         │
│     insert / get / findBy / update / delete / query     │
└─────────────────────────────────────────────────────────┘

emulate (CLI package)
┌─────────────────────────────────────────────────────────┐
│ ServiceEntry (registry entry)                           │
│   label, endpoints                                      │
│   load() → Promise<LoadedService>    (dynamic import)   │
│   defaultFallback(cfg) → AuthFallback                   │
│   initConfig                                            │
└─────────────────────────────────────────────────────────┘
```

Sources: [packages/@emulators/core/src/plugin.ts:14-18](), [packages/@emulators/core/src/store.ts:63-219](), [packages/emulate/src/registry.ts:9-15]()

---

## Where to Go Next

| You want to… | Go to… |
|---|---|
| Add a new service | Implement `ServicePlugin`, add a `ServiceEntry` to the registry |
| Understand a specific service's routes | Read `packages/@emulators/<service>/src/` |
| Understand state persistence | Read `packages/@emulators/core/src/persistence.ts` |
| Embed in a Next.js app | Read `packages/@emulators/adapter-next/` and the README Next.js section |
| Add seed data | Pass a `seed` object to `createEmulator` or use the YAML config format |
| Reset between tests | Call `emulator.reset()` in `afterEach` |

---

The whole system is smaller than it looks: one `Store`, one `ServicePlugin` interface, and one registry entry per service. Everything else — OAuth flows, webhook delivery, rate limiting, pagination — is built on top of those three primitives. Hold that map and the rest is detail.

Sources: [packages/@emulators/core/src/server.ts:92](), [packages/emulate/src/api.ts:58]()
