History

move API/MCP dispatch to Start request middleware

Rhys Sullivan committed 7 months ago

Commit 4b944b51 parent 236b76e9 files · +41 −118Browse files

Unified · Split

9 files
  1. apps/cloud/src/routeTree.gen.ts +2 −22
  2. apps/cloud/src/routes/api.$.ts +0 −18
  3. apps/cloud/src/server/api-handler.ts +2 −2
  4. apps/cloud/src/start.ts +15 −0
  5. apps/local/src/routeTree.gen.ts +2 −43
  6. apps/local/src/routes/api.$.ts +0 −18
  7. apps/local/src/routes/mcp.$.ts +0 −13
  8. apps/local/src/server/api-handler.ts +2 −2
  9. apps/local/src/start.ts +18 −0
apps/cloud/src/routeTree.gen.ts+2−22
@@ -13,7 +13,6 @@ import { Route as ToolsRouteImport } from './routes/tools' · 12 unmodified lines
1313 import { Route as SecretsRouteImport } from './routes/secrets'
1414 import { Route as IndexRouteImport } from './routes/index'
1515 import { Route as SourcesNamespaceRouteImport } from './routes/sources.$namespace'
16−import { Route as ApiSplatRouteImport } from './routes/api.$'
1716 import { Route as SourcesAddPluginKeyRouteImport } from './routes/sources.add.$pluginKey'
1817
1918 const ToolsRoute = ToolsRouteImport.update({
@@ -36,11 +35,6 @@ const SourcesNamespaceRoute = SourcesNamespaceRouteImport.update({ · 16 unmodified lines
3635 path: '/sources/$namespace',
3736 getParentRoute: () => rootRouteImport,
3837 } as any)
39−const ApiSplatRoute = ApiSplatRouteImport.update({
40− id: '/api/$',
41− path: '/api/$',
42− getParentRoute: () => rootRouteImport,
43−} as any)
4438 const SourcesAddPluginKeyRoute = SourcesAddPluginKeyRouteImport.update({
4539 id: '/sources/add/$pluginKey',
4640 path: '/sources/add/$pluginKey',
@@ -51,7 +45,6 @@ export interface FileRoutesByFullPath { · 4 unmodified lines
5145 '/': typeof IndexRoute
5246 '/secrets': typeof SecretsRoute
5347 '/tools': typeof ToolsRoute
54− '/api/$': typeof ApiSplatRoute
5548 '/sources/$namespace': typeof SourcesNamespaceRoute
5649 '/sources/add/$pluginKey': typeof SourcesAddPluginKeyRoute
5750 }
@@ -59,7 +52,6 @@ export interface FileRoutesByTo { · 1 unmodified line
5952 '/': typeof IndexRoute
6053 '/secrets': typeof SecretsRoute
6154 '/tools': typeof ToolsRoute
62− '/api/$': typeof ApiSplatRoute
6355 '/sources/$namespace': typeof SourcesNamespaceRoute
6456 '/sources/add/$pluginKey': typeof SourcesAddPluginKeyRoute
6557 }
@@ -68,7 +60,6 @@ export interface FileRoutesById { · 2 unmodified lines
6860 '/': typeof IndexRoute
6961 '/secrets': typeof SecretsRoute
7062 '/tools': typeof ToolsRoute
71− '/api/$': typeof ApiSplatRoute
7263 '/sources/$namespace': typeof SourcesNamespaceRoute
7364 '/sources/add/$pluginKey': typeof SourcesAddPluginKeyRoute
7465 }
@@ -78,7 +69,6 @@ export interface FileRouteTypes { · 3 unmodified lines
7869 | '/'
7970 | '/secrets'
8071 | '/tools'
81− | '/api/$'
8272 | '/sources/$namespace'
8373 | '/sources/add/$pluginKey'
8474 fileRoutesByTo: FileRoutesByTo
@@ -86,7 +76,6 @@ export interface FileRouteTypes { · 1 unmodified line
8676 | '/'
8777 | '/secrets'
8878 | '/tools'
89− | '/api/$'
9079 | '/sources/$namespace'
9180 | '/sources/add/$pluginKey'
9281 id:
@@ -94,7 +83,6 @@ export interface FileRouteTypes { · 1 unmodified line
9483 | '/'
9584 | '/secrets'
9685 | '/tools'
97− | '/api/$'
9886 | '/sources/$namespace'
9987 | '/sources/add/$pluginKey'
10088 fileRoutesById: FileRoutesById
@@ -103,7 +91,6 @@ export interface RootRouteChildren { · 2 unmodified lines
10391 IndexRoute: typeof IndexRoute
10492 SecretsRoute: typeof SecretsRoute
10593 ToolsRoute: typeof ToolsRoute
106− ApiSplatRoute: typeof ApiSplatRoute
10794 SourcesNamespaceRoute: typeof SourcesNamespaceRoute
10895 SourcesAddPluginKeyRoute: typeof SourcesAddPluginKeyRoute
10996 }
@@ -138,13 +125,6 @@ declare module '@tanstack/react-router' { · 28 unmodified lines
138125 preLoaderRoute: typeof SourcesNamespaceRouteImport
139126 parentRoute: typeof rootRouteImport
140127 }
141− '/api/$': {
142− id: '/api/$'
143− path: '/api/$'
144− fullPath: '/api/$'
145− preLoaderRoute: typeof ApiSplatRouteImport
146− parentRoute: typeof rootRouteImport
147− }
148128 '/sources/add/$pluginKey': {
149129 id: '/sources/add/$pluginKey'
150130 path: '/sources/add/$pluginKey'
@@ -159,7 +139,6 @@ const rootRouteChildren: RootRouteChildren = { · 8 unmodified lines
159139 IndexRoute: IndexRoute,
160140 SecretsRoute: SecretsRoute,
161141 ToolsRoute: ToolsRoute,
162− ApiSplatRoute: ApiSplatRoute,
163142 SourcesNamespaceRoute: SourcesNamespaceRoute,
164143 SourcesAddPluginKeyRoute: SourcesAddPluginKeyRoute,
165144 }
@@ -168,10 +147,11 @@ export const routeTree = rootRouteImport · 2 unmodified lines
168147 ._addFileTypes<FileRouteTypes>()
169148
170149 import type { getRouter } from './router.tsx'
171−import type { createStart } from '@tanstack/react-start'
150+import type { startInstance } from './start.ts'
172151 declare module '@tanstack/react-start' {
173152 interface Register {
174153 ssr: true
175154 router: Awaited<ReturnType<typeof getRouter>>
155+ config: Awaited<ReturnType<typeof startInstance.getOptions>>
176156 }
177157 }
apps/cloud/src/routes/api.$.ts+0−18
@@ -1,18 +0,0 @@
1−import { createFileRoute } from "@tanstack/react-router";
2−
3−const handle = async (request: Request) => {
4− const { handleApiRequest } = await import("../server/api-handler");
5− return handleApiRequest(request);
6−};
7−
8−export const Route = createFileRoute("/api/$")({
9− server: {
10− handlers: {
11− GET: ({ request }) => handle(request),
12− POST: ({ request }) => handle(request),
13− PUT: ({ request }) => handle(request),
14− DELETE: ({ request }) => handle(request),
15− PATCH: ({ request }) => handle(request),
16− },
17− },
18−});
apps/cloud/src/server/api-handler.ts+2−2
@@ -1,8 +1,8 @@
11 import { handleApiRequest as _handleApiRequest } from "../api";
22
33 export const handleApiRequest = (request: Request) => {
4− // Strip /api prefix — route catch-all (api.$.ts) matches /api/*
5− // but Effect endpoints are defined without the prefix
4+ // Strip /api prefix — Start request middleware forwards /api/* here,
5+ // but Effect endpoints are defined without the prefix.
66 const url = new URL(request.url);
77 url.pathname = url.pathname.replace(/^\/api/, "");
88 return _handleApiRequest(new Request(url, request));
apps/cloud/src/start.ts+15−0
@@ -0,0 +1,15 @@
1+import { createMiddleware, createStart } from "@tanstack/react-start";
2+import { handleApiRequest } from "./server/api-handler";
3+
4+const apiRequestMiddleware = createMiddleware({ type: "request" }).server(
5+ ({ pathname, request, next }) => {
6+ if (pathname === "/api" || pathname.startsWith("/api/")) {
7+ return handleApiRequest(request);
8+ }
9+ return next();
10+ },
11+);
12+
13+export const startInstance = createStart(() => ({
14+ requestMiddleware: [apiRequestMiddleware],
15+}));
apps/local/src/routeTree.gen.ts+2−43
@@ -13,8 +13,6 @@ import { Route as ToolsRouteImport } from './routes/tools' · 12 unmodified lines
1313 import { Route as SecretsRouteImport } from './routes/secrets'
1414 import { Route as IndexRouteImport } from './routes/index'
1515 import { Route as SourcesNamespaceRouteImport } from './routes/sources.$namespace'
16−import { Route as McpSplatRouteImport } from './routes/mcp.$'
17−import { Route as ApiSplatRouteImport } from './routes/api.$'
1816 import { Route as SourcesAddPluginKeyRouteImport } from './routes/sources.add.$pluginKey'
1917
2018 const ToolsRoute = ToolsRouteImport.update({
@@ -37,16 +35,6 @@ const SourcesNamespaceRoute = SourcesNamespaceRouteImport.update({ · 16 unmodified lines
3735 path: '/sources/$namespace',
3836 getParentRoute: () => rootRouteImport,
3937 } as any)
40−const McpSplatRoute = McpSplatRouteImport.update({
41− id: '/mcp/$',
42− path: '/mcp/$',
43− getParentRoute: () => rootRouteImport,
44−} as any)
45−const ApiSplatRoute = ApiSplatRouteImport.update({
46− id: '/api/$',
47− path: '/api/$',
48− getParentRoute: () => rootRouteImport,
49−} as any)
5038 const SourcesAddPluginKeyRoute = SourcesAddPluginKeyRouteImport.update({
5139 id: '/sources/add/$pluginKey',
5240 path: '/sources/add/$pluginKey',
@@ -57,8 +45,6 @@ export interface FileRoutesByFullPath { · 4 unmodified lines
5745 '/': typeof IndexRoute
5846 '/secrets': typeof SecretsRoute
5947 '/tools': typeof ToolsRoute
60− '/api/$': typeof ApiSplatRoute
61− '/mcp/$': typeof McpSplatRoute
6248 '/sources/$namespace': typeof SourcesNamespaceRoute
6349 '/sources/add/$pluginKey': typeof SourcesAddPluginKeyRoute
6450 }
@@ -66,8 +52,6 @@ export interface FileRoutesByTo { · 1 unmodified line
6652 '/': typeof IndexRoute
6753 '/secrets': typeof SecretsRoute
6854 '/tools': typeof ToolsRoute
69− '/api/$': typeof ApiSplatRoute
70− '/mcp/$': typeof McpSplatRoute
7155 '/sources/$namespace': typeof SourcesNamespaceRoute
7256 '/sources/add/$pluginKey': typeof SourcesAddPluginKeyRoute
7357 }
@@ -76,8 +60,6 @@ export interface FileRoutesById { · 2 unmodified lines
7660 '/': typeof IndexRoute
7761 '/secrets': typeof SecretsRoute
7862 '/tools': typeof ToolsRoute
79− '/api/$': typeof ApiSplatRoute
80− '/mcp/$': typeof McpSplatRoute
8163 '/sources/$namespace': typeof SourcesNamespaceRoute
8264 '/sources/add/$pluginKey': typeof SourcesAddPluginKeyRoute
8365 }
@@ -87,8 +69,6 @@ export interface FileRouteTypes { · 3 unmodified lines
8769 | '/'
8870 | '/secrets'
8971 | '/tools'
90− | '/api/$'
91− | '/mcp/$'
9272 | '/sources/$namespace'
9373 | '/sources/add/$pluginKey'
9474 fileRoutesByTo: FileRoutesByTo
@@ -96,8 +76,6 @@ export interface FileRouteTypes { · 1 unmodified line
9676 | '/'
9777 | '/secrets'
9878 | '/tools'
99− | '/api/$'
100− | '/mcp/$'
10179 | '/sources/$namespace'
10280 | '/sources/add/$pluginKey'
10381 id:
@@ -105,8 +83,6 @@ export interface FileRouteTypes { · 1 unmodified line
10583 | '/'
10684 | '/secrets'
10785 | '/tools'
108− | '/api/$'
109− | '/mcp/$'
11086 | '/sources/$namespace'
11187 | '/sources/add/$pluginKey'
11288 fileRoutesById: FileRoutesById
@@ -115,8 +91,6 @@ export interface RootRouteChildren { · 2 unmodified lines
11591 IndexRoute: typeof IndexRoute
11692 SecretsRoute: typeof SecretsRoute
11793 ToolsRoute: typeof ToolsRoute
118− ApiSplatRoute: typeof ApiSplatRoute
119− McpSplatRoute: typeof McpSplatRoute
12094 SourcesNamespaceRoute: typeof SourcesNamespaceRoute
12195 SourcesAddPluginKeyRoute: typeof SourcesAddPluginKeyRoute
12296 }
@@ -151,20 +125,6 @@ declare module '@tanstack/react-router' { · 28 unmodified lines
151125 preLoaderRoute: typeof SourcesNamespaceRouteImport
152126 parentRoute: typeof rootRouteImport
153127 }
154− '/mcp/$': {
155− id: '/mcp/$'
156− path: '/mcp/$'
157− fullPath: '/mcp/$'
158− preLoaderRoute: typeof McpSplatRouteImport
159− parentRoute: typeof rootRouteImport
160− }
161− '/api/$': {
162− id: '/api/$'
163− path: '/api/$'
164− fullPath: '/api/$'
165− preLoaderRoute: typeof ApiSplatRouteImport
166− parentRoute: typeof rootRouteImport
167− }
168128 '/sources/add/$pluginKey': {
169129 id: '/sources/add/$pluginKey'
170130 path: '/sources/add/$pluginKey'
@@ -179,8 +139,6 @@ const rootRouteChildren: RootRouteChildren = { · 8 unmodified lines
179139 IndexRoute: IndexRoute,
180140 SecretsRoute: SecretsRoute,
181141 ToolsRoute: ToolsRoute,
182− ApiSplatRoute: ApiSplatRoute,
183− McpSplatRoute: McpSplatRoute,
184142 SourcesNamespaceRoute: SourcesNamespaceRoute,
185143 SourcesAddPluginKeyRoute: SourcesAddPluginKeyRoute,
186144 }
@@ -189,10 +147,11 @@ export const routeTree = rootRouteImport · 2 unmodified lines
189147 ._addFileTypes<FileRouteTypes>()
190148
191149 import type { getRouter } from './router.tsx'
192−import type { createStart } from '@tanstack/react-start'
150+import type { startInstance } from './start.ts'
193151 declare module '@tanstack/react-start' {
194152 interface Register {
195153 ssr: true
196154 router: Awaited<ReturnType<typeof getRouter>>
155+ config: Awaited<ReturnType<typeof startInstance.getOptions>>
197156 }
198157 }
apps/local/src/routes/api.$.ts+0−18
@@ -1,18 +0,0 @@
1−import { createFileRoute } from "@tanstack/react-router";
2−
3−const handle = async (request: Request) => {
4− const { handleApiRequest } = await import("../server/api-handler");
5− return handleApiRequest(request);
6−};
7−
8−export const Route = createFileRoute("/api/$")({
9− server: {
10− handlers: {
11− GET: ({ request }) => handle(request),
12− POST: ({ request }) => handle(request),
13− PUT: ({ request }) => handle(request),
14− DELETE: ({ request }) => handle(request),
15− PATCH: ({ request }) => handle(request),
16− },
17− },
18−});
apps/local/src/routes/mcp.$.ts+0−13
@@ -1,13 +0,0 @@
1−import { createFileRoute } from "@tanstack/react-router";
2−import { handleMcpRequest } from "../server/api-handler";
3−
4−export const Route = createFileRoute("/mcp/$")({
5− server: {
6− handlers: {
7− GET: ({ request }) => handleMcpRequest(request),
8− POST: ({ request }) => handleMcpRequest(request),
9− PUT: ({ request }) => handleMcpRequest(request),
10− DELETE: ({ request }) => handleMcpRequest(request),
11− },
12− },
13−});
apps/local/src/server/api-handler.ts+2−2
@@ -20,8 +20,8 @@ const getHandlers = () => { · 19 unmodified lines
2020
2121 export const handleApiRequest = async (request: Request): Promise<Response> => {
2222 const handlers = await getHandlers();
23− // Strip /api prefix — the route catch-all (api.$.ts) matches /api/*
24− // but the Effect handler endpoints are defined without the prefix
23+ // Strip /api prefix — Start request middleware forwards /api/* here,
24+ // but the Effect handler endpoints are defined without the prefix.
2525 const url = new URL(request.url);
2626 url.pathname = url.pathname.replace(/^\/api/, "");
2727 return handlers.api.handler(new Request(url, request));
apps/local/src/start.ts+18−0
@@ -0,0 +1,18 @@
1+import { createMiddleware, createStart } from "@tanstack/react-start";
2+import { handleApiRequest, handleMcpRequest } from "./server/api-handler";
3+
4+const serverRequestMiddleware = createMiddleware({ type: "request" }).server(
5+ ({ pathname, request, next }) => {
6+ if (pathname === "/api" || pathname.startsWith("/api/")) {
7+ return handleApiRequest(request);
8+ }
9+ if (pathname === "/mcp" || pathname.startsWith("/mcp/")) {
10+ return handleMcpRequest(request);
11+ }
12+ return next();
13+ },
14+);
15+
16+export const startInstance = createStart(() => ({
17+ requestMiddleware: [serverRequestMiddleware],
18+}));