110 lines · 4.4 KB · TypeScript
RawDownload
import { createRootRoute } from "@tanstack/react-router";import { useEffect, type ReactNode } from "react"; import { ExecutorProvider } from "@executor-js/react/api/provider";import { ExecutorPluginsProvider } from "@executor-js/sdk/client";import { ArtifactRendererProvider } from "@executor-js/react/api/artifact-renderer";import { OrganizationProvider } from "@executor-js/react/api/organization-context";import { OrgSlugGate } from "@executor-js/react/multiplayer/org-slug-gate";import { Toaster } from "@executor-js/react/components/sonner";import { AuthProvider, useAuth } from "@executor-js/react/multiplayer/auth-context";import { Shell, defaultShellNavItems } from "@executor-js/react/multiplayer/shell";import { plugins as clientPlugins } from "virtual:executor/plugins-client"; // ---------------------------------------------------------------------------// Cloudflare root: the SAME shared multiplayer composition as cloud / self-host// (AuthProvider → Shell → pages), with Cloudflare Access as the identity.//// Access authenticates the human at the edge BEFORE the request reaches the// Worker, so there is no in-app login or first-run setup. `/account/me` (the// CF AccountProvider) reflects the Access principal, so the auth gate only ever// resolves to authenticated; the unauthenticated branch can only happen when// Access isn't in front yet (or a JWT expired) — we bounce to the Access login.//// API keys + members are managed in Cloudflare Access, not in-app, so this host// omits the API-keys nav item and just uses the default set.// --------------------------------------------------------------------------- // The MCP-Apps shell is browser-only — it imports `@tailwindcss/browser`, which// touches `document` at import scope. It is registered as a dynamic import the// artifact page resolves in the browser, never a static one, so it stays out of// any server graph. Module scope keeps the loader identity stable, so the lazy// component behind it never remounts.const artifactRendererLoader = () => import("@executor-js/mcp-apps-shell/shell/artifact-renderer"); export const Route = createRootRoute({  component: RootComponent,}); // Sign-out is a redirect to Access's logout endpoint (it clears the Access// session cookie); the next request re-prompts the Access login.const signOut = () => {  window.location.href = "/cdn-cgi/access/logout";}; const Loading = ({ label }: { label: string }) => (  <div className="flex min-h-screen items-center justify-center text-sm text-muted-foreground">    {label}  </div>); function AuthGate({ children }: { children: ReactNode }) {  const auth = useAuth();   // Access already authenticated the user at the edge; an unauthenticated state  // means there's no live Access session (gate not configured, or expired) —  // send them through the Access login, which returns to the app with a JWT.  useEffect(() => {    if (auth.status === "unauthenticated") {      window.location.href = "/cdn-cgi/access/login";    }  }, [auth.status]);   if (auth.status === "authenticated") return <>{children}</>;  return (    <Loading label={auth.status === "unauthenticated" ? "Redirecting to sign in…" : "Loading…"} />  );} function AuthenticatedApp() {  const auth = useAuth();  const organization = auth.status === "authenticated" ? (auth.organization ?? null) : null;   // Single-org instance: a bare URL canonicalizes onto the instance org's  // slug. There's only ever one org, so no other slug is reachable.  const gated = (    <>      <Shell onSignOut={signOut} navItems={defaultShellNavItems} />      <Toaster />    </>  );   return (    <ExecutorProvider>      <ExecutorPluginsProvider plugins={clientPlugins}>        {/* No organizationSlug: the worker serves only the bare /mcp (see            wrangler.jsonc run_worker_first), so a slug-pinned URL would fall            through to the SPA. */}        <OrganizationProvider organizationId={organization?.id ?? null}>          <ArtifactRendererProvider loader={artifactRendererLoader}>            {organization ? (              <OrgSlugGate activeSlug={organization.slug}>{gated}</OrgSlugGate>            ) : (              gated            )}          </ArtifactRendererProvider>        </OrganizationProvider>      </ExecutorPluginsProvider>    </ExecutorProvider>  );} function RootComponent() {  return (    <AuthProvider>      <AuthGate>        <AuthenticatedApp />      </AuthGate>    </AuthProvider>  );}