43 lines · 1.9 KB · TypeScript
RawDownload
import { createFileRoute, notFound } from "@tanstack/react-router";import { useClientPlugins } from "@executor-js/sdk/client"; // ---------------------------------------------------------------------------// /plugins/<pluginId>/<rest>//// Mounts pages contributed by client plugins. The host's// `<ExecutorPluginsProvider>` (set up at the root) materialises the// list of `ClientPluginSpec` from `virtual:executor/plugins-client`,// and this route reads it via `useClientPlugins()` — so adding a// plugin to `executor.config.ts` is sufficient for its pages to mount// here, with no per-route imports.//// Match logic is intentionally tiny: exact path equality between the URL// remainder and a `PageDecl.path`, with `""` and `/` treated as the// same root. Plugins that want parameterized paths can build their own// in-component routing for now.// --------------------------------------------------------------------------- export const Route = createFileRoute("/{-$orgSlug}/plugins/$pluginId/$")({  component: PluginRouteComponent,}); function normalizePath(input: string): string {  if (!input || input === "/") return "/";  return input.startsWith("/") ? input : `/${input}`;} function PluginRouteComponent() {  const { pluginId, _splat: rest } = Route.useParams();  const plugins = useClientPlugins();  const plugin = plugins.find((p) => p.id === pluginId);  // oxlint-disable-next-line executor/no-try-catch-or-throw -- boundary: TanStack Router represents not-found from components by throwing notFound()  if (!plugin) throw notFound();   const target = normalizePath(rest ?? "/");  const page = plugin.pages?.find((p) => normalizePath(p.path) === target);  // oxlint-disable-next-line executor/no-try-catch-or-throw -- boundary: TanStack Router represents not-found from components by throwing notFound()  if (!page) throw notFound();   const Component = page.component;  return <Component />;}