import { Layer } from "effect";import { toApiHandler } from "@executor-js/api/server";import { RequestScopedServicesLive } from "./api/request-scoped";import { CoreSharedServices } from "./auth/workos";import { makeOrgRoutes, makeSessionRoutes } from "./extensions/session-routes";import { ApiErrorLoggingLive } from "./observability/error-logging";import { WorkerTelemetryLive } from "./observability/telemetry";// ===========================================================================// The Executor cloud AUTH plane — the session/auth surface on its own handler.//// Why a second handler instead of a lazier `./app`: Effect's `HttpApiBuilder`// registers every group into one router at layer-BUILD time, so the first// `/api/*` request that reaches `ExecutorApp.make`'s handler evaluates the// whole composition — plugin + OpenAPI + MCP + GraphQL catalogs, the execution// substrate (@babel/parser, sucrase), Swagger. A lazy split inside a single// `HttpApi` is not expressible. The seam that IS expressible is the worker// entry, where `servedByAppPlane` (./app-paths) already decides which paths// skip TanStack Start — so `servedByAuthPlane` names the session routes and// `server.ts` dispatches them here first.//// Measured on production 2026-09-18 for `/api/*` on the app plane: warm p50// ~120ms, cold p50 ~2.2s, ~31% of requests cold. `POST /api/auth/logout` is// the user-visible victim — the console posts it as a top-level form// navigation, so the cold wait is a blank page.//// What makes the two planes agree on the wire: they mount the SAME Layer// values. `makeSessionRoutes` / `makeOrgRoutes` (./extensions/session-routes)// are the exact constructors `makeCloudExtensionRoutes` feeds to// `ExecutorApp.make`, on the same `/api`-prefixed router view, over the same// `RequestScopedServicesLive`. Nothing is re-derived here.//// What this plane deliberately does NOT carry, because these routes never read// it: the protected (plugin) API and its execution-stack middleware, the// neutral `IdentityProvider` + `cloudIdentityFailureStrategy` (session routes// authenticate through `SessionAuth`, whose `Unauthorized` is rendered by the// HttpApi machinery, not by the identity failure strategy), the MCP envelope,// Swagger/OpenAPI, the billing proxy, the admin plane, and the WorkOS webhook.// `ErrorCapture` is absent for the same reason — no route here resolves that// tag (`captureCauseEffect` is a plain Effect and needs no service).//// `HttpMiddleware.tracer`'s `http.server` span still opens per request:// `toApiHandler` -> `HttpRouter.toWebHandler` installs it exactly as it does// for `./app`, so an auth-plane request traces like an app-plane one.// ===========================================================================// Boot-scoped context, the auth-plane subset of `./app`'s `boot`: the raw// WorkOS SDK client the session handlers and `SessionAuthLive` read, plus the// worker tracer. No api-key service (no Bearer plane here), no `AutumnService`// on the core — `makeSessionRoutes` provide-merges its own, exactly as it does// inside the full app. `HttpServer.layerServices` is supplied by// `toApiHandler`. A boot-time WorkOS misconfig is unrecoverable -> `orDie`.const authBoot = Layer.merge(CoreSharedServices, WorkerTelemetryLive).pipe( // oxlint-disable-next-line executor/no-effect-escape-hatch -- boundary: a boot-time WorkOS misconfiguration is unrecoverable Layer.orDie,);const AuthPlaneLayer = Layer.mergeAll( makeSessionRoutes(RequestScopedServicesLive), makeOrgRoutes(RequestScopedServicesLive), // The same global request-failure logging the app plane mounts, so a failing // session route logs identically on either plane. ApiErrorLoggingLive,).pipe(Layer.provideMerge(authBoot));/** * The auth-plane web handler: serves exactly the paths `servedByAuthPlane` * (./app-paths) names — `/api/auth/*`, `/api/org/domains*`, and the MCP * approval endpoints. Everything else under `/api` stays on `./app`. */export const cloudAuthHandler = () => toApiHandler(AuthPlaneLayer);
import { Layer } from "effect";
import { toApiHandler } from "@executor-js/api/server";
import { RequestScopedServicesLive } from "./api/request-scoped";
import { CoreSharedServices } from "./auth/workos";
import { makeOrgRoutes, makeSessionRoutes } from "./extensions/session-routes";
import { ApiErrorLoggingLive } from "./observability/error-logging";
import { WorkerTelemetryLive } from "./observability/telemetry";
// ===========================================================================
// The Executor cloud AUTH plane — the session/auth surface on its own handler.
//
// Why a second handler instead of a lazier `./app`: Effect's `HttpApiBuilder`
// registers every group into one router at layer-BUILD time, so the first
// `/api/*` request that reaches `ExecutorApp.make`'s handler evaluates the
// whole composition — plugin + OpenAPI + MCP + GraphQL catalogs, the execution
// substrate (@babel/parser, sucrase), Swagger. A lazy split inside a single
// `HttpApi` is not expressible. The seam that IS expressible is the worker
// entry, where `servedByAppPlane` (./app-paths) already decides which paths
// skip TanStack Start — so `servedByAuthPlane` names the session routes and
// `server.ts` dispatches them here first.
//
// Measured on production 2026-09-18 for `/api/*` on the app plane: warm p50
// ~120ms, cold p50 ~2.2s, ~31% of requests cold. `POST /api/auth/logout` is
// the user-visible victim — the console posts it as a top-level form
// navigation, so the cold wait is a blank page.
//
// What makes the two planes agree on the wire: they mount the SAME Layer
// values. `makeSessionRoutes` / `makeOrgRoutes` (./extensions/session-routes)
// are the exact constructors `makeCloudExtensionRoutes` feeds to
// `ExecutorApp.make`, on the same `/api`-prefixed router view, over the same
// `RequestScopedServicesLive`. Nothing is re-derived here.
//
// What this plane deliberately does NOT carry, because these routes never read
// it: the protected (plugin) API and its execution-stack middleware, the
// neutral `IdentityProvider` + `cloudIdentityFailureStrategy` (session routes
// authenticate through `SessionAuth`, whose `Unauthorized` is rendered by the
// HttpApi machinery, not by the identity failure strategy), the MCP envelope,
// Swagger/OpenAPI, the billing proxy, the admin plane, and the WorkOS webhook.
// `ErrorCapture` is absent for the same reason — no route here resolves that
// tag (`captureCauseEffect` is a plain Effect and needs no service).
//
// `HttpMiddleware.tracer`'s `http.server` span still opens per request:
// `toApiHandler` -> `HttpRouter.toWebHandler` installs it exactly as it does
// for `./app`, so an auth-plane request traces like an app-plane one.
// ===========================================================================
// Boot-scoped context, the auth-plane subset of `./app`'s `boot`: the raw
// WorkOS SDK client the session handlers and `SessionAuthLive` read, plus the
// worker tracer. No api-key service (no Bearer plane here), no `AutumnService`
// on the core — `makeSessionRoutes` provide-merges its own, exactly as it does
// inside the full app. `HttpServer.layerServices` is supplied by
// `toApiHandler`. A boot-time WorkOS misconfig is unrecoverable -> `orDie`.
const authBoot = Layer.merge(CoreSharedServices, WorkerTelemetryLive).pipe(
// oxlint-disable-next-line executor/no-effect-escape-hatch -- boundary: a boot-time WorkOS misconfiguration is unrecoverable
Layer.orDie,
);
const AuthPlaneLayer = Layer.mergeAll(
makeSessionRoutes(RequestScopedServicesLive),
makeOrgRoutes(RequestScopedServicesLive),
// The same global request-failure logging the app plane mounts, so a failing
// session route logs identically on either plane.
ApiErrorLoggingLive,
).pipe(Layer.provideMerge(authBoot));
/**
* The auth-plane web handler: serves exactly the paths `servedByAuthPlane`
* (./app-paths) names — `/api/auth/*`, `/api/org/domains*`, and the MCP
* approval endpoints. Everything else under `/api` stays on `./app`.
*/
export const cloudAuthHandler = () => toApiHandler(AuthPlaneLayer);