Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 14 additions & 5 deletions apps/cloud/src/start.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { createMiddleware, createStart } from "@tanstack/react-start";
import { decodeOAuthCallbackState } from "@executor-js/sdk/shared";

import { cloudApiHandler } from "./app";
import { isAppOwnedPath } from "./app-paths";
import { authGateMiddleware } from "./auth/ssr-gate";
import { parseCookie } from "./auth/cookies";
Expand Down Expand Up @@ -35,8 +34,18 @@ import {
// (a workerd-only virtual module) into the browser build, breaking it. Keeping
// the call inside the server callback mirrors how every other server concern
// here stays server-only.
let app: ReturnType<typeof cloudApiHandler> | undefined;
const getApp = () => (app ??= cloudApiHandler());
//
// The IMPORT is dynamic for a second, server-side reason: `server.ts` now
// dispatches `/api/*` at the Worker entry, so the only paths that still reach
// this middleware are the two Start's own chain claims first (the Sentry tunnel
// and the OAuth callback's signed-out redirect) plus `/mcp`. A static import
// would still put the entire Effect app in the graph every SSR page load
// evaluates — 3.06 MB of the 12.94 MB page closure, for code a page never runs.
// Deferring it takes the page closure to 9.88 MB; `scripts/start-closure.mjs`
// reports both planes and will show it coming back if this becomes static.
let app: ReturnType<typeof import("./app").cloudApiHandler> | undefined;
const getApp = async (): Promise<NonNullable<typeof app>> =>
(app ??= (await import("./app")).cloudApiHandler());

const SESSION_COOKIE = "wos-session";
const OAUTH_CALLBACK_PATH = "/api/oauth/callback";
Expand Down Expand Up @@ -78,11 +87,11 @@ const oauthCallbackSignInMiddleware = createMiddleware({ type: "request" }).serv
// envelope routes, pinning the org in an internal header (a no-op for everything
// else, including `/api/*`).
const appRequestMiddleware = createMiddleware({ type: "request" }).server(
({ pathname, request, next }) => {
async ({ pathname, request, next }) => {
if (isAppOwnedPath(pathname)) {
const scopedRequest =
pathname === OAUTH_CALLBACK_PATH ? oauthCallbackOrgScopedRequest(request) : request;
return getApp().handler(prepareMcpOrgScope(scopedRequest));
return (await getApp()).handler(prepareMcpOrgScope(scopedRequest));
}
return next();
},
Expand Down
Loading