Skip to content

Serve cloud session routes from a separate auth plane - #2067

Draft
RhysSullivan wants to merge 3 commits into
mainfrom
auth-plane
Draft

RhysSullivan wants to merge 3 commits into
mainfrom
auth-plane

Conversation

@RhysSullivan

Copy link
Copy Markdown
Collaborator

Every /api/* request goes through getAppPlane() in apps/cloud/src/server.ts,
which dynamically imports ./app — the full ExecutorApp.make composition
(plugin/OpenAPI/MCP/GraphQL catalogs, the execution substrate, Swagger, billing).
HttpApiBuilder registers every group into one router at layer-build time, so a
lazy split inside the single HttpApi is not expressible. The seam that is
expressible is the worker entry, where servedByAppPlane already lives.

This adds a second, small plane for the session/auth surface.

Evaluated module closures (scripts/start-closure.mjs)

closure before after
startup 6.08 MB 6.08 MB
page request (startup + start) 9.86 MB 9.87 MB
API request (startup + app) 9.84 MB 9.85 MB
auth request (startup + auth) 6.13 MB (+0.05 MB over startup)

A sign-out on a cold isolate now evaluates 0.05 MB of plane code instead of the
app plane's 3.77 MB.

Remaining in the auth closure beyond startup: error-logging (31 KB), the auth
API schemas (6 KB), last-org-cookie (6 KB), the billing plans predicates
(2 KB), app-auth itself (1 KB).

Routes moved to the auth plane

  • GET /api/auth/login, POST /api/auth/logout, GET /api/auth/callback,
    GET /api/auth/cli-login
  • GET /api/auth/me, GET /api/auth/organizations,
    GET /api/auth/pending-invitations, POST /api/auth/accept-invitation
  • POST /api/auth/create-organization, POST /api/auth/delete-organization
  • GET/POST /api/mcp-sessions/:mcpSessionId/executions/:executionId[/resume]
  • GET /api/org/domains, POST /api/org/domains/verify-link,
    DELETE /api/org/domains/:domainId

Everything else under /api still goes to the app plane. servedByAuthPlane is
an exact allowlist, gated on servedByAppPlane, with unit tests in
app-paths.test.ts.

Why create-organization and the MCP approval endpoints stayed

The plan was to move them to the full plane so the auth plane would not pull
autumn-js or the MCP module. Neither pays off:

  • AutumnService is not reachable only from createOrganization. The login
    callback reconciles the landed org's billed seat count on every sign-in
    (forkReportMemberSeats), so the seam is on the most important auth route
    there is. Splitting the group would have moved the endpoint without removing
    the dependency.
  • @executor-js/cloudflare/mcp/session-stub is a typed RPC accessor plus one
    name helper from execution-owner-directory, which server.ts already
    imports statically for the DO export. It is in the startup closure either way.

Both are visible in the measured 0.05 MB, so keeping them cost effectively
nothing and avoided splitting an HttpApiGroup.

Shape

  • apps/cloud/src/extensions/session-routes.tsmakeSessionRoutes /
    makeOrgRoutes / apiPrefixedRouter, lifted out of extensions/routes.ts.
    Both planes mount the same Layer values, so handlers, middleware order, prefix
    and error rendering cannot drift apart.
  • apps/cloud/src/api/request-scoped.tsRequestScopedServicesLive, lifted out
    of api/layers.ts so depending on the per-request socket no longer drags in
    the protected plugin API. api/layers.ts re-exports it.
  • apps/cloud/src/app-auth.ts — the plane: those two route layers plus
    ApiErrorLoggingLive over CoreSharedServices + WorkerTelemetryLive, bound
    with toApiHandler (so HttpMiddleware.tracer opens the same http.server
    span).
  • server.ts — a memoized getAuthPlane() beside getAppPlane(), dispatched
    first; executor.dispatch.plane gains the value auth and
    executor.auth_graph.entered mirrors app_graph.entered. The edit is confined
    to those two spots.

Not included

/.well-known/* OAuth discovery still routes through TanStack Start. Serving it
from the auth plane means re-declaring the MCP auth seam's discovery routes
(org-pinned resource ids, toolkit slugs) outside cloudMcpAuth, which is a real
divergence risk for MCP client discovery and is not on the sign-out path.

Verified

  • bun run --cwd apps/cloud typecheck — clean.
  • vitest run src/auth src/app-paths.test.ts src/api.request-scope.node.test.ts
    250 passed.
  • e2e against the cloud target (the vite dev worker, so the real server.ts
    dispatch): cloud/logout-stale-session, cloud/auth-session,
    cloud/org-limit, cloud/org-switcher, cloud/surface-reachability,
    cloud/mcp-browser-approval-org-scope — all passed.
  • oxlint + oxfmt clean on the changed files. Not deployed.

RhysSullivan and others added 2 commits September 18, 2026 12:41
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Sep 18, 2026

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Updated (UTC)
✅ Deployment successful!
View logs
executor-cloud ae0d45f Sep 18 2026, 07:48 PM

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Sep 18, 2026

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
executor-marketing ae0d45f Commit Preview URL

Branch Preview URL
Sep 18 2026, 07:48 PM

@github-actions

github-actions Bot commented Sep 18, 2026

Copy link
Copy Markdown
Contributor

Cloudflare preview

Console https://executor-preview-pr-2067.executor-e2e.workers.dev
MCP https://executor-preview-pr-2067.executor-e2e.workers.dev/mcp
Deployed commit ae0d45f

Sign-in is Cloudflare Access (one-time PIN to an allowed email). The preview has its own database and encryption key; it is destroyed when this PR closes.

@pkg-pr-new

pkg-pr-new Bot commented Sep 18, 2026

Copy link
Copy Markdown

Open in StackBlitz

@executor-js/cli

npm i https://pkg.pr.new/@executor-js/cli@2067

@executor-js/config

npm i https://pkg.pr.new/@executor-js/config@2067

@executor-js/execution

npm i https://pkg.pr.new/@executor-js/execution@2067

@executor-js/sdk

npm i https://pkg.pr.new/@executor-js/sdk@2067

@executor-js/codemode-core

npm i https://pkg.pr.new/@executor-js/codemode-core@2067

@executor-js/runtime-quickjs

npm i https://pkg.pr.new/@executor-js/runtime-quickjs@2067

@executor-js/plugin-file-secrets

npm i https://pkg.pr.new/@executor-js/plugin-file-secrets@2067

@executor-js/plugin-graphql

npm i https://pkg.pr.new/@executor-js/plugin-graphql@2067

@executor-js/plugin-keychain

npm i https://pkg.pr.new/@executor-js/plugin-keychain@2067

@executor-js/plugin-mcp

npm i https://pkg.pr.new/@executor-js/plugin-mcp@2067

@executor-js/plugin-onepassword

npm i https://pkg.pr.new/@executor-js/plugin-onepassword@2067

@executor-js/plugin-openapi

npm i https://pkg.pr.new/@executor-js/plugin-openapi@2067

executor

npm i https://pkg.pr.new/executor@2067

commit: ae0d45f

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant