@emulators/adapter-next 0.4.0 → 0.5.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 +120 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/package.json +5 -3
package/README.md
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# @emulators/adapter-next
|
|
2
|
+
|
|
3
|
+
Next.js App Router integration for emulate. Embed emulators directly in your Next.js app so they run on the same origin, solving the Vercel preview deployment problem where OAuth callback URLs change with every deployment.
|
|
4
|
+
|
|
5
|
+
Part of [emulate](https://github.com/vercel-labs/emulate) — local drop-in replacement services for CI and no-network sandboxes.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @emulators/adapter-next
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Only install the emulators you need alongside the adapter:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install @emulators/adapter-next @emulators/github @emulators/google
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Route handler
|
|
20
|
+
|
|
21
|
+
Create a catch-all route that serves emulator traffic:
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
// app/emulate/[...path]/route.ts
|
|
25
|
+
import { createEmulateHandler } from '@emulators/adapter-next'
|
|
26
|
+
import * as github from '@emulators/github'
|
|
27
|
+
import * as google from '@emulators/google'
|
|
28
|
+
|
|
29
|
+
export const { GET, POST, PUT, PATCH, DELETE } = createEmulateHandler({
|
|
30
|
+
services: {
|
|
31
|
+
github: {
|
|
32
|
+
emulator: github,
|
|
33
|
+
seed: {
|
|
34
|
+
users: [{ login: 'octocat', name: 'The Octocat' }],
|
|
35
|
+
repos: [{ owner: 'octocat', name: 'hello-world', auto_init: true }],
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
google: {
|
|
39
|
+
emulator: google,
|
|
40
|
+
seed: {
|
|
41
|
+
users: [{ email: 'test@example.com', name: 'Test User' }],
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
})
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Auth.js / NextAuth configuration
|
|
49
|
+
|
|
50
|
+
Point your provider at the emulator paths on the same origin:
|
|
51
|
+
|
|
52
|
+
```typescript
|
|
53
|
+
import GitHub from 'next-auth/providers/github'
|
|
54
|
+
|
|
55
|
+
const baseUrl = process.env.VERCEL_URL
|
|
56
|
+
? `https://${process.env.VERCEL_URL}`
|
|
57
|
+
: 'http://localhost:3000'
|
|
58
|
+
|
|
59
|
+
GitHub({
|
|
60
|
+
clientId: 'any-value',
|
|
61
|
+
clientSecret: 'any-value',
|
|
62
|
+
authorization: { url: `${baseUrl}/emulate/github/login/oauth/authorize` },
|
|
63
|
+
token: { url: `${baseUrl}/emulate/github/login/oauth/access_token` },
|
|
64
|
+
userinfo: { url: `${baseUrl}/emulate/github/user` },
|
|
65
|
+
})
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
No `oauth_apps` need to be seeded. When none are configured, the emulator skips `client_id`, `client_secret`, and `redirect_uri` validation.
|
|
69
|
+
|
|
70
|
+
## Font files in serverless
|
|
71
|
+
|
|
72
|
+
Emulator UI pages use bundled fonts. Wrap your Next.js config to include them in the serverless trace:
|
|
73
|
+
|
|
74
|
+
```typescript
|
|
75
|
+
// next.config.mjs
|
|
76
|
+
import { withEmulate } from '@emulators/adapter-next'
|
|
77
|
+
|
|
78
|
+
export default withEmulate({
|
|
79
|
+
// your normal Next.js config
|
|
80
|
+
})
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
If you mount the catch-all at a custom path, pass the matching prefix:
|
|
84
|
+
|
|
85
|
+
```typescript
|
|
86
|
+
export default withEmulate(nextConfig, { routePrefix: '/api/emulate' })
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Persistence
|
|
90
|
+
|
|
91
|
+
By default, emulator state is in-memory and resets on every cold start. To persist state across restarts, pass a `persistence` adapter:
|
|
92
|
+
|
|
93
|
+
```typescript
|
|
94
|
+
import { createEmulateHandler } from '@emulators/adapter-next'
|
|
95
|
+
import * as github from '@emulators/github'
|
|
96
|
+
|
|
97
|
+
const kvAdapter = {
|
|
98
|
+
async load() { return await kv.get('emulate-state') },
|
|
99
|
+
async save(data: string) { await kv.set('emulate-state', data) },
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export const { GET, POST, PUT, PATCH, DELETE } = createEmulateHandler({
|
|
103
|
+
services: { github: { emulator: github } },
|
|
104
|
+
persistence: kvAdapter,
|
|
105
|
+
})
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
For local development, `@emulators/core` ships `filePersistence`:
|
|
109
|
+
|
|
110
|
+
```typescript
|
|
111
|
+
import { filePersistence } from '@emulators/core'
|
|
112
|
+
|
|
113
|
+
// ...
|
|
114
|
+
persistence: filePersistence('.emulate/state.json'),
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Links
|
|
118
|
+
|
|
119
|
+
- [Full documentation](https://emulate.dev)
|
|
120
|
+
- [GitHub](https://github.com/vercel-labs/emulate)
|
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { ServicePlugin, Store, AppKeyResolver, PersistenceAdapter } from '@emulators/core';
|
|
1
|
+
import { ServicePlugin, Store, WebhookDispatcher, AppKeyResolver, PersistenceAdapter } from '@emulators/core';
|
|
2
2
|
export { PersistenceAdapter } from '@emulators/core';
|
|
3
3
|
|
|
4
4
|
interface EmulatorModule {
|
|
5
5
|
plugin?: ServicePlugin;
|
|
6
6
|
default?: ServicePlugin;
|
|
7
|
-
seedFromConfig?(store: Store, baseUrl: string, config: unknown): void;
|
|
7
|
+
seedFromConfig?(store: Store, baseUrl: string, config: unknown, webhooks?: WebhookDispatcher): void;
|
|
8
8
|
createAppKeyResolver?(store: Store): AppKeyResolver;
|
|
9
9
|
}
|
|
10
10
|
interface EmulatorEntry {
|
package/dist/index.js
CHANGED
|
@@ -127,14 +127,14 @@ function createEmulateHandler(config) {
|
|
|
127
127
|
const servicePrefix = `${mountPath2}/${name}`;
|
|
128
128
|
const baseUrl = `${origin}${servicePrefix}`;
|
|
129
129
|
let appKeyResolver;
|
|
130
|
-
const { app, store, tokenMap } = createServer(plugin, {
|
|
130
|
+
const { app, store, tokenMap, webhooks } = createServer(plugin, {
|
|
131
131
|
baseUrl,
|
|
132
132
|
appKeyResolver: entry.emulator.createAppKeyResolver ? (appId) => appKeyResolver(appId) : void 0
|
|
133
133
|
});
|
|
134
134
|
if (entry.emulator.createAppKeyResolver) {
|
|
135
135
|
appKeyResolver = entry.emulator.createAppKeyResolver(store);
|
|
136
136
|
}
|
|
137
|
-
serviceApps.set(name, { hono: app, store, tokenMap, plugin });
|
|
137
|
+
serviceApps.set(name, { hono: app, store, tokenMap, plugin, webhooks });
|
|
138
138
|
}
|
|
139
139
|
let restored = false;
|
|
140
140
|
if (persistence) {
|
|
@@ -155,7 +155,7 @@ function createEmulateHandler(config) {
|
|
|
155
155
|
const baseUrl = `${origin}${servicePrefix}`;
|
|
156
156
|
sa.plugin.seed?.(sa.store, baseUrl);
|
|
157
157
|
if (entry.seed && entry.emulator.seedFromConfig) {
|
|
158
|
-
entry.emulator.seedFromConfig(sa.store, baseUrl, entry.seed);
|
|
158
|
+
entry.emulator.seedFromConfig(sa.store, baseUrl, entry.seed, sa.webhooks);
|
|
159
159
|
}
|
|
160
160
|
}
|
|
161
161
|
if (persistence) {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import {\n createServer,\n debug,\n serializeTokenMap,\n restoreTokenMap,\n type ServicePlugin,\n type Store,\n type TokenMap,\n type TokenEntry,\n type StoreSnapshot,\n type PersistenceAdapter,\n type AppKeyResolver,\n} from \"@emulators/core\";\n\nexport type { PersistenceAdapter } from \"@emulators/core\";\n\nexport interface EmulatorModule {\n plugin?: ServicePlugin;\n default?: ServicePlugin;\n seedFromConfig?(store: Store, baseUrl: string, config: unknown): void;\n createAppKeyResolver?(store: Store): AppKeyResolver;\n}\n\ninterface EmulatorEntry {\n emulator: EmulatorModule;\n seed?: Record<string, unknown>;\n}\n\nexport interface EmulateHandlerConfig {\n services: Record<string, EmulatorEntry>;\n persistence?: PersistenceAdapter;\n}\n\ninterface Fetchable {\n fetch(request: Request, ...rest: unknown[]): Response | Promise<Response>;\n}\n\ninterface ServiceApp {\n hono: Fetchable;\n store: Store;\n tokenMap: TokenMap;\n plugin: ServicePlugin;\n}\n\ninterface FullSnapshot {\n store: StoreSnapshot;\n tokens: Record<string, TokenEntry[]>;\n}\n\ntype NextRequest = Request;\ntype NextResponse = Response;\ntype RouteHandler = (req: NextRequest, ctx: { params: Promise<{ path: string[] }> }) => Promise<NextResponse>;\n\nconst MUTATING_METHODS = new Set([\"POST\", \"PUT\", \"PATCH\", \"DELETE\"]);\n\nfunction resolvePlugin(mod: EmulatorModule): ServicePlugin {\n const plugin = mod.plugin ?? mod.default;\n if (!plugin) {\n throw new Error(\"Emulator module must export `plugin` or a default export implementing ServicePlugin\");\n }\n return plugin;\n}\n\nfunction takeSnapshot(apps: Map<string, ServiceApp>): FullSnapshot {\n const mergedStore: StoreSnapshot = { collections: {}, data: {} };\n const tokens: Record<string, TokenEntry[]> = {};\n\n for (const [name, sa] of apps) {\n const snap = sa.store.snapshot();\n for (const [colName, colSnap] of Object.entries(snap.collections)) {\n mergedStore.collections[`${name}:${colName}`] = colSnap;\n }\n for (const [key, val] of Object.entries(snap.data)) {\n mergedStore.data[`${name}:${key}`] = val;\n }\n tokens[name] = serializeTokenMap(sa.tokenMap);\n }\n\n return { store: mergedStore, tokens };\n}\n\nfunction restoreFromSnapshot(apps: Map<string, ServiceApp>, snapshot: FullSnapshot): void {\n const storesByName = new Map<string, StoreSnapshot>();\n for (const [qualifiedName, colSnap] of Object.entries(snapshot.store.collections)) {\n const sepIdx = qualifiedName.indexOf(\":\");\n const name = qualifiedName.slice(0, sepIdx);\n const colName = qualifiedName.slice(sepIdx + 1);\n if (!storesByName.has(name)) {\n storesByName.set(name, { collections: {}, data: {} });\n }\n storesByName.get(name)!.collections[colName] = colSnap;\n }\n for (const [qualifiedKey, val] of Object.entries(snapshot.store.data)) {\n const sepIdx = qualifiedKey.indexOf(\":\");\n const name = qualifiedKey.slice(0, sepIdx);\n const dataKey = qualifiedKey.slice(sepIdx + 1);\n if (!storesByName.has(name)) {\n storesByName.set(name, { collections: {}, data: {} });\n }\n storesByName.get(name)!.data[dataKey] = val;\n }\n\n for (const [name, sa] of apps) {\n const snap = storesByName.get(name);\n if (snap) {\n sa.store.restore(snap);\n }\n restoreTokenMap(sa.tokenMap, snapshot.tokens[name] ?? []);\n }\n}\n\nfunction detectPrefix(url: string, pathSegments: string[]): string {\n const parsed = new URL(url);\n const fullPath = parsed.pathname;\n const restPath = \"/\" + pathSegments.join(\"/\");\n const idx = fullPath.lastIndexOf(restPath);\n if (idx > 0) {\n return fullPath.slice(0, idx);\n }\n throw new Error(`Could not detect mount path from URL: ${url}`);\n}\n\nasync function rewriteResponse(response: Response, servicePrefix: string): Promise<Response> {\n const contentType = response.headers.get(\"Content-Type\") ?? \"\";\n const location = response.headers.get(\"Location\");\n const isHtml = contentType.includes(\"text/html\");\n const locationChanged = location != null && location.startsWith(\"/\");\n\n if (!isHtml) {\n if (!locationChanged) return response;\n const headers = new Headers(response.headers);\n headers.set(\"Location\", servicePrefix + location);\n return new Response(response.body, {\n status: response.status,\n statusText: response.statusText,\n headers,\n });\n }\n\n let html = await response.text();\n\n // Skip paths already carrying the service prefix to avoid double-prefixing\n // (e.g., redirects that already went through rewriting).\n html = html.replace(/(action|href)=\"(\\/[^\"]*?)\"/g, (_match, attr, path) => {\n if (path.startsWith(servicePrefix)) return `${attr}=\"${path}\"`;\n return `${attr}=\"${servicePrefix}${path}\"`;\n });\n\n html = html.replace(/url\\('(\\/[^']*?)'\\)/g, (_match, path) => {\n if (path.startsWith(servicePrefix)) return `url('${path}')`;\n return `url('${servicePrefix}${path}')`;\n });\n\n const headers = new Headers(response.headers);\n if (locationChanged) {\n headers.set(\"Location\", servicePrefix + location);\n }\n headers.delete(\"Content-Length\");\n\n return new Response(html, {\n status: response.status,\n statusText: response.statusText,\n headers,\n });\n}\n\nexport function createEmulateHandler(config: EmulateHandlerConfig) {\n const { services: serviceEntries, persistence } = config;\n\n let apps: Map<string, ServiceApp> | null = null;\n let mountPath: string | null = null;\n let initPromise: Promise<void> | null = null;\n let pendingSave: Promise<void> = Promise.resolve();\n\n function enqueueSave(): void {\n if (!persistence || !apps) return;\n pendingSave = pendingSave.then(async () => {\n if (!apps) return;\n const snapshot = takeSnapshot(apps);\n const json = JSON.stringify(snapshot);\n try {\n await persistence.save(json);\n } catch (err) {\n debug(\"persistence\", \"save failed: %o\", err);\n }\n });\n }\n\n async function initApps(origin: string, mountPath: string): Promise<Map<string, ServiceApp>> {\n const serviceApps = new Map<string, ServiceApp>();\n\n for (const [name, entry] of Object.entries(serviceEntries)) {\n const plugin = resolvePlugin(entry.emulator);\n const servicePrefix = `${mountPath}/${name}`;\n const baseUrl = `${origin}${servicePrefix}`;\n\n let appKeyResolver: AppKeyResolver | undefined;\n const { app, store, tokenMap } = createServer(plugin, {\n baseUrl,\n appKeyResolver: entry.emulator.createAppKeyResolver\n ? (appId) => appKeyResolver!(appId)\n : undefined,\n });\n\n if (entry.emulator.createAppKeyResolver) {\n appKeyResolver = entry.emulator.createAppKeyResolver(store);\n }\n\n serviceApps.set(name, { hono: app, store, tokenMap, plugin });\n }\n\n let restored = false;\n if (persistence) {\n const raw = await persistence.load();\n if (raw) {\n try {\n const snapshot = JSON.parse(raw) as FullSnapshot;\n restoreFromSnapshot(serviceApps, snapshot);\n restored = true;\n } catch {\n // Corrupted data, fall through to seeding\n }\n }\n }\n\n if (!restored) {\n for (const [name, entry] of Object.entries(serviceEntries)) {\n const sa = serviceApps.get(name)!;\n const servicePrefix = `${mountPath}/${name}`;\n const baseUrl = `${origin}${servicePrefix}`;\n sa.plugin.seed?.(sa.store, baseUrl);\n if (entry.seed && entry.emulator.seedFromConfig) {\n entry.emulator.seedFromConfig(sa.store, baseUrl, entry.seed);\n }\n }\n if (persistence) {\n enqueueSave();\n }\n }\n\n return serviceApps;\n }\n\n async function ensureInit(req: Request, pathSegments: string[]): Promise<Map<string, ServiceApp>> {\n if (apps) return apps;\n if (!initPromise) {\n const url = new URL(req.url);\n const origin = url.origin;\n mountPath = detectPrefix(req.url, pathSegments);\n initPromise = initApps(origin, mountPath).then((result) => {\n apps = result;\n });\n }\n await initPromise;\n return apps!;\n }\n\n async function handleRequest(req: NextRequest, ctx: { params: Promise<{ path: string[] }> }): Promise<NextResponse> {\n const { path: pathSegments } = await ctx.params;\n const serviceApps = await ensureInit(req, pathSegments);\n\n if (pathSegments.length === 0) {\n return new Response(\"Not found\", { status: 404 });\n }\n\n const serviceName = pathSegments[0];\n const sa = serviceApps.get(serviceName);\n if (!sa) {\n return new Response(`Unknown service: ${serviceName}`, { status: 404 });\n }\n\n const restPath = \"/\" + pathSegments.slice(1).join(\"/\");\n const url = new URL(req.url);\n const strippedUrl = new URL(restPath + url.search, url.origin);\n\n const strippedReq = new Request(strippedUrl.toString(), {\n method: req.method,\n headers: req.headers,\n body: req.body,\n duplex: \"half\",\n } as RequestInit & { duplex: string });\n\n let response = await sa.hono.fetch(strippedReq);\n\n const servicePrefix = `${mountPath!}/${serviceName}`;\n response = await rewriteResponse(response, servicePrefix);\n\n if (persistence && MUTATING_METHODS.has(req.method)) {\n enqueueSave();\n }\n\n return response;\n }\n\n const handler: RouteHandler = handleRequest;\n\n return {\n GET: handler,\n POST: handler,\n PUT: handler,\n PATCH: handler,\n DELETE: handler,\n };\n}\n\nexport function withEmulate<T>(nextConfig: T, options?: { routePrefix?: string }): T {\n const config = nextConfig as Record<string, unknown>;\n const prefix = options?.routePrefix ?? \"/emulate\";\n const routePattern = `${prefix}/**`;\n const fontGlob = \"./node_modules/@emulators/core/dist/fonts/**\";\n\n const topLevel = { ...((config.outputFileTracingIncludes as Record<string, string[]> | undefined) ?? {}) };\n const existing = topLevel[routePattern] ?? [];\n if (!existing.includes(fontGlob)) {\n topLevel[routePattern] = [...existing, fontGlob];\n }\n\n return { ...config, outputFileTracingIncludes: topLevel } as T;\n}\n"],"mappings":"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","names":["headers","mountPath"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import {\n createServer,\n debug,\n serializeTokenMap,\n restoreTokenMap,\n type ServicePlugin,\n type Store,\n type TokenMap,\n type TokenEntry,\n type StoreSnapshot,\n type PersistenceAdapter,\n type AppKeyResolver,\n type WebhookDispatcher,\n} from \"@emulators/core\";\n\nexport type { PersistenceAdapter } from \"@emulators/core\";\n\nexport interface EmulatorModule {\n plugin?: ServicePlugin;\n default?: ServicePlugin;\n seedFromConfig?(store: Store, baseUrl: string, config: unknown, webhooks?: WebhookDispatcher): void;\n createAppKeyResolver?(store: Store): AppKeyResolver;\n}\n\ninterface EmulatorEntry {\n emulator: EmulatorModule;\n seed?: Record<string, unknown>;\n}\n\nexport interface EmulateHandlerConfig {\n services: Record<string, EmulatorEntry>;\n persistence?: PersistenceAdapter;\n}\n\ninterface Fetchable {\n fetch(request: Request, ...rest: unknown[]): Response | Promise<Response>;\n}\n\ninterface ServiceApp {\n hono: Fetchable;\n store: Store;\n tokenMap: TokenMap;\n plugin: ServicePlugin;\n webhooks: WebhookDispatcher;\n}\n\ninterface FullSnapshot {\n store: StoreSnapshot;\n tokens: Record<string, TokenEntry[]>;\n}\n\ntype NextRequest = Request;\ntype NextResponse = Response;\ntype RouteHandler = (req: NextRequest, ctx: { params: Promise<{ path: string[] }> }) => Promise<NextResponse>;\n\nconst MUTATING_METHODS = new Set([\"POST\", \"PUT\", \"PATCH\", \"DELETE\"]);\n\nfunction resolvePlugin(mod: EmulatorModule): ServicePlugin {\n const plugin = mod.plugin ?? mod.default;\n if (!plugin) {\n throw new Error(\"Emulator module must export `plugin` or a default export implementing ServicePlugin\");\n }\n return plugin;\n}\n\nfunction takeSnapshot(apps: Map<string, ServiceApp>): FullSnapshot {\n const mergedStore: StoreSnapshot = { collections: {}, data: {} };\n const tokens: Record<string, TokenEntry[]> = {};\n\n for (const [name, sa] of apps) {\n const snap = sa.store.snapshot();\n for (const [colName, colSnap] of Object.entries(snap.collections)) {\n mergedStore.collections[`${name}:${colName}`] = colSnap;\n }\n for (const [key, val] of Object.entries(snap.data)) {\n mergedStore.data[`${name}:${key}`] = val;\n }\n tokens[name] = serializeTokenMap(sa.tokenMap);\n }\n\n return { store: mergedStore, tokens };\n}\n\nfunction restoreFromSnapshot(apps: Map<string, ServiceApp>, snapshot: FullSnapshot): void {\n const storesByName = new Map<string, StoreSnapshot>();\n for (const [qualifiedName, colSnap] of Object.entries(snapshot.store.collections)) {\n const sepIdx = qualifiedName.indexOf(\":\");\n const name = qualifiedName.slice(0, sepIdx);\n const colName = qualifiedName.slice(sepIdx + 1);\n if (!storesByName.has(name)) {\n storesByName.set(name, { collections: {}, data: {} });\n }\n storesByName.get(name)!.collections[colName] = colSnap;\n }\n for (const [qualifiedKey, val] of Object.entries(snapshot.store.data)) {\n const sepIdx = qualifiedKey.indexOf(\":\");\n const name = qualifiedKey.slice(0, sepIdx);\n const dataKey = qualifiedKey.slice(sepIdx + 1);\n if (!storesByName.has(name)) {\n storesByName.set(name, { collections: {}, data: {} });\n }\n storesByName.get(name)!.data[dataKey] = val;\n }\n\n for (const [name, sa] of apps) {\n const snap = storesByName.get(name);\n if (snap) {\n sa.store.restore(snap);\n }\n restoreTokenMap(sa.tokenMap, snapshot.tokens[name] ?? []);\n }\n}\n\nfunction detectPrefix(url: string, pathSegments: string[]): string {\n const parsed = new URL(url);\n const fullPath = parsed.pathname;\n const restPath = \"/\" + pathSegments.join(\"/\");\n const idx = fullPath.lastIndexOf(restPath);\n if (idx > 0) {\n return fullPath.slice(0, idx);\n }\n throw new Error(`Could not detect mount path from URL: ${url}`);\n}\n\nasync function rewriteResponse(response: Response, servicePrefix: string): Promise<Response> {\n const contentType = response.headers.get(\"Content-Type\") ?? \"\";\n const location = response.headers.get(\"Location\");\n const isHtml = contentType.includes(\"text/html\");\n const locationChanged = location != null && location.startsWith(\"/\");\n\n if (!isHtml) {\n if (!locationChanged) return response;\n const headers = new Headers(response.headers);\n headers.set(\"Location\", servicePrefix + location);\n return new Response(response.body, {\n status: response.status,\n statusText: response.statusText,\n headers,\n });\n }\n\n let html = await response.text();\n\n // Skip paths already carrying the service prefix to avoid double-prefixing\n // (e.g., redirects that already went through rewriting).\n html = html.replace(/(action|href)=\"(\\/[^\"]*?)\"/g, (_match, attr, path) => {\n if (path.startsWith(servicePrefix)) return `${attr}=\"${path}\"`;\n return `${attr}=\"${servicePrefix}${path}\"`;\n });\n\n html = html.replace(/url\\('(\\/[^']*?)'\\)/g, (_match, path) => {\n if (path.startsWith(servicePrefix)) return `url('${path}')`;\n return `url('${servicePrefix}${path}')`;\n });\n\n const headers = new Headers(response.headers);\n if (locationChanged) {\n headers.set(\"Location\", servicePrefix + location);\n }\n headers.delete(\"Content-Length\");\n\n return new Response(html, {\n status: response.status,\n statusText: response.statusText,\n headers,\n });\n}\n\nexport function createEmulateHandler(config: EmulateHandlerConfig) {\n const { services: serviceEntries, persistence } = config;\n\n let apps: Map<string, ServiceApp> | null = null;\n let mountPath: string | null = null;\n let initPromise: Promise<void> | null = null;\n let pendingSave: Promise<void> = Promise.resolve();\n\n function enqueueSave(): void {\n if (!persistence || !apps) return;\n pendingSave = pendingSave.then(async () => {\n if (!apps) return;\n const snapshot = takeSnapshot(apps);\n const json = JSON.stringify(snapshot);\n try {\n await persistence.save(json);\n } catch (err) {\n debug(\"persistence\", \"save failed: %o\", err);\n }\n });\n }\n\n async function initApps(origin: string, mountPath: string): Promise<Map<string, ServiceApp>> {\n const serviceApps = new Map<string, ServiceApp>();\n\n for (const [name, entry] of Object.entries(serviceEntries)) {\n const plugin = resolvePlugin(entry.emulator);\n const servicePrefix = `${mountPath}/${name}`;\n const baseUrl = `${origin}${servicePrefix}`;\n\n let appKeyResolver: AppKeyResolver | undefined;\n const { app, store, tokenMap, webhooks } = createServer(plugin, {\n baseUrl,\n appKeyResolver: entry.emulator.createAppKeyResolver ? (appId) => appKeyResolver!(appId) : undefined,\n });\n\n if (entry.emulator.createAppKeyResolver) {\n appKeyResolver = entry.emulator.createAppKeyResolver(store);\n }\n\n serviceApps.set(name, { hono: app, store, tokenMap, plugin, webhooks });\n }\n\n let restored = false;\n if (persistence) {\n const raw = await persistence.load();\n if (raw) {\n try {\n const snapshot = JSON.parse(raw) as FullSnapshot;\n restoreFromSnapshot(serviceApps, snapshot);\n restored = true;\n } catch {\n // Corrupted data, fall through to seeding\n }\n }\n }\n\n if (!restored) {\n for (const [name, entry] of Object.entries(serviceEntries)) {\n const sa = serviceApps.get(name)!;\n const servicePrefix = `${mountPath}/${name}`;\n const baseUrl = `${origin}${servicePrefix}`;\n sa.plugin.seed?.(sa.store, baseUrl);\n if (entry.seed && entry.emulator.seedFromConfig) {\n entry.emulator.seedFromConfig(sa.store, baseUrl, entry.seed, sa.webhooks);\n }\n }\n if (persistence) {\n enqueueSave();\n }\n }\n\n return serviceApps;\n }\n\n async function ensureInit(req: Request, pathSegments: string[]): Promise<Map<string, ServiceApp>> {\n if (apps) return apps;\n if (!initPromise) {\n const url = new URL(req.url);\n const origin = url.origin;\n mountPath = detectPrefix(req.url, pathSegments);\n initPromise = initApps(origin, mountPath).then((result) => {\n apps = result;\n });\n }\n await initPromise;\n return apps!;\n }\n\n async function handleRequest(req: NextRequest, ctx: { params: Promise<{ path: string[] }> }): Promise<NextResponse> {\n const { path: pathSegments } = await ctx.params;\n const serviceApps = await ensureInit(req, pathSegments);\n\n if (pathSegments.length === 0) {\n return new Response(\"Not found\", { status: 404 });\n }\n\n const serviceName = pathSegments[0];\n const sa = serviceApps.get(serviceName);\n if (!sa) {\n return new Response(`Unknown service: ${serviceName}`, { status: 404 });\n }\n\n const restPath = \"/\" + pathSegments.slice(1).join(\"/\");\n const url = new URL(req.url);\n const strippedUrl = new URL(restPath + url.search, url.origin);\n\n const strippedReq = new Request(strippedUrl.toString(), {\n method: req.method,\n headers: req.headers,\n body: req.body,\n duplex: \"half\",\n } as RequestInit & { duplex: string });\n\n let response = await sa.hono.fetch(strippedReq);\n\n const servicePrefix = `${mountPath!}/${serviceName}`;\n response = await rewriteResponse(response, servicePrefix);\n\n if (persistence && MUTATING_METHODS.has(req.method)) {\n enqueueSave();\n }\n\n return response;\n }\n\n const handler: RouteHandler = handleRequest;\n\n return {\n GET: handler,\n POST: handler,\n PUT: handler,\n PATCH: handler,\n DELETE: handler,\n };\n}\n\nexport function withEmulate<T>(nextConfig: T, options?: { routePrefix?: string }): T {\n const config = nextConfig as Record<string, unknown>;\n const prefix = options?.routePrefix ?? \"/emulate\";\n const routePattern = `${prefix}/**`;\n const fontGlob = \"./node_modules/@emulators/core/dist/fonts/**\";\n\n const topLevel = { ...((config.outputFileTracingIncludes as Record<string, string[]> | undefined) ?? {}) };\n const existing = topLevel[routePattern] ?? [];\n if (!existing.includes(fontGlob)) {\n topLevel[routePattern] = [...existing, fontGlob];\n }\n\n return { ...config, outputFileTracingIncludes: topLevel } as T;\n}\n"],"mappings":"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","names":["headers","mountPath"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@emulators/adapter-next",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"dist"
|
|
29
29
|
],
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@emulators/core": "0.
|
|
31
|
+
"@emulators/core": "0.5.0"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
34
|
"tsup": "^8",
|
|
@@ -37,6 +37,8 @@
|
|
|
37
37
|
"scripts": {
|
|
38
38
|
"build": "tsup --clean",
|
|
39
39
|
"dev": "tsup --watch",
|
|
40
|
-
"clean": "rm -rf dist .turbo"
|
|
40
|
+
"clean": "rm -rf dist .turbo",
|
|
41
|
+
"type-check": "tsc --noEmit",
|
|
42
|
+
"lint": "eslint src"
|
|
41
43
|
}
|
|
42
44
|
}
|