Skip to main content

nuxt

Nuxt adapter for embedding emulators directly in a Nuxt app via @emulators/adapter-nuxt. Use when the user needs to embed emulators in Nuxt, set up same-origin OAuth for preview deployments, create an emulate catch-all server route, configure persistence for embedded Nuxt emulators, or wrap nuxt.config with withEmulate. Triggers include "Nuxt emulator", "adapter-nuxt", "embedded emulator", "same-origin OAuth", "createEmulateHandler", "withEmulate", or any task requiring emulators inside a Nuxt app.

Quellinformationen

Repository
vercel-labs/emulate
Letzte Quellaktivität
24. September 2026 um 14:38
Erkannte Sprache von SKILL.md
Englisch
Sterne
1.893
Forks
138

Installationsoptionen

Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.

Quelldateien prüfen

Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.

SKILL.md wird angezeigt

SKILL.md
Quellanweisungen · Schreibgeschützte Vorschau
name
nuxt
description
Nuxt adapter for embedding emulators directly in a Nuxt app via @emulators/adapter-nuxt. Use when the user needs to embed emulators in Nuxt, set up same-origin OAuth for preview deployments, create an emulate catch-all server route, configure persistence for embedded Nuxt emulators, or wrap nuxt.config with withEmulate. Triggers include "Nuxt emulator", "adapter-nuxt", "embedded emulator", "same-origin OAuth", "createEmulateHandler", "withEmulate", or any task requiring emulators inside a Nuxt app.
allowed-tools
Bash(npx emulate:*)
# Nuxt Integration The `@emulators/adapter-nuxt` package embeds emulators directly into a Nuxt app, running them on the same origin. This is useful for preview deployments where OAuth callback URLs change with every deployment. ## Install ```bash npm install @emulators/adapter-nuxt @emulators/github @emulators/google ``` Only install the emulators you need. Each `@emulators/*` package is published independently, keeping server bundles small. ## Server Route Create a named catch-all route that serves emulator traffic: ```typescript // server/routes/emulate/[...path].ts import { createEmulateHandler } from '@emulators/adapter-nuxt' import * as github from '@emulators/github' import * as google from '@emulators/google' export default defineEventHandler(createEmulateHandler({ services: { github: { emulator: github, seed: { users: [{ login: 'octocat', name: 'The Octocat' }], repos: [{ owner: 'octocat', name: 'hello-world', auto_init: true }], }, }, google: { emulator: google, seed: { users: [{ email: 'test@example.com', name: 'Test User' }], }, }, }, })) ``` This creates these routes: - `/emulate/github/**` serves the GitHub emulator - `/emulate/google/**` serves the Google emulator GitHub installation-token metadata is available server-side at `/emulate/github/_emulate/installation-tokens`. ## Nuxt Config Emulator UI pages use bundled fonts. Wrap your Nuxt config so Nitro traces the core package assets into production builds: ```typescript // nuxt.config.ts import { withEmulate } from '@emulators/adapter-nuxt' export default defineNuxtConfig(withEmulate({ // your normal Nuxt config })) ``` ## OAuth Configuration Point your OAuth provider at the emulator paths on the same origin: ```typescript const baseUrl = process.env.NUXT_PUBLIC_SITE_URL ?? 'http://localhost:3000' export const githubOAuth = { clientId: 'any-value', clientSecret: 'any-value', authorizationUrl: `${baseUrl}/emulate/github/login/oauth/authorize`, tokenUrl: `${baseUrl}/emulate/github/login/oauth/access_token`, userInfoUrl: `${baseUrl}/emulate/github/user`, } ``` No `oauth_apps` need to be seeded. When none are configured, the emulator skips `client_id`, `client_secret`, and `redirect_uri` validation. ## Persistence By default, emulator state is in-memory and resets on every cold start. To persist state across restarts, pass a `persistence` adapter. ### Nitro Storage ```typescript import { createEmulateHandler } from '@emulators/adapter-nuxt' import * as github from '@emulators/github' const storageAdapter = { async load() { return await useStorage('emulate').getItem<string>('state') }, async save(data: string) { await useStorage('emulate').setItem('state', data) }, } export default defineEventHandler(createEmulateHandler({ services: { github: { emulator: github } }, persistence: storageAdapter, })) ``` ### File Persistence For local development, `@emulators/core` ships a file-based adapter: ```typescript import { filePersistence } from '@emulators/core' persistence: filePersistence('.emulate/state.json'), ``` GitHub App seeds may omit `private_key`. Retain the handler and call server-only `generatedSecrets()`; explicit keys are excluded. Keep persisted snapshots private and implement `initialize` atomically. ### How Persistence Works - **Cold start**: The adapter loads state from the persistence adapter. If found, it restores the full Store and token map. If not found, it seeds from config and saves the initial state. - **After mutating requests** (POST, PUT, PATCH, DELETE): State is saved. Saves are serialized via an internal queue to prevent race conditions. - **No persistence configured**: Falls back to pure in-memory. Seed data re-initializes on every cold start. ## How It Works 1. **Incoming request**: `/emulate/github/login/oauth/authorize?client_id=...` 2. **Parse**: service = `github`, rest = `/login/oauth/authorize` 3. **Strip prefix**: A new `Request` is created with the stripped path and forwarded to the GitHub service app 4. **Rewrite response**: HTML `action` and `href` attributes, CSS `url()` font references, and `Location` headers get the service prefix prepended 5. **Persist**: After mutating requests, state is saved via the persistence adapter ## Limitations - Requires a Node-compatible Nuxt server runtime since emulators use Node APIs - Concurrent mutations use last-write-wins semantics. Generated identities require `initialize` to select the initial snapshot atomically across cold starts. ## Config Reference ### `createEmulateHandler(config, options?)` | Field | Type | Description | |-------|------|-------------| | `services` | `Record<string, EmulatorEntry>` | Map of service name to emulator config | | `persistence?` | `PersistenceAdapter` | Optional persistence adapter for state across cold starts | Each `EmulatorEntry`: | Field | Type | Description | |-------|------|-------------| | `emulator` | `EmulatorModule` | The emulator package, such as `import * as github from '@emulators/github'` | | `seed?` | `Record<string, unknown>` | Seed data matching the service's config schema | Options: | Option | Type | Default | Description | |--------|------|---------|-------------| | `param` | `string` | `"path"` | Named catch-all route param | | `routePrefix` | `string` | detected | Path prefix where the catch-all route is mounted | ### `withEmulate(nuxtConfig)` Wraps a Nuxt config to include `@emulators/core` assets in Nitro's production trace. Call it inside `defineNuxtConfig` in `nuxt.config.ts`. ### `PersistenceAdapter` ```typescript interface PersistenceAdapter { load(): Promise<string | null> save(data: string): Promise<void> initialize?(data: string): Promise<string> } ``` `initialize` must atomically create the initial value or return the value another instance created first. Implement it with compare-and-set semantics such as Redis `SET NX`. The built-in `filePersistence(path)` from `@emulators/core` provides this behavior for local development. ## Custom emulators The adapter accepts definitions created with `defineEmulator` from `emulate` in `services[name].emulator`. Reuse the definition from CLI/tests; custom inspector is opt-in. Root-relative redirect locations stay under the service mount, while custom HTML bodies pass through unchanged. Await the returned handler's `close()` in test teardown. Install `emulate` as a runtime dependency for deployed definitions. See https://emulate.dev/docs/custom-emulators for seeds, snapshots, persistence, and lifecycle rules.
Auf GitHub ansehen