(server)
| 74 | return { |
| 75 | name: "executor-api", |
| 76 | configureServer(server) { |
| 77 | devToken ??= loadOrMintLocalAuthToken(); |
| 78 | |
| 79 | // Print the bootstrap URL when vite is the front (plain `bun run dev`). |
| 80 | // When the CLI daemon spawns vite as a child (EXECUTOR_DEV_VITE_PORT set), |
| 81 | // the daemon prints its own `?_token=` URL and the app is loaded from the |
| 82 | // daemon port, so we stay quiet to avoid two conflicting URLs. |
| 83 | if (!process.env.EXECUTOR_DEV_VITE_PORT) { |
| 84 | server.httpServer?.once("listening", () => { |
| 85 | const address = server.httpServer?.address(); |
| 86 | const port = |
| 87 | typeof address === "object" && address ? address.port : server.config.server.port; |
| 88 | server.config.logger.info( |
| 89 | `\n Open with auth: http://127.0.0.1:${port}/?_token=${devToken}\n`, |
| 90 | ); |
| 91 | }); |
| 92 | } |
| 93 | |
| 94 | server.watcher.on("change", (path) => { |
| 95 | if (path.includes("/apps/local/src/") || path.endsWith("/executor.config.ts")) { |
| 96 | handlers = null; |
| 97 | } |
| 98 | }); |
| 99 | server.middlewares.use(async (req, res, next) => { |
| 100 | const rawUrl = req.url ?? "/"; |
| 101 | const pathOnly = rawUrl.split("?")[0] ?? "/"; |
| 102 | const isApi = pathOnly.startsWith("/api/") || pathOnly === "/api"; |
| 103 | const isMcp = pathOnly === "/mcp" || pathOnly.startsWith("/mcp/"); |
| 104 | // App-level routes the Effect app serves at root, outside the `/api` |
| 105 | // prefix (e.g. `/v1/app/npm/dist-tags`, the update-check the web shell |
| 106 | // fetches). Public, like `/api/health` below. |
| 107 | const isV1 = pathOnly === "/v1" || pathOnly.startsWith("/v1/"); |
| 108 | |
| 109 | if (!isApi && !isMcp && !isV1) return next(); |
| 110 | |
| 111 | // Gate parity with the production Bun shell (serve.ts): the vite server |
| 112 | // is reachable by any local process, so /api and /mcp require the bearer |
| 113 | // here too — otherwise /mcp would be unauthenticated arbitrary code |
| 114 | // execution in dev. Exempt the health probe and the state-gated OAuth |
| 115 | // callback. The SPA carries the token from its `?_token`/localStorage |
| 116 | // bootstrap, so the UI is unaffected; external MCP clients use the |
| 117 | // daemon port. |
| 118 | const authExempt = |
| 119 | pathOnly === "/api/health" || isV1 || isUnauthenticatedOAuthPath(pathOnly); |
| 120 | if (!authExempt) { |
| 121 | const presented = req.headers.authorization; |
| 122 | const authValue = Array.isArray(presented) ? presented[0] : presented; |
| 123 | const probe = new Request( |
| 124 | "http://localhost/", |
| 125 | authValue ? { headers: { authorization: authValue } } : undefined, |
| 126 | ); |
| 127 | if (!makeIsAuthorized(devToken ?? loadOrMintLocalAuthToken())(probe)) { |
| 128 | res.statusCode = 401; |
| 129 | res.setHeader("www-authenticate", 'Bearer realm="executor"'); |
| 130 | res.end("Unauthorized"); |
| 131 | return; |
| 132 | } |
| 133 | } |
nothing calls this directly
no test coverage detected