(options: CloudBootOptions)
| 49 | } |
| 50 | |
| 51 | export const bootCloud = async (options: CloudBootOptions): Promise<CloudBooted> => { |
| 52 | // Fresh dev DB per boot — the WorkOS emulator mints org ids from a |
| 53 | // per-process counter, so a persisted DB from a previous invocation |
| 54 | // collides with the new boot's ids (identities land in polluted orgs / |
| 55 | // org creation 500s). |
| 56 | const dbPath = resolve(cloudDir, ".e2e-stub-db"); |
| 57 | if (options.fresh ?? true) rmSync(dbPath, { recursive: true, force: true }); |
| 58 | |
| 59 | // MCP access tokens minted by the emulator's OAuth server must carry the |
| 60 | // app's client id as audience (what the resource server verifies). |
| 61 | process.env.EMULATE_WORKOS_AUDIENCE = options.workosClientId; |
| 62 | const workos = await createEmulator({ |
| 63 | service: "workos", |
| 64 | port: options.workosPort, |
| 65 | ...(options.workosPublicUrl ? { baseUrl: options.workosPublicUrl } : {}), |
| 66 | }); |
| 67 | const autumn = await createEmulator({ |
| 68 | service: "autumn", |
| 69 | port: options.autumnPort, |
| 70 | // Seed the plan catalog so the billing UI (plans, eligibility, trial |
| 71 | // checkout) has real plans to render. Derived from autumn.config.ts. |
| 72 | seed: { autumn: { plans: AUTUMN_PLAN_SEED } }, |
| 73 | }); |
| 74 | |
| 75 | const workosUrl = options.workosPublicUrl ?? workos.url; |
| 76 | const env = { |
| 77 | // Real client, emulated service. The app derives the browser-facing |
| 78 | // authorize URL from WORKOS_API_URL, so it must be the PUBLIC origin. |
| 79 | WORKOS_API_URL: workosUrl, |
| 80 | AUTUMN_API_URL: autumn.url, |
| 81 | WORKOS_API_KEY: "sk_test_emulate", |
| 82 | WORKOS_CLIENT_ID: options.workosClientId, |
| 83 | WORKOS_COOKIE_PASSWORD: options.cookiePassword, |
| 84 | AUTUMN_SECRET_KEY: "am_test_emulate", |
| 85 | ENCRYPTION_KEY: "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", |
| 86 | DATABASE_URL: `postgresql://postgres:postgres@127.0.0.1:${options.dbPort}/postgres`, |
| 87 | EXECUTOR_DIRECT_DATABASE_URL: "true", |
| 88 | CLOUDFLARE_INCLUDE_PROCESS_ENV: "true", |
| 89 | VITE_PUBLIC_SITE_URL: options.publicUrl, |
| 90 | // The AuthKit domain (MCP OAuth metadata + JWKS) is the emulator too. |
| 91 | MCP_AUTHKIT_DOMAIN: workosUrl, |
| 92 | MCP_RESOURCE_ORIGIN: options.publicUrl, |
| 93 | MCP_SESSION_TIMEOUT_MS: process.env.MCP_SESSION_TIMEOUT_MS, |
| 94 | MCP_PAUSED_SESSION_IDLE_TIMEOUT_MS: process.env.MCP_PAUSED_SESSION_IDLE_TIMEOUT_MS, |
| 95 | ALLOW_LOCAL_NETWORK: "true", |
| 96 | // Shrink the per-org hourly execution cap (prod default 1000) to a number |
| 97 | // the rate-limit-backstop scenario can actually exhaust with real |
| 98 | // executions — but see execution-limits.ts: it must stay above every other |
| 99 | // scenario's per-org execute count. Reaches the worker via |
| 100 | // CLOUDFLARE_INCLUDE_PROCESS_ENV, same as ALLOW_LOCAL_NETWORK. |
| 101 | EXECUTION_RATE_LIMIT_PER_HOUR: String(E2E_EXECUTION_RATE_LIMIT), |
| 102 | // Throwaway PGlite on its own port + dir so it never fights `bun dev`. |
| 103 | DEV_DB_PORT: String(options.dbPort), |
| 104 | DEV_DB_PATH: dbPath, |
| 105 | // Vite rejects unknown Host headers; allow the public hostname when a |
| 106 | // proxy fronts the app. |
| 107 | __VITE_ADDITIONAL_SERVER_ALLOWED_HOSTS: new URL(options.publicUrl).hostname, |
| 108 | ...options.extraEnv, |
no test coverage detected