diff --git a/docs/docs-html-cache-experiment.ts.txt b/docs/docs-html-cache-experiment.ts.txt deleted file mode 100644 index f142cf982..000000000 --- a/docs/docs-html-cache-experiment.ts.txt +++ /dev/null @@ -1,55 +0,0 @@ -// Archived proof of concept. Not imported by the application. - -export async function serveDocsHtml( - request: Request, - options: { - cache: Pick | undefined - render: () => Response | Promise - waitUntil: (task: Promise) => void - }, -) { - const eligible = isPublicDocsHtmlRequest(request) - // A separate key prevents collisions with negotiated Markdown responses. - const key = new URL(request.url) - key.searchParams.set('__docs_html_cache', 'v1') - if (eligible && options.cache) { - const hit = await options.cache.match(key.href).catch((error) => { - console.warn('[Docs HTML cache] Read failed', error) - return undefined - }) - if (hit) { - const headers = new Headers(hit.headers) - headers.set('X-Docs-Cache', 'HIT') - const [, libraryId, version] = new URL(request.url).pathname.split('/') - headers.set( - 'Cache-Control', - getDocsCacheHeaders({ libraryId, version })['Cache-Control'], - ) - return new Response(hit.body, { status: hit.status, headers }) - } - } - const response = finalizeDocsHtmlHeaders(request, await options.render()) - if ( - eligible && - options.cache && - response.status === 200 && - response.headers.get('content-type')?.includes('text/html') && - response.headers.get('cache-tag')?.split(',').includes('docs:all') && - !response.headers.has('set-cookie') && - !/no-store|private/i.test(response.headers.get('cache-control') ?? '') - ) { - // Cache API uses Cache-Control, not the CDN header. Keep this spike's - // HTML TTL at 60 seconds; content refreshes independently in waitUntil. - const headers = new Headers(response.headers) - headers.set('Cache-Control', 'public, max-age=60') - options.waitUntil( - options.cache - .put(key.href, new Response(response.clone().body, { headers })) - .catch((error) => { - console.warn('[Docs HTML cache] Write failed', error) - }), - ) - response.headers.set('X-Docs-Cache', 'MISS') - } - return response -} diff --git a/docs/docs-performance-measurements.json b/docs/docs-performance-measurements.json deleted file mode 100644 index 5a237297e..000000000 --- a/docs/docs-performance-measurements.json +++ /dev/null @@ -1,194 +0,0 @@ -[ - { - "request": 1, - "status": 200, - "ttfb_ms": 1779.9, - "total_ms": 1900.0, - "tls_ms": 128.1, - "server_timing": "app_headers;dur=256.0, db_config;dur=0.0, content_edge_read;dur=504.0, start_handler;dur=256.0, db_used;desc=\"false\", docs_request;desc=\"1\"", - "cache_control": "private, no-store", - "ray": "a4b03dcc0e46f0aa", - "instance": "d91be598-ef5a-4d60-965f-2579acc5d50a", - "docs_request": 1, - "wall_ms": 424, - "cpu_ms": 166, - "clock_ms": 256, - "db_used": false - }, - { - "request": 2, - "status": 200, - "ttfb_ms": 1713.9, - "total_ms": 1831.7, - "tls_ms": 85.0, - "server_timing": "app_headers;dur=243.0, db_config;dur=0.0, content_edge_read;dur=480.0, start_handler;dur=243.0, db_used;desc=\"false\", docs_request;desc=\"1\"", - "cache_control": "private, no-store", - "ray": "a4b03dd7cda61e3c", - "instance": "041c4fde-fa09-4ade-a9cd-17386142d366", - "docs_request": 1, - "wall_ms": 411, - "cpu_ms": 163, - "clock_ms": 243, - "db_used": false - }, - { - "request": 3, - "status": 200, - "ttfb_ms": 286.8, - "total_ms": 412.8, - "tls_ms": 84.0, - "server_timing": "app_headers;dur=19.0, db_config;dur=0.0, content_edge_read;dur=25.0, start_handler;dur=19.0, db_used;desc=\"false\", docs_request;desc=\"2\"", - "cache_control": "private, no-store", - "ray": "a4b03de3583bf0ba", - "instance": "d91be598-ef5a-4d60-965f-2579acc5d50a", - "docs_request": 2, - "wall_ms": 99, - "cpu_ms": 63, - "clock_ms": 19, - "db_used": false - }, - { - "request": 4, - "status": 200, - "ttfb_ms": 3243.7, - "total_ms": 3361.7, - "tls_ms": 122.5, - "server_timing": "app_headers;dur=507.0, db_config;dur=0.0, content_edge_read;dur=1004.0, start_handler;dur=507.0, db_used;desc=\"false\", docs_request;desc=\"1\"", - "cache_control": "private, no-store", - "ray": "a4b03de63a396b3f", - "instance": "c995ad13-f3e8-47dc-80a3-7e53db2cc399", - "docs_request": 1, - "wall_ms": 955, - "cpu_ms": 443, - "clock_ms": 507, - "db_used": false - }, - { - "request": 5, - "status": 200, - "ttfb_ms": 3008.6, - "total_ms": 3133.4, - "tls_ms": 80.2, - "server_timing": "app_headers;dur=408.0, db_config;dur=0.0, content_edge_read;dur=806.0, start_handler;dur=408.0, db_used;desc=\"false\", docs_request;desc=\"1\"", - "cache_control": "private, no-store", - "ray": "a4b03dfb0ad62e5a", - "instance": "df765ba1-16b1-46c9-a22a-522a4ca6fa6c", - "docs_request": 1, - "wall_ms": 872, - "cpu_ms": 469, - "clock_ms": 408, - "db_used": false - }, - { - "request": 6, - "status": 200, - "ttfb_ms": 1747.5, - "total_ms": 1866.6, - "tls_ms": 80.8, - "server_timing": "app_headers;dur=248.0, db_config;dur=0.0, content_edge_read;dur=489.0, start_handler;dur=248.0, db_used;desc=\"false\", docs_request;desc=\"1\"", - "cache_control": "private, no-store", - "ray": "a4b03e0ebffd21d2", - "instance": "a965714b-3f6f-47bf-b76f-b9eda86c923c", - "docs_request": 1, - "wall_ms": 422, - "cpu_ms": 167, - "clock_ms": 248, - "db_used": false - }, - { - "request": 1, - "status": 200, - "ttfb_ms": 2192.4, - "total_ms": 2314.2, - "tls_ms": 80.1, - "server_timing": "app_headers;dur=489.0, db_config;dur=0.0, content_edge_read;dur=970.0, start_handler;dur=489.0, db_used;desc=\"false\", docs_request;desc=\"1\"", - "cache_control": "private, no-store", - "ray": "a4b03e97be5ffe48", - "instance": "34c797bd-a9ad-4270-a8c8-56f1611201b3", - "docs_request": 1, - "wall_ms": 683, - "cpu_ms": 192, - "clock_ms": 489, - "db_used": false - }, - { - "request": 2, - "status": 200, - "ttfb_ms": 1991.8, - "total_ms": 2109.0, - "tls_ms": 80.6, - "server_timing": "app_headers;dur=305.0, db_config;dur=0.0, content_edge_read;dur=603.0, start_handler;dur=305.0, db_used;desc=\"false\", docs_request;desc=\"1\"", - "cache_control": "private, no-store", - "ray": "a4b03ea65b2969fb", - "instance": "8d523fd5-9787-4cc8-810a-6e41e9bf1373", - "docs_request": 1, - "wall_ms": 486, - "cpu_ms": 177, - "clock_ms": 305, - "db_used": false - }, - { - "request": 3, - "status": 200, - "ttfb_ms": 274.7, - "total_ms": 391.4, - "tls_ms": 84.2, - "server_timing": "app_headers;dur=13.0, db_config;dur=0.0, content_edge_read;dur=19.0, start_handler;dur=13.0, db_used;desc=\"false\", docs_request;desc=\"2\"", - "cache_control": "private, no-store", - "ray": "a4b03eb3a8863cd3", - "instance": "34c797bd-a9ad-4270-a8c8-56f1611201b3", - "docs_request": 2, - "wall_ms": 92, - "cpu_ms": 64, - "clock_ms": 13, - "db_used": false - }, - { - "request": 4, - "status": 200, - "ttfb_ms": 242.1, - "total_ms": 363.0, - "tls_ms": 81.4, - "server_timing": "app_headers;dur=16.0, db_config;dur=0.0, content_edge_read;dur=23.0, start_handler;dur=16.0, db_used;desc=\"false\", docs_request;desc=\"3\"", - "cache_control": "private, no-store", - "ray": "a4b03eb62ad5f0b0", - "instance": "d91be598-ef5a-4d60-965f-2579acc5d50a", - "docs_request": 3, - "wall_ms": 79, - "cpu_ms": 51, - "clock_ms": 16, - "db_used": false - }, - { - "request": 5, - "status": 200, - "ttfb_ms": 248.4, - "total_ms": 363.3, - "tls_ms": 81.7, - "server_timing": "app_headers;dur=12.0, db_config;dur=0.0, content_edge_read;dur=19.0, start_handler;dur=12.0, db_used;desc=\"false\", docs_request;desc=\"2\"", - "cache_control": "private, no-store", - "ray": "a4b03eb8898adaec", - "instance": "a965714b-3f6f-47bf-b76f-b9eda86c923c", - "docs_request": 2, - "wall_ms": 93, - "cpu_ms": 60, - "clock_ms": 12, - "db_used": false - }, - { - "request": 6, - "status": 200, - "ttfb_ms": 272.6, - "total_ms": 388.5, - "tls_ms": 94.6, - "server_timing": "app_headers;dur=11.0, db_config;dur=0.0, content_edge_read;dur=16.0, start_handler;dur=11.0, db_used;desc=\"false\", docs_request;desc=\"3\"", - "cache_control": "private, no-store", - "ray": "a4b03ebafaab3127", - "instance": "34c797bd-a9ad-4270-a8c8-56f1611201b3", - "docs_request": 3, - "wall_ms": 108, - "cpu_ms": 88, - "clock_ms": 11, - "db_used": false - } -] diff --git a/docs/docs-performance-spike.md b/docs/docs-performance-spike.md deleted file mode 100644 index 594d0ad1f..000000000 --- a/docs/docs-performance-spike.md +++ /dev/null @@ -1,162 +0,0 @@ -# Docs response performance investigation - -## Current implementation - -Complete-page caching is out of the request path. `wrangler.jsonc` still has Workers Cache disabled. HTML docs responses use `Cache-Control: private, no-store` and `Cloudflare-CDN-Cache-Control: no-store`. The earlier Cache API experiment is archived in `docs-html-cache-experiment.ts.txt`, which the application does not import. Production deployment and follow-up measurements are recorded in the final section below. No CDN purge was performed. An isolated temporary Worker was deployed for measurement on October 15, with no production routes, database binding, application secrets, or scheduled jobs. It used the existing docs R2 bucket. The temporary Worker was deleted after capture; the R2 bucket was retained. - -The retained changes are manifest reuse across browser navigation, final page header ownership, and background refresh of expired positive GitHub source content. Explicit source invalidation still refreshes synchronously. Document and sidebar purge tags remain available, but do not enable HTML caching. - -## Production observations, October 14, 2026 - -Three requests to `/router/latest/docs/routing/routing-concepts`, before deploying any of these changes: - -| Ray ID | Client TTFB | Cloudflare cfEdge | Cloudflare cfWorker | -| -------------------- | ----------: | ----------------: | ------------------: | -| a4a8f328c97c6b56-DFW | 3104ms | 79ms | 2817ms | -| a4a8f33c8aaa6de9-DFW | 3380ms | 2467ms | 780ms | -| a4a8f352784b1b62-DFW | 320ms | 44ms | 151ms | - -The live Worker tail captured the last two. Worker wall/CPU times were 787/323ms and 158/92ms. Existing application request-end logs reported 460ms and 28ms, with zero outbound HTTP fetches counted. Those counts do not include R2 bindings or database sockets, and request-end logs do not cover the entire streamed response. The first request was not captured by the tail. - -The slow requests cannot all be attributed to the same application phase. One has substantial Worker time; another has substantial Cloudflare-reported edge time. The measurements do not establish why either was slow. - -Docs source reads use R2 plus the content cache, falling back to GitHub. Postgres is initialized lazily, so entering the database request context does not itself issue a query. - -## New diagnostics - -Only docs-path requests receive these diagnostics: - -- `Server-Timing`: application time through response creation, Start handler, database configuration lookup, content edge-cache reads/writes, R2 reads/body reads, origin fetch work, artifact construction and persistence where executed. -- `db_used`: whether the database accessor was used by response-header creation. This is an access indicator, not a SQL query count or duration. -- Structured `docs_timing` logs: headers ready, first body byte, body completion, cancellation or stream failure. Logs include the Cloudflare ray ID, phase offsets/durations, and database access indicator at that stage. -- Sentry child spans for the measured operations, under the existing request tracing integration. - -Timings overlap and can be nested, so do not add their durations to calculate total latency. Header timings are a snapshot; work completed during streaming appears in later body-phase logs. Origin time includes the whole content-origin operation, including response-body consumption. These diagnostics do not measure Worker startup before the entrypoint or network transit to the visitor. - -Sentry tracing is configured at 100% with request and server-function middleware. Receipt of these new child spans in the production Sentry project has not been verified. Cloudflare Worker tail access was verified. - -## Deployed preview measurements, October 15 - -The temporary Worker ran the production build with complete HTML caching disabled. Twelve sequential requests across two runs all returned 200 and `private, no-store`, with no database access recorded. Requests reached DFW from the same machine. The instance ID and per-instance docs request counter distinguish first docs requests from reused instances. - -| Instance state | Requests | Client TTFB | Median TTFB | Platform CPU | Platform wall time | -| ------------------ | -------: | ------------: | ----------: | -----------: | -----------------: | -| First docs request | 7 | 1,714–3,244ms | 1,992ms | 163–469ms | 411–955ms | -| Reused instance | 5 | 242–287ms | 273ms | 51–88ms | 79–108ms | - -Individual samples and ray IDs are in `docs-performance-measurements.json`. This is a small preview sample, not a production percentile or a multi-region benchmark. First docs request is an observed counter, not a direct platform cold-start event. - -Fresh-instance work is strongly associated with the slow responses. The page does not require Postgres to render. This does not yet isolate which functions are expensive, nor explain all the gap between platform invocation timing and client TTFB. The Worker upload was approximately 8.4MB compressed and reported 345ms startup time on the first build, which makes module initialization worth profiling, but is not proof of the full cause. - -The content-phase spans showed initial parallel cache reads taking much longer on first docs requests. Their intervals are not a standalone benchmark of the cache service. - -### Clock limitation - -Cloudflare freezes `performance.now()` and `Date.now()` between I/O events in deployed Workers. The application phase timings can therefore miss CPU-only work, especially rendering after the last I/O. Do not treat `app_headers`, first-body-byte or body-complete clock values as complete real elapsed durations. Compare them with Cloudflare's platform CPU/wall counters and client TTFB. See https://developers.cloudflare.com/workers/runtime-apis/performance/. - -The CPU-profile API returned HTTP 404, “No recent executions were found for this Worker,” twice, even with successful traffic and Worker tail events. A function-level CPU profile was not obtained. Sentry delivery remains unverified. - -### Validation - -Production build, all TypeScript configurations and repository lint passed. Unit tests: 556 passed, 4 skipped. Chat tests: 2,269 passed. Desktop tests: 20 passed, 1 skipped. The initial unit command was blocked by the sandbox's IPC restriction; rerunning the remaining suites with IPC permission passed. The later instance marker passed its targeted tests and production build. - -## Next measurement - -Profile CPU for cold and reused instances to identify module initialization versus first-render work. Keep HTML caching disabled. If deploying the instrumentation to production, correlate `cf-ray` with `docs_timing` logs. Compare Cloudflare timing, headers-ready, first-body-byte and body-complete timing first. Then inspect the nested content phases and `databaseUsed`. If database access appears, instrument the specific query path rather than attributing all request time to Postgres. Compare multiple regions and cold/warm Worker runs. - -The local runtime uses development content sources and Vite compilation. Its timing is useful for verifying instrumentation, not for predicting production latency. - -## First-request CPU investigation, October 15 - -Profiled the production build locally with the workerd inspector, then used `wrangler check startup` for module initialization. No additional remote Worker was created. - -An initially empty local content store produced a 2,275ms first request, dominated by GitHub/tree retrieval and manifest construction. That is a content-cache miss, not a clean cold-instance comparison. After populating storage and restarting the Worker, the first request was 143ms and the repeated request 20ms, with no origin fetches in the first request's timing header. - -Startup profiling found initialization of Zod schemas, chat/Kody dependencies, database schema definitions, and garbage collection. A controlled build temporarily omitted the StreamObject, WorkspaceSync, Conversation and TanChatWorkflow exports from the shared entrypoint. Source exports were restored immediately after building. - -| Local comparison | Full Worker | Chat exports omitted | -| ------------------------------------ | ----------: | -------------------: | -| Sampled active module-startup CPU | 88.9ms | 23.9ms | -| Startup garbage collection | 13.8ms | 1.3ms | -| First docs request with warm content | 143ms | 191ms | -| Repeated docs request | 20ms | 19ms | - -These are single local samples, not production estimates or statistically stable benchmarks. The reduction in startup CPU did not produce an end-to-end improvement: schema initialization reappeared in the first-request CPU profile. Removing exports alone shifts work and is not a solution. - -The SSR import graph and the compiled router identify this eager dependency path: - -``` -src/router.tsx - -> src/routeTree.gen.ts - -> src/routes/api/chat/mcp/contract.ts - -> src/chat/server/reference-catalog-http.server.ts - -> src/chat/server/discovery-integrations/index.ts - -> src/chat/server/discovery-integrations/kody.ts - -> src/chat/server/discovery-integrations/kody-contract.ts - -> src/chat/server/kody-actions.ts - -> @babel/parser and @babel/types -``` - -The API route imports its handler at module scope. Kody actions imports Babel at module scope. The first docs request consequently initializes unrelated chat/API/compiler code while loading the router. Other routes and the Worker exports also reach chat dependencies, so changing just one route would not necessarily remove them. - -The next implementation should isolate those dependencies behind the routes/entrypoints that use them: lazy server-handler imports for unrelated API routes, and a separate chat Durable Object/workflow entrypoint if needed. Verify the generated static import graph and repeat cold-instance measurements, rather than assuming that smaller startup time means faster first responses. - -This identifies concrete unnecessary application work, not the entirety of the multi-second Cloudflare delay. Network/runtime startup remains outside the local request profile. The production source and full build have been restored, HTML caching remains disabled, and no experimental export removal is retained. - -Profiles from this run are saved locally at `/tmp/docs-startup-full.cpuprofile`, `/tmp/docs-startup-without-chat.cpuprofile`, `/tmp/docs-warm-content-first.cpuprofile`, and `/tmp/docs-warm-content-repeat.cpuprofile`. - -## TanChat isolation implementation, October 15 - -Chat API handlers and MCP OAuth handlers now import their implementations when invoked. Larger inline handlers live outside the generated route tree, under `src/chat/server/routes`. The chat access check, legacy chat redirects, appearance bootstrap, CSS URL, and shared builder loading UI also load on demand. The chat admin component no longer has an extra export that prevents automatic route splitting. The main navigation link disables hover preloading for TanChat. - -The four deployed Worker class names remain unchanged. Lightweight classes in `src/chat/server/entries.ts` defer their implementation imports until object construction or workflow execution. Durable Object initialization runs inside `blockConcurrencyWhile`, and explicit prototype methods preserve the RPC surface. No storage namespace, binding, or migration changes are needed. Scheduled work is imported only from the scheduled entrypoint. - -The production build now checks the emitted static chunk graph for both server and browser entrypoints, including the server router loaded by docs. Only two small synchronous routing-contract modules, `core/navigation.ts` and `core/workspace-panels.ts`, remain eager, along with the server's lightweight class declarations. No chat UI, services, MCP implementation, or Babel modules appeared in that graph. The build fails if another chat implementation module becomes eager. - -### Local validation - -- Production build passed its new isolation check. `pnpm test` passed all TypeScript configurations, lint, 560 unit tests, 2,270 chat tests, and 20 desktop tests. Five existing tests were skipped. -- Real local workerd initialized Conversation's SQLite state and returned `{running:false,pending:false}` through RPC. -- A local test subclass verified WorkspaceSync initialization. StreamObject created a stream, read its contents, and acquired a fork through RPC. -- A contract test compares every public RPC/lifecycle method against the lazy entrypoints. A separate test checks deferred imports, initialization, arguments, and return values. -- Browser docs rendering and unauthenticated chat navigation were checked against the local production build, using a generated local session secret. No production credentials or storage were used for the chat checks. - -| Local sample | Before isolation | After isolation | -| -------------------------------------- | ---------------: | --------------: | -| Sampled active module-startup CPU | 88.9ms | 22.7ms | -| Startup garbage collection | 13.8ms | 0ms sampled | -| First docs request, warm content, TTFB | 143ms | 171ms | -| Repeated docs request, TTFB | 20ms | 36ms | - -These are individual local profiles, not a controlled performance distribution. The startup sample improved by about 74%, but there is no demonstrated end-to-end TTFB improvement yet. The first-request profile no longer shows the chat/compiler initialization path; remaining work includes routing/rendering, shared partners/blog modules, and content-cache operations. Both measured docs requests reported no database use and no origin content fetch. - -The Worker still contains the lazy chat chunks in its upload, about 26MB uncompressed. This change reduces what initializes for unrelated requests, not total upload size. Production cold-instance measurements are still needed. At the end of the local validation, this isolation change had not been deployed. Complete HTML caching remains disabled. - -Profiles: `/tmp/docs-startup-isolated-chat.cpuprofile`, `/tmp/docs-isolated-chat-first.cpuprofile`, and `/tmp/docs-isolated-chat-repeat.cpuprofile`. Raw client timings: `/tmp/docs-isolated-chat-requests.jsonl`. - -## Production deployment and measurements, October 15 - -Deployed the tested build to `tanstack-com` at 20:41 UTC. Previous version: `9440f136-1e14-4cea-9583-830df3dae49c`. New version: `3b554871-c23c-4825-9bb4-f9bc27dc5466`. Deployment kept existing variables and secrets. Durable Object bindings/namespaces, database schema, and cache configuration did not change. No CDN purge was needed. The deployed changes include the earlier docs manifest/content-cache/header fixes and tracing as well as TanChat isolation. - -Cloudflare reported **36ms Worker startup**. The earlier isolated preview reported 345ms, which is a different deployment context, not a controlled production before/after startup benchmark. - -Measured six requests immediately before deployment, then 28 afterward from the same client through DFW. Requests used separate curl processes/connections and a one-second pause. Cloudflare tail records were joined by ray ID to obtain the actual serving version, CPU, wall time, and application timing logs. Five requests during rollout reached the previous version and are excluded from new-version statistics. All 12 requests in the final run reached the new version. - -| Request group | Samples | Median TTFB | TTFB range | Median platform CPU | Median platform wall | -| ------------------------------------------- | ------: | ----------: | ------------: | ------------------: | -------------------: | -| Before deployment, first three requests | 3 | 2,555ms | 1,846–2,914ms | 174ms | 451ms | -| Before deployment, last three requests | 3 | 305ms | 258–346ms | 93ms | 122ms | -| New version, first docs request on instance | 9 | 1,393ms | 297–3,271ms | 165ms | 362ms | -| New version, reused docs instance | 14 | 240ms | 214–440ms | 56ms | 77ms | - -The old version lacked the instance counter, so its first/last groups are observations of request order, not verified cold/warm labels. The new first-docs counter also does not prove that no other route already initialized the instance. These small samples suggest a warm-path improvement, but do not establish production percentiles or a causal percentage improvement from TanChat isolation alone. - -All 23 measured new-version responses returned 200 and `private, no-store`. Every corresponding docs timing record reported `databaseUsed: false`. On the 3,271ms outlier, Cloudflare's response header reported `cfEdge=2467ms` and `cfWorker=673ms`. Much of that wait lies outside the reported Worker duration. This does not identify which edge/platform operation caused it. The multi-second first-request problem remains. - -Read-only smoke checks passed: `/chat` redirected to `/chat-access` and returned 200; `/api/chat/bootstrap` returned the expected unauthenticated 401; `/auth/mcp/client-metadata` returned 200. Observed exception messages during the deployment window were network disconnects, with no module-initialization exception observed. Signed-in chat interactions were not exercised in production. - -Full request measurements and phase logs are in `docs-production-performance-measurements.json`. No follow-up code change was deployed after these measurements. - -## Detailed cold-request investigation - -The follow-up isolated the dominant delay to pre-handler preparation of the complete uploaded Worker, including code never imported by the request. See [the investigation](./worker-cold-start-investigation.md) and [220 probe measurements](./worker-cold-start-measurements.json). No additional production deployment was performed. diff --git a/docs/docs-production-performance-measurements.json b/docs/docs-production-performance-measurements.json deleted file mode 100644 index 81391475f..000000000 --- a/docs/docs-production-performance-measurements.json +++ /dev/null @@ -1,3188 +0,0 @@ -{ - "measured_at_utc": "2026-10-15T20:40:09+00:00 through 2026-10-15T20:42:31+00:00", - "url": "https://tanstack.com/router/latest/docs/routing/routing-concepts", - "region": "DFW", - "previous_version": "9440f136-1e14-4cea-9583-830df3dae49c", - "deployed_version": "3b554871-c23c-4825-9bb4-f9bc27dc5466", - "deployment_started_at_utc": "2026-10-15T20:41:02Z", - "reported_startup_ms": 36, - "before": [ - { - "request": 1, - "status": 200, - "ttfb_ms": 2914.0, - "total_ms": 3045.6, - "tls_ms": 165.9, - "ray": "a4b1a3106836f887-DFW", - "server_timing": "cfEdge;dur=1436,cfOrigin;dur=0,cfWorker;dur=1271", - "cache_control": "public, max-age=0, must-revalidate", - "cf_cache_status": null, - "date": "Thu, 15 Oct 2026 20:40:09 GMT", - "cpu_ms": 222, - "wall_ms": 2017, - "version": "9440f136-1e14-4cea-9583-830df3dae49c", - "outcome": "ok" - }, - { - "request": 2, - "status": 200, - "ttfb_ms": 2555.4, - "total_ms": 2674.9, - "tls_ms": 79.1, - "ray": "a4b1a3294cf78c20-DFW", - "server_timing": "cfEdge;dur=1985,cfOrigin;dur=0,cfWorker;dur=448", - "cache_control": "public, max-age=0, must-revalidate", - "cf_cache_status": null, - "date": "Thu, 15 Oct 2026 20:40:12 GMT", - "cpu_ms": 174, - "wall_ms": 451, - "version": "9440f136-1e14-4cea-9583-830df3dae49c", - "outcome": "ok" - }, - { - "request": 3, - "status": 200, - "ttfb_ms": 1846.0, - "total_ms": 1967.7, - "tls_ms": 85.4, - "ray": "a4b1a3406f2de7ff-DFW", - "server_timing": "cfEdge;dur=1314,cfOrigin;dur=0,cfWorker;dur=405", - "cache_control": "public, max-age=0, must-revalidate", - "cf_cache_status": null, - "date": "Thu, 15 Oct 2026 20:40:15 GMT", - "cpu_ms": 153, - "wall_ms": 409, - "version": "9440f136-1e14-4cea-9583-830df3dae49c", - "outcome": "ok" - }, - { - "request": 4, - "status": 200, - "ttfb_ms": 345.6, - "total_ms": 463.5, - "tls_ms": 79.1, - "ray": "a4b1a3530c225e57-DFW", - "server_timing": "cfEdge;dur=30,cfOrigin;dur=0,cfWorker;dur=194", - "cache_control": "public, max-age=0, must-revalidate", - "cf_cache_status": null, - "date": "Thu, 15 Oct 2026 20:40:17 GMT", - "cpu_ms": 136, - "wall_ms": 196, - "version": "9440f136-1e14-4cea-9583-830df3dae49c", - "outcome": "ok" - }, - { - "request": 5, - "status": 200, - "ttfb_ms": 257.5, - "total_ms": 386.8, - "tls_ms": 80.0, - "ray": "a4b1a35c4fb786ee-DFW", - "server_timing": "cfEdge;dur=27,cfOrigin;dur=0,cfWorker;dur=106", - "cache_control": "public, max-age=0, must-revalidate", - "cf_cache_status": null, - "date": "Thu, 15 Oct 2026 20:40:18 GMT", - "cpu_ms": 76, - "wall_ms": 106, - "version": "9440f136-1e14-4cea-9583-830df3dae49c", - "outcome": "ok" - }, - { - "request": 6, - "status": 200, - "ttfb_ms": 305.3, - "total_ms": 429.5, - "tls_ms": 82.8, - "ray": "a4b1a3650cbfa927-DFW", - "server_timing": "cfEdge;dur=53,cfOrigin;dur=0,cfWorker;dur=120", - "cache_control": "public, max-age=0, must-revalidate", - "cf_cache_status": null, - "date": "Thu, 15 Oct 2026 20:40:20 GMT", - "cpu_ms": 93, - "wall_ms": 122, - "version": "9440f136-1e14-4cea-9583-830df3dae49c", - "outcome": "ok" - } - ], - "during_rollout": [ - { - "request": 1, - "status": 200, - "ttfb_ms": 2046.1, - "total_ms": 2167.8, - "tls_ms": 80.0, - "ray": "a4b1a4ad6db4a91e-DFW", - "server_timing": "cfEdge;dur=1377,cfOrigin;dur=0,cfWorker;dur=546", - "cache_control": "private, no-store", - "cf_cache_status": null, - "date": "Thu, 15 Oct 2026 20:41:14 GMT", - "cpu_ms": 247, - "wall_ms": 550, - "version": "3b554871-c23c-4825-9bb4-f9bc27dc5466", - "outcome": "ok", - "docs_timings": [ - { - "logType": "docs_timing", - "workerInstance": "13eb6168-600f-44ed-8a81-43632a34383d", - "docsRequest": 1, - "phase": "headers_ready", - "pathname": "/router/latest/docs/routing/routing-concepts", - "ray": "a4b1a4ad6db4a91e", - "status": 200, - "headersReadyMs": 297, - "databaseUsed": false, - "phases": [ - { - "name": "db_config", - "startMs": 0, - "durationMs": 0 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 291 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 291 - }, - { - "name": "content_edge_read", - "startMs": 291, - "durationMs": 6 - }, - { - "name": "start_handler", - "startMs": 0, - "durationMs": 297 - } - ] - }, - { - "logType": "docs_timing", - "workerInstance": "13eb6168-600f-44ed-8a81-43632a34383d", - "docsRequest": 1, - "phase": "first_body_byte", - "pathname": "/router/latest/docs/routing/routing-concepts", - "ray": "a4b1a4ad6db4a91e", - "elapsedMs": 297, - "databaseUsed": false, - "phases": [ - { - "name": "db_config", - "startMs": 0, - "durationMs": 0 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 291 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 291 - }, - { - "name": "content_edge_read", - "startMs": 291, - "durationMs": 6 - }, - { - "name": "start_handler", - "startMs": 0, - "durationMs": 297 - } - ] - }, - { - "logType": "docs_timing", - "workerInstance": "13eb6168-600f-44ed-8a81-43632a34383d", - "docsRequest": 1, - "phase": "body_complete", - "pathname": "/router/latest/docs/routing/routing-concepts", - "ray": "a4b1a4ad6db4a91e", - "elapsedMs": 297, - "databaseUsed": false, - "phases": [ - { - "name": "db_config", - "startMs": 0, - "durationMs": 0 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 291 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 291 - }, - { - "name": "content_edge_read", - "startMs": 291, - "durationMs": 6 - }, - { - "name": "start_handler", - "startMs": 0, - "durationMs": 297 - } - ] - } - ] - }, - { - "request": 2, - "status": 200, - "ttfb_ms": 2343.4, - "total_ms": 2462.2, - "tls_ms": 81.7, - "ray": "a4b1a4c15da114ef-DFW", - "server_timing": "cfEdge;dur=1794,cfOrigin;dur=0,cfWorker;dur=424", - "cache_control": "public, max-age=0, must-revalidate", - "cf_cache_status": null, - "date": "Thu, 15 Oct 2026 20:41:17 GMT", - "cpu_ms": 159, - "wall_ms": 430, - "version": "9440f136-1e14-4cea-9583-830df3dae49c", - "outcome": "ok" - }, - { - "request": 3, - "status": 200, - "ttfb_ms": 2640.6, - "total_ms": 2761.0, - "tls_ms": 105.3, - "ray": "a4b1a4d73c384780-DFW", - "server_timing": "cfEdge;dur=1691,cfOrigin;dur=0,cfWorker;dur=795", - "cache_control": "private, no-store", - "cf_cache_status": null, - "date": "Thu, 15 Oct 2026 20:41:21 GMT", - "cpu_ms": 428, - "wall_ms": 803, - "version": "3b554871-c23c-4825-9bb4-f9bc27dc5466", - "outcome": "ok", - "docs_timings": [ - { - "logType": "docs_timing", - "workerInstance": "4b1da96b-ffe6-4c92-9ceb-572b0aa28c5e", - "docsRequest": 1, - "phase": "headers_ready", - "pathname": "/router/latest/docs/routing/routing-concepts", - "ray": "a4b1a4d73c384780", - "status": 200, - "headersReadyMs": 382, - "databaseUsed": false, - "phases": [ - { - "name": "db_config", - "startMs": 0, - "durationMs": 0 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 370 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 372 - }, - { - "name": "content_edge_read", - "startMs": 372, - "durationMs": 10 - }, - { - "name": "start_handler", - "startMs": 0, - "durationMs": 382 - } - ] - }, - { - "logType": "docs_timing", - "workerInstance": "4b1da96b-ffe6-4c92-9ceb-572b0aa28c5e", - "docsRequest": 1, - "phase": "first_body_byte", - "pathname": "/router/latest/docs/routing/routing-concepts", - "ray": "a4b1a4d73c384780", - "elapsedMs": 382, - "databaseUsed": false, - "phases": [ - { - "name": "db_config", - "startMs": 0, - "durationMs": 0 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 370 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 372 - }, - { - "name": "content_edge_read", - "startMs": 372, - "durationMs": 10 - }, - { - "name": "start_handler", - "startMs": 0, - "durationMs": 382 - } - ] - }, - { - "logType": "docs_timing", - "workerInstance": "4b1da96b-ffe6-4c92-9ceb-572b0aa28c5e", - "docsRequest": 1, - "phase": "body_complete", - "pathname": "/router/latest/docs/routing/routing-concepts", - "ray": "a4b1a4d73c384780", - "elapsedMs": 382, - "databaseUsed": false, - "phases": [ - { - "name": "db_config", - "startMs": 0, - "durationMs": 0 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 370 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 372 - }, - { - "name": "content_edge_read", - "startMs": 372, - "durationMs": 10 - }, - { - "name": "start_handler", - "startMs": 0, - "durationMs": 382 - } - ] - } - ] - }, - { - "request": 4, - "status": 200, - "ttfb_ms": 1963.5, - "total_ms": 2082.4, - "tls_ms": 86.8, - "ray": "a4b1a4eebd86f070-DFW", - "server_timing": "cfEdge;dur=1283,cfOrigin;dur=0,cfWorker;dur=550", - "cache_control": "public, max-age=0, must-revalidate", - "cf_cache_status": null, - "date": "Thu, 15 Oct 2026 20:41:24 GMT", - "cpu_ms": 302, - "wall_ms": 556, - "version": "9440f136-1e14-4cea-9583-830df3dae49c", - "outcome": "ok" - }, - { - "request": 5, - "status": 200, - "ttfb_ms": 2901.2, - "total_ms": 3022.1, - "tls_ms": 109.0, - "ray": "a4b1a5023b59b1c9-DFW", - "server_timing": "cfEdge;dur=2270,cfOrigin;dur=0,cfWorker;dur=478", - "cache_control": "public, max-age=0, must-revalidate", - "cf_cache_status": null, - "date": "Thu, 15 Oct 2026 20:41:28 GMT", - "cpu_ms": 175, - "wall_ms": 483, - "version": "9440f136-1e14-4cea-9583-830df3dae49c", - "outcome": "ok" - }, - { - "request": 6, - "status": 200, - "ttfb_ms": 1383.1, - "total_ms": 1504.1, - "tls_ms": 82.4, - "ray": "a4b1a51b5d0d9a79-DFW", - "server_timing": "cfEdge;dur=926,cfOrigin;dur=0,cfWorker;dur=331", - "cache_control": "private, no-store", - "cf_cache_status": null, - "date": "Thu, 15 Oct 2026 20:41:31 GMT", - "cpu_ms": 147, - "wall_ms": 333, - "version": "3b554871-c23c-4825-9bb4-f9bc27dc5466", - "outcome": "ok", - "docs_timings": [ - { - "logType": "docs_timing", - "workerInstance": "ceee50a1-bdee-4077-a79a-4d5707f53e98", - "docsRequest": 1, - "phase": "headers_ready", - "pathname": "/router/latest/docs/routing/routing-concepts", - "ray": "a4b1a51b5d0d9a79", - "status": 200, - "headersReadyMs": 183, - "databaseUsed": false, - "phases": [ - { - "name": "db_config", - "startMs": 0, - "durationMs": 0 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 178 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 179 - }, - { - "name": "content_edge_read", - "startMs": 178, - "durationMs": 5 - }, - { - "name": "start_handler", - "startMs": 0, - "durationMs": 183 - } - ] - }, - { - "logType": "docs_timing", - "workerInstance": "ceee50a1-bdee-4077-a79a-4d5707f53e98", - "docsRequest": 1, - "phase": "first_body_byte", - "pathname": "/router/latest/docs/routing/routing-concepts", - "ray": "a4b1a51b5d0d9a79", - "elapsedMs": 183, - "databaseUsed": false, - "phases": [ - { - "name": "db_config", - "startMs": 0, - "durationMs": 0 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 178 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 179 - }, - { - "name": "content_edge_read", - "startMs": 178, - "durationMs": 5 - }, - { - "name": "start_handler", - "startMs": 0, - "durationMs": 183 - } - ] - }, - { - "logType": "docs_timing", - "workerInstance": "ceee50a1-bdee-4077-a79a-4d5707f53e98", - "docsRequest": 1, - "phase": "body_complete", - "pathname": "/router/latest/docs/routing/routing-concepts", - "ray": "a4b1a51b5d0d9a79", - "elapsedMs": 183, - "databaseUsed": false, - "phases": [ - { - "name": "db_config", - "startMs": 0, - "durationMs": 0 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 178 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 179 - }, - { - "name": "content_edge_read", - "startMs": 178, - "durationMs": 5 - }, - { - "name": "start_handler", - "startMs": 0, - "durationMs": 183 - } - ] - } - ] - }, - { - "request": 7, - "status": 200, - "ttfb_ms": 238.6, - "total_ms": 356.9, - "tls_ms": 81.3, - "ray": "a4b1a52b0eacee9e-DFW", - "server_timing": "cfEdge;dur=39,cfOrigin;dur=0,cfWorker;dur=72", - "cache_control": "private, no-store", - "cf_cache_status": null, - "date": "Thu, 15 Oct 2026 20:41:32 GMT", - "cpu_ms": 57, - "wall_ms": 73, - "version": "3b554871-c23c-4825-9bb4-f9bc27dc5466", - "outcome": "ok", - "docs_timings": [ - { - "logType": "docs_timing", - "workerInstance": "0bc0619a-83d0-473f-a9fb-03e1973224d5", - "docsRequest": 3, - "phase": "headers_ready", - "pathname": "/router/latest/docs/routing/routing-concepts", - "ray": "a4b1a52b0eacee9e", - "status": 200, - "headersReadyMs": 15, - "databaseUsed": false, - "phases": [ - { - "name": "db_config", - "startMs": 0, - "durationMs": 0 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 7 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 10 - }, - { - "name": "content_edge_read", - "startMs": 10, - "durationMs": 5 - }, - { - "name": "start_handler", - "startMs": 0, - "durationMs": 15 - } - ] - }, - { - "logType": "docs_timing", - "workerInstance": "0bc0619a-83d0-473f-a9fb-03e1973224d5", - "docsRequest": 3, - "phase": "first_body_byte", - "pathname": "/router/latest/docs/routing/routing-concepts", - "ray": "a4b1a52b0eacee9e", - "elapsedMs": 15, - "databaseUsed": false, - "phases": [ - { - "name": "db_config", - "startMs": 0, - "durationMs": 0 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 7 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 10 - }, - { - "name": "content_edge_read", - "startMs": 10, - "durationMs": 5 - }, - { - "name": "start_handler", - "startMs": 0, - "durationMs": 15 - } - ] - }, - { - "logType": "docs_timing", - "workerInstance": "0bc0619a-83d0-473f-a9fb-03e1973224d5", - "docsRequest": 3, - "phase": "body_complete", - "pathname": "/router/latest/docs/routing/routing-concepts", - "ray": "a4b1a52b0eacee9e", - "elapsedMs": 15, - "databaseUsed": false, - "phases": [ - { - "name": "db_config", - "startMs": 0, - "durationMs": 0 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 7 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 10 - }, - { - "name": "content_edge_read", - "startMs": 10, - "durationMs": 5 - }, - { - "name": "start_handler", - "startMs": 0, - "durationMs": 15 - } - ] - } - ] - }, - { - "request": 8, - "status": 200, - "ttfb_ms": 215.5, - "total_ms": 332.7, - "tls_ms": 79.0, - "ray": "a4b1a5339937863c-DFW", - "server_timing": "cfEdge;dur=30,cfOrigin;dur=0,cfWorker;dur=65", - "cache_control": "private, no-store", - "cf_cache_status": null, - "date": "Thu, 15 Oct 2026 20:41:34 GMT", - "cpu_ms": 54, - "wall_ms": 66, - "version": "3b554871-c23c-4825-9bb4-f9bc27dc5466", - "outcome": "ok", - "docs_timings": [ - { - "logType": "docs_timing", - "workerInstance": "ceee50a1-bdee-4077-a79a-4d5707f53e98", - "docsRequest": 2, - "phase": "headers_ready", - "pathname": "/router/latest/docs/routing/routing-concepts", - "ray": "a4b1a5339937863c", - "status": 200, - "headersReadyMs": 12, - "databaseUsed": false, - "phases": [ - { - "name": "db_config", - "startMs": 0, - "durationMs": 0 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 6 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 6 - }, - { - "name": "content_edge_read", - "startMs": 6, - "durationMs": 6 - }, - { - "name": "start_handler", - "startMs": 0, - "durationMs": 12 - } - ] - }, - { - "logType": "docs_timing", - "workerInstance": "ceee50a1-bdee-4077-a79a-4d5707f53e98", - "docsRequest": 2, - "phase": "first_body_byte", - "pathname": "/router/latest/docs/routing/routing-concepts", - "ray": "a4b1a5339937863c", - "elapsedMs": 12, - "databaseUsed": false, - "phases": [ - { - "name": "db_config", - "startMs": 0, - "durationMs": 0 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 6 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 6 - }, - { - "name": "content_edge_read", - "startMs": 6, - "durationMs": 6 - }, - { - "name": "start_handler", - "startMs": 0, - "durationMs": 12 - } - ] - }, - { - "logType": "docs_timing", - "workerInstance": "ceee50a1-bdee-4077-a79a-4d5707f53e98", - "docsRequest": 2, - "phase": "body_complete", - "pathname": "/router/latest/docs/routing/routing-concepts", - "ray": "a4b1a5339937863c", - "elapsedMs": 12, - "databaseUsed": false, - "phases": [ - { - "name": "db_config", - "startMs": 0, - "durationMs": 0 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 6 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 6 - }, - { - "name": "content_edge_read", - "startMs": 6, - "durationMs": 6 - }, - { - "name": "start_handler", - "startMs": 0, - "durationMs": 12 - } - ] - } - ] - }, - { - "request": 9, - "status": 200, - "ttfb_ms": 326.9, - "total_ms": 449.4, - "tls_ms": 83.2, - "ray": "a4b1a53c091fc437-DFW", - "server_timing": "cfEdge;dur=19,cfOrigin;dur=0,cfWorker;dur=180", - "cache_control": "private, no-store", - "cf_cache_status": null, - "date": "Thu, 15 Oct 2026 20:41:35 GMT", - "cpu_ms": 123, - "wall_ms": 181, - "version": "3b554871-c23c-4825-9bb4-f9bc27dc5466", - "outcome": "ok", - "docs_timings": [ - { - "logType": "docs_timing", - "workerInstance": "4b9f0cbd-4094-45fa-88a2-40cb7822ea9d", - "docsRequest": 1, - "phase": "headers_ready", - "pathname": "/router/latest/docs/routing/routing-concepts", - "ray": "a4b1a53c091fc437", - "status": 200, - "headersReadyMs": 43, - "databaseUsed": false, - "phases": [ - { - "name": "db_config", - "startMs": 0, - "durationMs": 0 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 33 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 34 - }, - { - "name": "content_edge_read", - "startMs": 33, - "durationMs": 10 - }, - { - "name": "start_handler", - "startMs": 0, - "durationMs": 43 - } - ] - }, - { - "logType": "docs_timing", - "workerInstance": "4b9f0cbd-4094-45fa-88a2-40cb7822ea9d", - "docsRequest": 1, - "phase": "first_body_byte", - "pathname": "/router/latest/docs/routing/routing-concepts", - "ray": "a4b1a53c091fc437", - "elapsedMs": 43, - "databaseUsed": false, - "phases": [ - { - "name": "db_config", - "startMs": 0, - "durationMs": 0 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 33 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 34 - }, - { - "name": "content_edge_read", - "startMs": 33, - "durationMs": 10 - }, - { - "name": "start_handler", - "startMs": 0, - "durationMs": 43 - } - ] - }, - { - "logType": "docs_timing", - "workerInstance": "4b9f0cbd-4094-45fa-88a2-40cb7822ea9d", - "docsRequest": 1, - "phase": "body_complete", - "pathname": "/router/latest/docs/routing/routing-concepts", - "ray": "a4b1a53c091fc437", - "elapsedMs": 43, - "databaseUsed": false, - "phases": [ - { - "name": "db_config", - "startMs": 0, - "durationMs": 0 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 33 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 34 - }, - { - "name": "content_edge_read", - "startMs": 33, - "durationMs": 10 - }, - { - "name": "start_handler", - "startMs": 0, - "durationMs": 43 - } - ] - } - ] - }, - { - "request": 10, - "status": 200, - "ttfb_ms": 242.2, - "total_ms": 358.2, - "tls_ms": 99.6, - "ray": "a4b1a5455a6e2ba1-DFW", - "server_timing": "cfEdge;dur=37,cfOrigin;dur=0,cfWorker;dur=60", - "cache_control": "private, no-store", - "cf_cache_status": null, - "date": "Thu, 15 Oct 2026 20:41:36 GMT", - "cpu_ms": 48, - "wall_ms": 61, - "version": "3b554871-c23c-4825-9bb4-f9bc27dc5466", - "outcome": "ok", - "docs_timings": [ - { - "logType": "docs_timing", - "workerInstance": "0bc0619a-83d0-473f-a9fb-03e1973224d5", - "docsRequest": 4, - "phase": "headers_ready", - "pathname": "/router/latest/docs/routing/routing-concepts", - "ray": "a4b1a5455a6e2ba1", - "status": 200, - "headersReadyMs": 11, - "databaseUsed": false, - "phases": [ - { - "name": "db_config", - "startMs": 0, - "durationMs": 0 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 6 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 7 - }, - { - "name": "content_edge_read", - "startMs": 7, - "durationMs": 4 - }, - { - "name": "start_handler", - "startMs": 0, - "durationMs": 11 - } - ] - }, - { - "logType": "docs_timing", - "workerInstance": "0bc0619a-83d0-473f-a9fb-03e1973224d5", - "docsRequest": 4, - "phase": "first_body_byte", - "pathname": "/router/latest/docs/routing/routing-concepts", - "ray": "a4b1a5455a6e2ba1", - "elapsedMs": 11, - "databaseUsed": false, - "phases": [ - { - "name": "db_config", - "startMs": 0, - "durationMs": 0 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 6 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 7 - }, - { - "name": "content_edge_read", - "startMs": 7, - "durationMs": 4 - }, - { - "name": "start_handler", - "startMs": 0, - "durationMs": 11 - } - ] - }, - { - "logType": "docs_timing", - "workerInstance": "0bc0619a-83d0-473f-a9fb-03e1973224d5", - "docsRequest": 4, - "phase": "body_complete", - "pathname": "/router/latest/docs/routing/routing-concepts", - "ray": "a4b1a5455a6e2ba1", - "elapsedMs": 11, - "databaseUsed": false, - "phases": [ - { - "name": "db_config", - "startMs": 0, - "durationMs": 0 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 6 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 7 - }, - { - "name": "content_edge_read", - "startMs": 7, - "durationMs": 4 - }, - { - "name": "start_handler", - "startMs": 0, - "durationMs": 11 - } - ] - } - ] - }, - { - "request": 11, - "status": 200, - "ttfb_ms": 297.4, - "total_ms": 423.3, - "tls_ms": 81.5, - "ray": "a4b1a54dd863b66c-DFW", - "server_timing": "cfEdge;dur=38,cfOrigin;dur=0,cfWorker;dur=134", - "cache_control": "private, no-store", - "cf_cache_status": null, - "date": "Thu, 15 Oct 2026 20:41:38 GMT", - "cpu_ms": 104, - "wall_ms": 135, - "version": "3b554871-c23c-4825-9bb4-f9bc27dc5466", - "outcome": "ok", - "docs_timings": [ - { - "logType": "docs_timing", - "workerInstance": "d94a23be-f6aa-4d62-9705-df14cc3b59db", - "docsRequest": 1, - "phase": "headers_ready", - "pathname": "/router/latest/docs/routing/routing-concepts", - "ray": "a4b1a54dd863b66c", - "status": 200, - "headersReadyMs": 24, - "databaseUsed": false, - "phases": [ - { - "name": "db_config", - "startMs": 0, - "durationMs": 0 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 15 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 15 - }, - { - "name": "content_edge_read", - "startMs": 15, - "durationMs": 9 - }, - { - "name": "start_handler", - "startMs": 0, - "durationMs": 24 - } - ] - }, - { - "logType": "docs_timing", - "workerInstance": "d94a23be-f6aa-4d62-9705-df14cc3b59db", - "docsRequest": 1, - "phase": "first_body_byte", - "pathname": "/router/latest/docs/routing/routing-concepts", - "ray": "a4b1a54dd863b66c", - "elapsedMs": 24, - "databaseUsed": false, - "phases": [ - { - "name": "db_config", - "startMs": 0, - "durationMs": 0 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 15 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 15 - }, - { - "name": "content_edge_read", - "startMs": 15, - "durationMs": 9 - }, - { - "name": "start_handler", - "startMs": 0, - "durationMs": 24 - } - ] - }, - { - "logType": "docs_timing", - "workerInstance": "d94a23be-f6aa-4d62-9705-df14cc3b59db", - "docsRequest": 1, - "phase": "body_complete", - "pathname": "/router/latest/docs/routing/routing-concepts", - "ray": "a4b1a54dd863b66c", - "elapsedMs": 24, - "databaseUsed": false, - "phases": [ - { - "name": "db_config", - "startMs": 0, - "durationMs": 0 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 15 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 15 - }, - { - "name": "content_edge_read", - "startMs": 15, - "durationMs": 9 - }, - { - "name": "start_handler", - "startMs": 0, - "durationMs": 24 - } - ] - } - ] - }, - { - "request": 12, - "status": 200, - "ttfb_ms": 2861.6, - "total_ms": 2992.5, - "tls_ms": 89.6, - "ray": "a4b1a556d8546c6c-DFW", - "server_timing": "cfEdge;dur=2015,cfOrigin;dur=0,cfWorker;dur=711", - "cache_control": "public, max-age=0, must-revalidate", - "cf_cache_status": null, - "date": "Thu, 15 Oct 2026 20:41:42 GMT", - "cpu_ms": 307, - "wall_ms": 721, - "version": "9440f136-1e14-4cea-9583-830df3dae49c", - "outcome": "ok" - }, - { - "request": 13, - "status": 200, - "ttfb_ms": 1586.5, - "total_ms": 2141.4, - "tls_ms": 81.2, - "ray": "a4b1a56fdf42c514-DFW", - "server_timing": "cfEdge;dur=909,cfOrigin;dur=0,cfWorker;dur=531", - "cache_control": "private, no-store", - "cf_cache_status": null, - "date": "Thu, 15 Oct 2026 20:41:45 GMT", - "cpu_ms": 206, - "wall_ms": 535, - "version": "3b554871-c23c-4825-9bb4-f9bc27dc5466", - "outcome": "ok", - "docs_timings": [ - { - "logType": "docs_timing", - "workerInstance": "3f5f2043-2489-4def-9b91-f37cc5fb244c", - "docsRequest": 1, - "phase": "headers_ready", - "pathname": "/router/latest/docs/routing/routing-concepts", - "ray": "a4b1a56fdf42c514", - "status": 200, - "headersReadyMs": 328, - "databaseUsed": false, - "phases": [ - { - "name": "db_config", - "startMs": 0, - "durationMs": 0 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 320 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 320 - }, - { - "name": "content_edge_read", - "startMs": 320, - "durationMs": 8 - }, - { - "name": "start_handler", - "startMs": 0, - "durationMs": 328 - } - ] - }, - { - "logType": "docs_timing", - "workerInstance": "3f5f2043-2489-4def-9b91-f37cc5fb244c", - "docsRequest": 1, - "phase": "first_body_byte", - "pathname": "/router/latest/docs/routing/routing-concepts", - "ray": "a4b1a56fdf42c514", - "elapsedMs": 328, - "databaseUsed": false, - "phases": [ - { - "name": "db_config", - "startMs": 0, - "durationMs": 0 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 320 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 320 - }, - { - "name": "content_edge_read", - "startMs": 320, - "durationMs": 8 - }, - { - "name": "start_handler", - "startMs": 0, - "durationMs": 328 - } - ] - }, - { - "logType": "docs_timing", - "workerInstance": "3f5f2043-2489-4def-9b91-f37cc5fb244c", - "docsRequest": 1, - "phase": "body_complete", - "pathname": "/router/latest/docs/routing/routing-concepts", - "ray": "a4b1a56fdf42c514", - "elapsedMs": 328, - "databaseUsed": false, - "phases": [ - { - "name": "db_config", - "startMs": 0, - "durationMs": 0 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 320 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 320 - }, - { - "name": "content_edge_read", - "startMs": 320, - "durationMs": 8 - }, - { - "name": "start_handler", - "startMs": 0, - "durationMs": 328 - } - ] - } - ] - }, - { - "request": 14, - "status": 200, - "ttfb_ms": 2910.9, - "total_ms": 3125.2, - "tls_ms": 81.6, - "ray": "a4b1a5838ef1f088-DFW", - "server_timing": "cfEdge;dur=2123,cfOrigin;dur=0,cfWorker;dur=659", - "cache_control": "public, max-age=0, must-revalidate", - "cf_cache_status": null, - "date": "Thu, 15 Oct 2026 20:41:49 GMT", - "cpu_ms": 310, - "wall_ms": 665, - "version": "9440f136-1e14-4cea-9583-830df3dae49c", - "outcome": "ok" - }, - { - "request": 15, - "status": 200, - "ttfb_ms": 439.8, - "total_ms": 563.1, - "tls_ms": 93.2, - "ray": "a4b1a59d89f70af8-DFW", - "server_timing": "cfEdge;dur=221,cfOrigin;dur=0,cfWorker;dur=75", - "cache_control": "private, no-store", - "cf_cache_status": null, - "date": "Thu, 15 Oct 2026 20:41:51 GMT", - "cpu_ms": 55, - "wall_ms": 76, - "version": "3b554871-c23c-4825-9bb4-f9bc27dc5466", - "outcome": "ok", - "docs_timings": [ - { - "logType": "docs_timing", - "workerInstance": "0bc0619a-83d0-473f-a9fb-03e1973224d5", - "docsRequest": 5, - "phase": "headers_ready", - "pathname": "/router/latest/docs/routing/routing-concepts", - "ray": "a4b1a59d89f70af8", - "status": 200, - "headersReadyMs": 17, - "databaseUsed": false, - "phases": [ - { - "name": "db_config", - "startMs": 0, - "durationMs": 0 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 7 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 9 - }, - { - "name": "content_edge_read", - "startMs": 9, - "durationMs": 8 - }, - { - "name": "start_handler", - "startMs": 0, - "durationMs": 17 - } - ] - }, - { - "logType": "docs_timing", - "workerInstance": "0bc0619a-83d0-473f-a9fb-03e1973224d5", - "docsRequest": 5, - "phase": "first_body_byte", - "pathname": "/router/latest/docs/routing/routing-concepts", - "ray": "a4b1a59d89f70af8", - "elapsedMs": 17, - "databaseUsed": false, - "phases": [ - { - "name": "db_config", - "startMs": 0, - "durationMs": 0 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 7 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 9 - }, - { - "name": "content_edge_read", - "startMs": 9, - "durationMs": 8 - }, - { - "name": "start_handler", - "startMs": 0, - "durationMs": 17 - } - ] - }, - { - "logType": "docs_timing", - "workerInstance": "0bc0619a-83d0-473f-a9fb-03e1973224d5", - "docsRequest": 5, - "phase": "body_complete", - "pathname": "/router/latest/docs/routing/routing-concepts", - "ray": "a4b1a59d89f70af8", - "elapsedMs": 17, - "databaseUsed": false, - "phases": [ - { - "name": "db_config", - "startMs": 0, - "durationMs": 0 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 7 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 9 - }, - { - "name": "content_edge_read", - "startMs": 9, - "durationMs": 8 - }, - { - "name": "start_handler", - "startMs": 0, - "durationMs": 17 - } - ] - } - ] - }, - { - "request": 16, - "status": 200, - "ttfb_ms": 1353.9, - "total_ms": 1472.4, - "tls_ms": 82.4, - "ray": "a4b1a5a75b4df07d-DFW", - "server_timing": "cfEdge;dur=905,cfOrigin;dur=0,cfWorker;dur=319", - "cache_control": "private, no-store", - "cf_cache_status": null, - "date": "Thu, 15 Oct 2026 20:41:53 GMT", - "cpu_ms": 159, - "wall_ms": 322, - "version": "3b554871-c23c-4825-9bb4-f9bc27dc5466", - "outcome": "ok", - "docs_timings": [ - { - "logType": "docs_timing", - "workerInstance": "2cd6c3cf-4089-4604-9783-2cf642580036", - "docsRequest": 1, - "phase": "headers_ready", - "pathname": "/router/latest/docs/routing/routing-concepts", - "ray": "a4b1a5a75b4df07d", - "status": 200, - "headersReadyMs": 154, - "databaseUsed": false, - "phases": [ - { - "name": "db_config", - "startMs": 0, - "durationMs": 0 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 151 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 151 - }, - { - "name": "content_edge_read", - "startMs": 151, - "durationMs": 3 - }, - { - "name": "start_handler", - "startMs": 0, - "durationMs": 154 - } - ] - }, - { - "logType": "docs_timing", - "workerInstance": "2cd6c3cf-4089-4604-9783-2cf642580036", - "docsRequest": 1, - "phase": "first_body_byte", - "pathname": "/router/latest/docs/routing/routing-concepts", - "ray": "a4b1a5a75b4df07d", - "elapsedMs": 154, - "databaseUsed": false, - "phases": [ - { - "name": "db_config", - "startMs": 0, - "durationMs": 0 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 151 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 151 - }, - { - "name": "content_edge_read", - "startMs": 151, - "durationMs": 3 - }, - { - "name": "start_handler", - "startMs": 0, - "durationMs": 154 - } - ] - }, - { - "logType": "docs_timing", - "workerInstance": "2cd6c3cf-4089-4604-9783-2cf642580036", - "docsRequest": 1, - "phase": "body_complete", - "pathname": "/router/latest/docs/routing/routing-concepts", - "ray": "a4b1a5a75b4df07d", - "elapsedMs": 154, - "databaseUsed": false, - "phases": [ - { - "name": "db_config", - "startMs": 0, - "durationMs": 0 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 151 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 151 - }, - { - "name": "content_edge_read", - "startMs": 151, - "durationMs": 3 - }, - { - "name": "start_handler", - "startMs": 0, - "durationMs": 154 - } - ] - } - ] - } - ], - "after_rollout": [ - { - "request": 1, - "status": 200, - "ttfb_ms": 362.0, - "total_ms": 478.0, - "tls_ms": 81.8, - "ray": "a4b1a6206e2f6c38-DFW", - "server_timing": "cfEdge;dur=65,cfOrigin;dur=0,cfWorker;dur=165", - "cache_control": "private, no-store", - "cf_cache_status": null, - "date": "Thu, 15 Oct 2026 20:42:12 GMT", - "cpu_ms": 130, - "wall_ms": 167, - "version": "3b554871-c23c-4825-9bb4-f9bc27dc5466", - "outcome": "ok", - "docs_timings": [ - { - "logType": "docs_timing", - "workerInstance": "491c8962-14e6-4f24-b558-698b6566fbef", - "docsRequest": 2, - "phase": "headers_ready", - "pathname": "/router/latest/docs/routing/routing-concepts", - "ray": "a4b1a6206e2f6c38", - "status": 200, - "headersReadyMs": 22, - "databaseUsed": false, - "phases": [ - { - "name": "db_config", - "startMs": 0, - "durationMs": 0 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 13 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 13 - }, - { - "name": "content_edge_read", - "startMs": 13, - "durationMs": 9 - }, - { - "name": "start_handler", - "startMs": 0, - "durationMs": 22 - } - ] - }, - { - "logType": "docs_timing", - "workerInstance": "491c8962-14e6-4f24-b558-698b6566fbef", - "docsRequest": 2, - "phase": "first_body_byte", - "pathname": "/router/latest/docs/routing/routing-concepts", - "ray": "a4b1a6206e2f6c38", - "elapsedMs": 22, - "databaseUsed": false, - "phases": [ - { - "name": "db_config", - "startMs": 0, - "durationMs": 0 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 13 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 13 - }, - { - "name": "content_edge_read", - "startMs": 13, - "durationMs": 9 - }, - { - "name": "start_handler", - "startMs": 0, - "durationMs": 22 - } - ] - }, - { - "logType": "docs_timing", - "workerInstance": "491c8962-14e6-4f24-b558-698b6566fbef", - "docsRequest": 2, - "phase": "body_complete", - "pathname": "/router/latest/docs/routing/routing-concepts", - "ray": "a4b1a6206e2f6c38", - "elapsedMs": 22, - "databaseUsed": false, - "phases": [ - { - "name": "db_config", - "startMs": 0, - "durationMs": 0 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 13 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 13 - }, - { - "name": "content_edge_read", - "startMs": 13, - "durationMs": 9 - }, - { - "name": "start_handler", - "startMs": 0, - "durationMs": 22 - } - ] - } - ] - }, - { - "request": 2, - "status": 200, - "ttfb_ms": 232.1, - "total_ms": 348.8, - "tls_ms": 85.1, - "ray": "a4b1a629c89724e9-DFW", - "server_timing": "cfEdge;dur=14,cfOrigin;dur=0,cfWorker;dur=85", - "cache_control": "private, no-store", - "cf_cache_status": null, - "date": "Thu, 15 Oct 2026 20:42:13 GMT", - "cpu_ms": 59, - "wall_ms": 86, - "version": "3b554871-c23c-4825-9bb4-f9bc27dc5466", - "outcome": "ok", - "docs_timings": [ - { - "logType": "docs_timing", - "workerInstance": "0bc0619a-83d0-473f-a9fb-03e1973224d5", - "docsRequest": 6, - "phase": "headers_ready", - "pathname": "/router/latest/docs/routing/routing-concepts", - "ray": "a4b1a629c89724e9", - "status": 200, - "headersReadyMs": 18, - "databaseUsed": false, - "phases": [ - { - "name": "db_config", - "startMs": 0, - "durationMs": 0 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 10 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 11 - }, - { - "name": "content_edge_read", - "startMs": 11, - "durationMs": 7 - }, - { - "name": "start_handler", - "startMs": 0, - "durationMs": 18 - } - ] - }, - { - "logType": "docs_timing", - "workerInstance": "0bc0619a-83d0-473f-a9fb-03e1973224d5", - "docsRequest": 6, - "phase": "first_body_byte", - "pathname": "/router/latest/docs/routing/routing-concepts", - "ray": "a4b1a629c89724e9", - "elapsedMs": 18, - "databaseUsed": false, - "phases": [ - { - "name": "db_config", - "startMs": 0, - "durationMs": 0 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 10 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 11 - }, - { - "name": "content_edge_read", - "startMs": 11, - "durationMs": 7 - }, - { - "name": "start_handler", - "startMs": 0, - "durationMs": 18 - } - ] - }, - { - "logType": "docs_timing", - "workerInstance": "0bc0619a-83d0-473f-a9fb-03e1973224d5", - "docsRequest": 6, - "phase": "body_complete", - "pathname": "/router/latest/docs/routing/routing-concepts", - "ray": "a4b1a629c89724e9", - "elapsedMs": 18, - "databaseUsed": false, - "phases": [ - { - "name": "db_config", - "startMs": 0, - "durationMs": 0 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 10 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 11 - }, - { - "name": "content_edge_read", - "startMs": 11, - "durationMs": 7 - }, - { - "name": "start_handler", - "startMs": 0, - "durationMs": 18 - } - ] - } - ] - }, - { - "request": 3, - "status": 200, - "ttfb_ms": 241.9, - "total_ms": 361.0, - "tls_ms": 83.7, - "ray": "a4b1a6324b3a0dc1-DFW", - "server_timing": "cfEdge;dur=43,cfOrigin;dur=0,cfWorker;dur=71", - "cache_control": "private, no-store", - "cf_cache_status": null, - "date": "Thu, 15 Oct 2026 20:42:14 GMT", - "cpu_ms": 49, - "wall_ms": 72, - "version": "3b554871-c23c-4825-9bb4-f9bc27dc5466", - "outcome": "ok", - "docs_timings": [ - { - "logType": "docs_timing", - "workerInstance": "0bc0619a-83d0-473f-a9fb-03e1973224d5", - "docsRequest": 7, - "phase": "headers_ready", - "pathname": "/router/latest/docs/routing/routing-concepts", - "ray": "a4b1a6324b3a0dc1", - "status": 200, - "headersReadyMs": 23, - "databaseUsed": false, - "phases": [ - { - "name": "db_config", - "startMs": 0, - "durationMs": 0 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 13 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 13 - }, - { - "name": "content_edge_read", - "startMs": 13, - "durationMs": 10 - }, - { - "name": "start_handler", - "startMs": 0, - "durationMs": 23 - } - ] - }, - { - "logType": "docs_timing", - "workerInstance": "0bc0619a-83d0-473f-a9fb-03e1973224d5", - "docsRequest": 7, - "phase": "first_body_byte", - "pathname": "/router/latest/docs/routing/routing-concepts", - "ray": "a4b1a6324b3a0dc1", - "elapsedMs": 23, - "databaseUsed": false, - "phases": [ - { - "name": "db_config", - "startMs": 0, - "durationMs": 0 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 13 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 13 - }, - { - "name": "content_edge_read", - "startMs": 13, - "durationMs": 10 - }, - { - "name": "start_handler", - "startMs": 0, - "durationMs": 23 - } - ] - }, - { - "logType": "docs_timing", - "workerInstance": "0bc0619a-83d0-473f-a9fb-03e1973224d5", - "docsRequest": 7, - "phase": "body_complete", - "pathname": "/router/latest/docs/routing/routing-concepts", - "ray": "a4b1a6324b3a0dc1", - "elapsedMs": 23, - "databaseUsed": false, - "phases": [ - { - "name": "db_config", - "startMs": 0, - "durationMs": 0 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 13 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 13 - }, - { - "name": "content_edge_read", - "startMs": 13, - "durationMs": 10 - }, - { - "name": "start_handler", - "startMs": 0, - "durationMs": 23 - } - ] - } - ] - }, - { - "request": 4, - "status": 200, - "ttfb_ms": 213.9, - "total_ms": 331.1, - "tls_ms": 88.5, - "ray": "a4b1a63b0a03e792-DFW", - "server_timing": "cfEdge;dur=13,cfOrigin;dur=0,cfWorker;dur=69", - "cache_control": "private, no-store", - "cf_cache_status": null, - "date": "Thu, 15 Oct 2026 20:42:16 GMT", - "cpu_ms": 49, - "wall_ms": 70, - "version": "3b554871-c23c-4825-9bb4-f9bc27dc5466", - "outcome": "ok", - "docs_timings": [ - { - "logType": "docs_timing", - "workerInstance": "ceee50a1-bdee-4077-a79a-4d5707f53e98", - "docsRequest": 3, - "phase": "headers_ready", - "pathname": "/router/latest/docs/routing/routing-concepts", - "ray": "a4b1a63b0a03e792", - "status": 200, - "headersReadyMs": 18, - "databaseUsed": false, - "phases": [ - { - "name": "db_config", - "startMs": 0, - "durationMs": 0 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 9 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 9 - }, - { - "name": "content_edge_read", - "startMs": 9, - "durationMs": 9 - }, - { - "name": "start_handler", - "startMs": 0, - "durationMs": 18 - } - ] - }, - { - "logType": "docs_timing", - "workerInstance": "ceee50a1-bdee-4077-a79a-4d5707f53e98", - "docsRequest": 3, - "phase": "first_body_byte", - "pathname": "/router/latest/docs/routing/routing-concepts", - "ray": "a4b1a63b0a03e792", - "elapsedMs": 18, - "databaseUsed": false, - "phases": [ - { - "name": "db_config", - "startMs": 0, - "durationMs": 0 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 9 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 9 - }, - { - "name": "content_edge_read", - "startMs": 9, - "durationMs": 9 - }, - { - "name": "start_handler", - "startMs": 0, - "durationMs": 18 - } - ] - }, - { - "logType": "docs_timing", - "workerInstance": "ceee50a1-bdee-4077-a79a-4d5707f53e98", - "docsRequest": 3, - "phase": "body_complete", - "pathname": "/router/latest/docs/routing/routing-concepts", - "ray": "a4b1a63b0a03e792", - "elapsedMs": 18, - "databaseUsed": false, - "phases": [ - { - "name": "db_config", - "startMs": 0, - "durationMs": 0 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 9 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 9 - }, - { - "name": "content_edge_read", - "startMs": 9, - "durationMs": 9 - }, - { - "name": "start_handler", - "startMs": 0, - "durationMs": 18 - } - ] - } - ] - }, - { - "request": 5, - "status": 200, - "ttfb_ms": 3271.0, - "total_ms": 3397.0, - "tls_ms": 84.2, - "ray": "a4b1a6436fc13ad3-DFW", - "server_timing": "cfEdge;dur=2467,cfOrigin;dur=0,cfWorker;dur=673", - "cache_control": "private, no-store", - "cf_cache_status": null, - "date": "Thu, 15 Oct 2026 20:42:20 GMT", - "cpu_ms": 370, - "wall_ms": 681, - "version": "3b554871-c23c-4825-9bb4-f9bc27dc5466", - "outcome": "ok", - "docs_timings": [ - { - "logType": "docs_timing", - "workerInstance": "c0b6b4e8-1e60-4167-bb47-1f00c605143e", - "docsRequest": 1, - "phase": "headers_ready", - "pathname": "/router/latest/docs/routing/routing-concepts", - "ray": "a4b1a6436fc13ad3", - "status": 200, - "headersReadyMs": 317, - "databaseUsed": false, - "phases": [ - { - "name": "db_config", - "startMs": 0, - "durationMs": 0 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 313 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 317 - }, - { - "name": "content_edge_read", - "startMs": 313, - "durationMs": 4 - }, - { - "name": "start_handler", - "startMs": 0, - "durationMs": 317 - } - ] - }, - { - "logType": "docs_timing", - "workerInstance": "c0b6b4e8-1e60-4167-bb47-1f00c605143e", - "docsRequest": 1, - "phase": "first_body_byte", - "pathname": "/router/latest/docs/routing/routing-concepts", - "ray": "a4b1a6436fc13ad3", - "elapsedMs": 317, - "databaseUsed": false, - "phases": [ - { - "name": "db_config", - "startMs": 0, - "durationMs": 0 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 313 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 317 - }, - { - "name": "content_edge_read", - "startMs": 313, - "durationMs": 4 - }, - { - "name": "start_handler", - "startMs": 0, - "durationMs": 317 - } - ] - }, - { - "logType": "docs_timing", - "workerInstance": "c0b6b4e8-1e60-4167-bb47-1f00c605143e", - "docsRequest": 1, - "phase": "body_complete", - "pathname": "/router/latest/docs/routing/routing-concepts", - "ray": "a4b1a6436fc13ad3", - "elapsedMs": 317, - "databaseUsed": false, - "phases": [ - { - "name": "db_config", - "startMs": 0, - "durationMs": 0 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 313 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 317 - }, - { - "name": "content_edge_read", - "startMs": 313, - "durationMs": 4 - }, - { - "name": "start_handler", - "startMs": 0, - "durationMs": 317 - } - ] - } - ] - }, - { - "request": 6, - "status": 200, - "ttfb_ms": 231.8, - "total_ms": 355.4, - "tls_ms": 85.5, - "ray": "a4b1a65f0858f0c2-DFW", - "server_timing": "cfEdge;dur=26,cfOrigin;dur=0,cfWorker;dur=77", - "cache_control": "private, no-store", - "cf_cache_status": null, - "date": "Thu, 15 Oct 2026 20:42:22 GMT", - "cpu_ms": 55, - "wall_ms": 78, - "version": "3b554871-c23c-4825-9bb4-f9bc27dc5466", - "outcome": "ok", - "docs_timings": [ - { - "logType": "docs_timing", - "workerInstance": "2cd6c3cf-4089-4604-9783-2cf642580036", - "docsRequest": 2, - "phase": "headers_ready", - "pathname": "/router/latest/docs/routing/routing-concepts", - "ray": "a4b1a65f0858f0c2", - "status": 200, - "headersReadyMs": 12, - "databaseUsed": false, - "phases": [ - { - "name": "db_config", - "startMs": 0, - "durationMs": 0 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 6 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 7 - }, - { - "name": "content_edge_read", - "startMs": 7, - "durationMs": 5 - }, - { - "name": "start_handler", - "startMs": 0, - "durationMs": 12 - } - ] - }, - { - "logType": "docs_timing", - "workerInstance": "2cd6c3cf-4089-4604-9783-2cf642580036", - "docsRequest": 2, - "phase": "first_body_byte", - "pathname": "/router/latest/docs/routing/routing-concepts", - "ray": "a4b1a65f0858f0c2", - "elapsedMs": 12, - "databaseUsed": false, - "phases": [ - { - "name": "db_config", - "startMs": 0, - "durationMs": 0 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 6 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 7 - }, - { - "name": "content_edge_read", - "startMs": 7, - "durationMs": 5 - }, - { - "name": "start_handler", - "startMs": 0, - "durationMs": 12 - } - ] - }, - { - "logType": "docs_timing", - "workerInstance": "2cd6c3cf-4089-4604-9783-2cf642580036", - "docsRequest": 2, - "phase": "body_complete", - "pathname": "/router/latest/docs/routing/routing-concepts", - "ray": "a4b1a65f0858f0c2", - "elapsedMs": 12, - "databaseUsed": false, - "phases": [ - { - "name": "db_config", - "startMs": 0, - "durationMs": 0 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 6 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 7 - }, - { - "name": "content_edge_read", - "startMs": 7, - "durationMs": 5 - }, - { - "name": "start_handler", - "startMs": 0, - "durationMs": 12 - } - ] - } - ] - }, - { - "request": 7, - "status": 200, - "ttfb_ms": 319.2, - "total_ms": 442.7, - "tls_ms": 92.6, - "ray": "a4b1a667d81d2ca4-DFW", - "server_timing": "cfEdge;dur=32,cfOrigin;dur=0,cfWorker;dur=118", - "cache_control": "private, no-store", - "cf_cache_status": null, - "date": "Thu, 15 Oct 2026 20:42:23 GMT", - "cpu_ms": 98, - "wall_ms": 119, - "version": "3b554871-c23c-4825-9bb4-f9bc27dc5466", - "outcome": "ok", - "docs_timings": [ - { - "logType": "docs_timing", - "workerInstance": "ceee50a1-bdee-4077-a79a-4d5707f53e98", - "docsRequest": 4, - "phase": "headers_ready", - "pathname": "/router/latest/docs/routing/routing-concepts", - "ray": "a4b1a667d81d2ca4", - "status": 200, - "headersReadyMs": 16, - "databaseUsed": false, - "phases": [ - { - "name": "db_config", - "startMs": 0, - "durationMs": 0 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 5 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 8 - }, - { - "name": "content_edge_read", - "startMs": 8, - "durationMs": 8 - }, - { - "name": "start_handler", - "startMs": 0, - "durationMs": 16 - } - ] - }, - { - "logType": "docs_timing", - "workerInstance": "ceee50a1-bdee-4077-a79a-4d5707f53e98", - "docsRequest": 4, - "phase": "first_body_byte", - "pathname": "/router/latest/docs/routing/routing-concepts", - "ray": "a4b1a667d81d2ca4", - "elapsedMs": 16, - "databaseUsed": false, - "phases": [ - { - "name": "db_config", - "startMs": 0, - "durationMs": 0 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 5 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 8 - }, - { - "name": "content_edge_read", - "startMs": 8, - "durationMs": 8 - }, - { - "name": "start_handler", - "startMs": 0, - "durationMs": 16 - } - ] - }, - { - "logType": "docs_timing", - "workerInstance": "ceee50a1-bdee-4077-a79a-4d5707f53e98", - "docsRequest": 4, - "phase": "body_complete", - "pathname": "/router/latest/docs/routing/routing-concepts", - "ray": "a4b1a667d81d2ca4", - "elapsedMs": 16, - "databaseUsed": false, - "phases": [ - { - "name": "db_config", - "startMs": 0, - "durationMs": 0 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 5 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 8 - }, - { - "name": "content_edge_read", - "startMs": 8, - "durationMs": 8 - }, - { - "name": "start_handler", - "startMs": 0, - "durationMs": 16 - } - ] - } - ] - }, - { - "request": 8, - "status": 200, - "ttfb_ms": 278.6, - "total_ms": 397.5, - "tls_ms": 79.7, - "ray": "a4b1a670cdd8533a-DFW", - "server_timing": "cfEdge;dur=26,cfOrigin;dur=0,cfWorker;dur=130", - "cache_control": "private, no-store", - "cf_cache_status": null, - "date": "Thu, 15 Oct 2026 20:42:24 GMT", - "cpu_ms": 106, - "wall_ms": 133, - "version": "3b554871-c23c-4825-9bb4-f9bc27dc5466", - "outcome": "ok", - "docs_timings": [ - { - "logType": "docs_timing", - "workerInstance": "13eb6168-600f-44ed-8a81-43632a34383d", - "docsRequest": 5, - "phase": "headers_ready", - "pathname": "/router/latest/docs/routing/routing-concepts", - "ray": "a4b1a670cdd8533a", - "status": 200, - "headersReadyMs": 18, - "databaseUsed": false, - "phases": [ - { - "name": "db_config", - "startMs": 0, - "durationMs": 0 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 8 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 12 - }, - { - "name": "content_edge_read", - "startMs": 12, - "durationMs": 6 - }, - { - "name": "start_handler", - "startMs": 0, - "durationMs": 18 - } - ] - }, - { - "logType": "docs_timing", - "workerInstance": "13eb6168-600f-44ed-8a81-43632a34383d", - "docsRequest": 5, - "phase": "first_body_byte", - "pathname": "/router/latest/docs/routing/routing-concepts", - "ray": "a4b1a670cdd8533a", - "elapsedMs": 18, - "databaseUsed": false, - "phases": [ - { - "name": "db_config", - "startMs": 0, - "durationMs": 0 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 8 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 12 - }, - { - "name": "content_edge_read", - "startMs": 12, - "durationMs": 6 - }, - { - "name": "start_handler", - "startMs": 0, - "durationMs": 18 - } - ] - }, - { - "logType": "docs_timing", - "workerInstance": "13eb6168-600f-44ed-8a81-43632a34383d", - "docsRequest": 5, - "phase": "body_complete", - "pathname": "/router/latest/docs/routing/routing-concepts", - "ray": "a4b1a670cdd8533a", - "elapsedMs": 18, - "databaseUsed": false, - "phases": [ - { - "name": "db_config", - "startMs": 0, - "durationMs": 0 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 8 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 12 - }, - { - "name": "content_edge_read", - "startMs": 12, - "durationMs": 6 - }, - { - "name": "start_handler", - "startMs": 0, - "durationMs": 18 - } - ] - } - ] - }, - { - "request": 9, - "status": 200, - "ttfb_ms": 236.8, - "total_ms": 367.0, - "tls_ms": 83.9, - "ray": "a4b1a67998bad7a0-DFW", - "server_timing": "cfEdge;dur=23,cfOrigin;dur=0,cfWorker;dur=89", - "cache_control": "private, no-store", - "cf_cache_status": null, - "date": "Thu, 15 Oct 2026 20:42:26 GMT", - "cpu_ms": 70, - "wall_ms": 90, - "version": "3b554871-c23c-4825-9bb4-f9bc27dc5466", - "outcome": "ok", - "docs_timings": [ - { - "logType": "docs_timing", - "workerInstance": "3f5f2043-2489-4def-9b91-f37cc5fb244c", - "docsRequest": 2, - "phase": "headers_ready", - "pathname": "/router/latest/docs/routing/routing-concepts", - "ray": "a4b1a67998bad7a0", - "status": 200, - "headersReadyMs": 20, - "databaseUsed": false, - "phases": [ - { - "name": "db_config", - "startMs": 0, - "durationMs": 0 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 9 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 9 - }, - { - "name": "content_edge_read", - "startMs": 9, - "durationMs": 11 - }, - { - "name": "start_handler", - "startMs": 0, - "durationMs": 20 - } - ] - }, - { - "logType": "docs_timing", - "workerInstance": "3f5f2043-2489-4def-9b91-f37cc5fb244c", - "docsRequest": 2, - "phase": "first_body_byte", - "pathname": "/router/latest/docs/routing/routing-concepts", - "ray": "a4b1a67998bad7a0", - "elapsedMs": 20, - "databaseUsed": false, - "phases": [ - { - "name": "db_config", - "startMs": 0, - "durationMs": 0 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 9 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 9 - }, - { - "name": "content_edge_read", - "startMs": 9, - "durationMs": 11 - }, - { - "name": "start_handler", - "startMs": 0, - "durationMs": 20 - } - ] - }, - { - "logType": "docs_timing", - "workerInstance": "3f5f2043-2489-4def-9b91-f37cc5fb244c", - "docsRequest": 2, - "phase": "body_complete", - "pathname": "/router/latest/docs/routing/routing-concepts", - "ray": "a4b1a67998bad7a0", - "elapsedMs": 20, - "databaseUsed": false, - "phases": [ - { - "name": "db_config", - "startMs": 0, - "durationMs": 0 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 9 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 9 - }, - { - "name": "content_edge_read", - "startMs": 9, - "durationMs": 11 - }, - { - "name": "start_handler", - "startMs": 0, - "durationMs": 20 - } - ] - } - ] - }, - { - "request": 10, - "status": 200, - "ttfb_ms": 231.2, - "total_ms": 397.9, - "tls_ms": 82.4, - "ray": "a4b1a6823d28a270-DFW", - "server_timing": "cfEdge;dur=36,cfOrigin;dur=0,cfWorker;dur=67", - "cache_control": "private, no-store", - "cf_cache_status": null, - "date": "Thu, 15 Oct 2026 20:42:27 GMT", - "cpu_ms": 52, - "wall_ms": 68, - "version": "3b554871-c23c-4825-9bb4-f9bc27dc5466", - "outcome": "ok", - "docs_timings": [ - { - "logType": "docs_timing", - "workerInstance": "4b9f0cbd-4094-45fa-88a2-40cb7822ea9d", - "docsRequest": 2, - "phase": "headers_ready", - "pathname": "/router/latest/docs/routing/routing-concepts", - "ray": "a4b1a6823d28a270", - "status": 200, - "headersReadyMs": 16, - "databaseUsed": false, - "phases": [ - { - "name": "db_config", - "startMs": 0, - "durationMs": 0 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 8 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 8 - }, - { - "name": "content_edge_read", - "startMs": 8, - "durationMs": 8 - }, - { - "name": "start_handler", - "startMs": 0, - "durationMs": 16 - } - ] - }, - { - "logType": "docs_timing", - "workerInstance": "4b9f0cbd-4094-45fa-88a2-40cb7822ea9d", - "docsRequest": 2, - "phase": "first_body_byte", - "pathname": "/router/latest/docs/routing/routing-concepts", - "ray": "a4b1a6823d28a270", - "elapsedMs": 16, - "databaseUsed": false, - "phases": [ - { - "name": "db_config", - "startMs": 0, - "durationMs": 0 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 8 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 8 - }, - { - "name": "content_edge_read", - "startMs": 8, - "durationMs": 8 - }, - { - "name": "start_handler", - "startMs": 0, - "durationMs": 16 - } - ] - }, - { - "logType": "docs_timing", - "workerInstance": "4b9f0cbd-4094-45fa-88a2-40cb7822ea9d", - "docsRequest": 2, - "phase": "body_complete", - "pathname": "/router/latest/docs/routing/routing-concepts", - "ray": "a4b1a6823d28a270", - "elapsedMs": 16, - "databaseUsed": false, - "phases": [ - { - "name": "db_config", - "startMs": 0, - "durationMs": 0 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 8 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 8 - }, - { - "name": "content_edge_read", - "startMs": 8, - "durationMs": 8 - }, - { - "name": "start_handler", - "startMs": 0, - "durationMs": 16 - } - ] - } - ] - }, - { - "request": 11, - "status": 200, - "ttfb_ms": 1392.7, - "total_ms": 1510.5, - "tls_ms": 79.1, - "ray": "a4b1a68b1cc769f5-DFW", - "server_timing": "cfEdge;dur=905,cfOrigin;dur=0,cfWorker;dur=360", - "cache_control": "private, no-store", - "cf_cache_status": null, - "date": "Thu, 15 Oct 2026 20:42:30 GMT", - "cpu_ms": 165, - "wall_ms": 362, - "version": "3b554871-c23c-4825-9bb4-f9bc27dc5466", - "outcome": "ok", - "docs_timings": [ - { - "logType": "docs_timing", - "workerInstance": "e3c88c49-0501-4898-b6a5-cf830552fc92", - "docsRequest": 1, - "phase": "headers_ready", - "pathname": "/router/latest/docs/routing/routing-concepts", - "ray": "a4b1a68b1cc769f5", - "status": 200, - "headersReadyMs": 197, - "databaseUsed": false, - "phases": [ - { - "name": "db_config", - "startMs": 0, - "durationMs": 0 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 190 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 190 - }, - { - "name": "content_edge_read", - "startMs": 190, - "durationMs": 7 - }, - { - "name": "start_handler", - "startMs": 0, - "durationMs": 197 - } - ] - }, - { - "logType": "docs_timing", - "workerInstance": "e3c88c49-0501-4898-b6a5-cf830552fc92", - "docsRequest": 1, - "phase": "first_body_byte", - "pathname": "/router/latest/docs/routing/routing-concepts", - "ray": "a4b1a68b1cc769f5", - "elapsedMs": 197, - "databaseUsed": false, - "phases": [ - { - "name": "db_config", - "startMs": 0, - "durationMs": 0 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 190 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 190 - }, - { - "name": "content_edge_read", - "startMs": 190, - "durationMs": 7 - }, - { - "name": "start_handler", - "startMs": 0, - "durationMs": 197 - } - ] - }, - { - "logType": "docs_timing", - "workerInstance": "e3c88c49-0501-4898-b6a5-cf830552fc92", - "docsRequest": 1, - "phase": "body_complete", - "pathname": "/router/latest/docs/routing/routing-concepts", - "ray": "a4b1a68b1cc769f5", - "elapsedMs": 197, - "databaseUsed": false, - "phases": [ - { - "name": "db_config", - "startMs": 0, - "durationMs": 0 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 190 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 190 - }, - { - "name": "content_edge_read", - "startMs": 190, - "durationMs": 7 - }, - { - "name": "start_handler", - "startMs": 0, - "durationMs": 197 - } - ] - } - ] - }, - { - "request": 12, - "status": 200, - "ttfb_ms": 271.7, - "total_ms": 392.4, - "tls_ms": 90.8, - "ray": "a4b1a69afceb1974-DFW", - "server_timing": "cfEdge;dur=29,cfOrigin;dur=0,cfWorker;dur=99", - "cache_control": "private, no-store", - "cf_cache_status": null, - "date": "Thu, 15 Oct 2026 20:42:31 GMT", - "cpu_ms": 71, - "wall_ms": 100, - "version": "3b554871-c23c-4825-9bb4-f9bc27dc5466", - "outcome": "ok", - "docs_timings": [ - { - "logType": "docs_timing", - "workerInstance": "0bc0619a-83d0-473f-a9fb-03e1973224d5", - "docsRequest": 8, - "phase": "headers_ready", - "pathname": "/router/latest/docs/routing/routing-concepts", - "ray": "a4b1a69afceb1974", - "status": 200, - "headersReadyMs": 22, - "databaseUsed": false, - "phases": [ - { - "name": "db_config", - "startMs": 0, - "durationMs": 0 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 11 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 11 - }, - { - "name": "content_edge_read", - "startMs": 11, - "durationMs": 11 - }, - { - "name": "start_handler", - "startMs": 0, - "durationMs": 22 - } - ] - }, - { - "logType": "docs_timing", - "workerInstance": "0bc0619a-83d0-473f-a9fb-03e1973224d5", - "docsRequest": 8, - "phase": "first_body_byte", - "pathname": "/router/latest/docs/routing/routing-concepts", - "ray": "a4b1a69afceb1974", - "elapsedMs": 22, - "databaseUsed": false, - "phases": [ - { - "name": "db_config", - "startMs": 0, - "durationMs": 0 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 11 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 11 - }, - { - "name": "content_edge_read", - "startMs": 11, - "durationMs": 11 - }, - { - "name": "start_handler", - "startMs": 0, - "durationMs": 22 - } - ] - }, - { - "logType": "docs_timing", - "workerInstance": "0bc0619a-83d0-473f-a9fb-03e1973224d5", - "docsRequest": 8, - "phase": "body_complete", - "pathname": "/router/latest/docs/routing/routing-concepts", - "ray": "a4b1a69afceb1974", - "elapsedMs": 22, - "databaseUsed": false, - "phases": [ - { - "name": "db_config", - "startMs": 0, - "durationMs": 0 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 11 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 11 - }, - { - "name": "content_edge_read", - "startMs": 11, - "durationMs": 11 - }, - { - "name": "start_handler", - "startMs": 0, - "durationMs": 22 - } - ] - } - ] - } - ], - "notes": [ - "Separate curl process and TLS connection per request, Accept: text/html, one-second pause between requests.", - "First docs request is an observed per-instance counter, not proof of a platform cold start.", - "Exclude five previous-version responses from new-version statistics.", - "Application timing clocks advance with I/O; use platform CPU/wall counters to complement them.", - "This deployment includes the preceding docs fixes and tracing as well as TanChat isolation; results do not isolate any single change." - ] -} diff --git a/docs/worker-cold-start-investigation.md b/docs/worker-cold-start-investigation.md deleted file mode 100644 index 486bb1c4d..000000000 --- a/docs/worker-cold-start-investigation.md +++ /dev/null @@ -1,109 +0,0 @@ -# What makes the first docs request slow - -The largest delay happens before the Worker fetch handler runs. It depends on the uploaded application code, even when that code is never imported or executed by the request. The remaining first-render cost is much smaller and includes real application CPU and content-cache reads. - -This explains why the TanChat import split helped runtime initialization without eliminating the multi-second spikes. The code stayed in the roughly 26,260 KiB Worker upload. Lazy imports control module execution, but do not remove the platform cost associated with carrying that upload. - -## A production request, broken down - -Production version `3b554871-c23c-4825-9bb4-f9bc27dc5466`, ray `a4b1a6436fc13ad3-DFW`: - -| Measurement | Time | -| --------------------------------- | ------: | -| Client time to first byte | 3,271ms | -| Connection/TLS setup | 84ms | -| Reported Cloudflare edge timing | 2,467ms | -| Reported Cloudflare Worker timing | 673ms | -| Tail invocation wall time | 681ms | -| Tail invocation CPU | 370ms | -| Application headers-ready clock | 317ms | - -Worker wall time includes CPU and waiting, so its CPU row must not be added again. After connection setup, roughly 2.5 seconds remain outside the recorded invocation, including network overhead. The small-worker controls below show that ordinary request/response transport accounts for tens of milliseconds in this environment, rather than the multi-second difference. - -The application recorded no database access, no origin content fetch, and no R2 read on this request. Its content came from the blob Cache API path. PostgreSQL and GitHub did not cause this spike. - -The application's 317ms measurement is not a second wall-clock measurement. Deployed Worker clocks advance with I/O and cannot accurately time CPU-only phases. Its two initial content reads ran in parallel. The `content_edge_read` label also includes reading the cached response body, not just `cache.match`. These spans locate work, but do not prove that the entire interval was storage-service latency. [Cloudflare timer behavior](https://developers.cloudflare.com/workers/runtime-apis/performance/) - -## Controlled proof of the pre-handler cost - -Created eight isolated Workers with no production routes, database, application secrets, Durable Objects, or scheduled jobs. The basic probe returns `ok`, records an instance ID and invocation counter, and performs no cache/storage/network operation on `/noop`. All comparisons below used DFW, separate curl connections, and a half-second pause between requests. - -The main timing removes connection setup: `time_starttransfer - time_pretransfer`. It still includes request/response network transit. "First" means the first observed handler invocation on that instance ID, which is a useful proxy rather than proof of a platform code-cache miss. - -| Upload/control | Upload KiB | First-instance samples | Median time after connection | Median invocation CPU / wall | -| --------------------------------------------------------------- | ---------: | ---------------------: | ---------------------------: | ---------------------------: | -| Minimal probe | 1.36 | 11 | 83ms | 0 / 1ms | -| Probe plus entire site upload, never imported | 26,263.71 | 6 | 1,114ms | 0 / 0ms | -| Probe plus static import of actual app, without rendering | 26,263.71 | 8 | 1,419ms | 0 / 0ms | -| Site JavaScript bytes as one inert Data module, excluding WASM | 22,615.06 | 13 | 315ms | 0 / 1ms | -| Entire site JavaScript, with empty diagnostic WASM | 22,617.00 | 16 | 897ms | 0 / 1ms | -| Similar bytes as one inert JavaScript string module | 23,239.25 | 20 | 527ms | 0 / 0ms | -| Similar string data split across 1,000 JavaScript modules | 23,256.81 | 14 | 441ms | 0 / 0.5ms | -| Actual app rebundled into one JS module, original WASM retained | 26,244.80 | 6 | 1,085ms | 0 / 0.5ms | - -The never-imported row uses the second run, after initial workers.dev routing failures. Other controls pool their successful runs. Non-200 platform responses remain in the raw measurements but are excluded from latency summaries. Some newly created probes returned 1042 or 1104, including probes with no application execution. These were not production responses. The later repeat runs for the single-string and empty-WASM controls returned 200 throughout. - -The same large never-imported Worker had a reused-instance median of 76ms after connection, close to the minimal Worker's 67ms. The roughly one-second cold penalty disappears when the instance is reused, despite identical response code and no data access. - -### What the controls establish - -- The production application upload itself causes substantial work before fetch dispatch. The probe can reproduce seconds of latency while the recorded invocation takes 0–2ms. -- Byte volume matters: even inert data adds cold latency. That Data control excludes the original WASM and is not an exact byte-for-byte match of the complete upload. -- Actual application JavaScript has more cold cost than similarly sized inert string/data controls. The platform is doing more than transmitting an equal number of bytes. -- The original OG WebAssembly payload is a contributor, but the JavaScript-only control remains slow. Replacing WASM is only a diagnostic experiment, not a usable application change. -- Module count alone does not explain the result. A thousand simple string modules were not slower than one large string module in these samples. Merging the actual app also left about a second of pre-handler delay. - -These are small sequential samples on different Workers, not randomized additive estimates. The differences should not be summed into an exact per-feature budget. What is directly verified is the dependence on the complete uploaded code and the timing boundary before the application's handler. The experiments cannot separate Cloudflare's internal script retrieval, decoding, compilation, or isolate preparation into individual timers. - -The reported deployment startup times ranged from 1–3ms for the synthetic probes to 35ms for the imported app and 87ms for the rebundle. Those figures did not predict the observed first-request delay. Treat deployment startup validation and real cold request latency as different measurements. - -## What is in that upload - -Source maps identify these large chunks. Sizes are uncompressed KiB from the source-mapped build, with a few extra bytes for map references: - -| Chunk | KiB | Source | -| --------------------------- | ----: | ----------------------------------------------------------------------------------------------------- | -| Iconography browser | 3,715 | `src/routes/ds.iconography.lazy.tsx`, generated Phosphor registry, 2,592 source modules | -| OG renderer WASM | 3,647 | Takumi, reached from `src/server/og/generate.server.ts` | -| AI starter template | 1,855 | `@tanstack/create/dist/generated/worker/frameworks/react/add-ons/ai.js`, generated project files/data | -| TanChat app UI | 1,204 | `src/chat/components/App.tsx` and its component dependencies | -| Chat model runtime | 990 | `src/chat/server/run-models.ts`, provider SDKs and attachment handling | -| Blog collection | 822 | generated `allPosts`, `src/utils/blog.ts`, and formatting | -| Conversation implementation | 673 | `src/chat/server/conversation.ts` and related code | -| Discovery integrations | 578 | chat discovery/integration dependencies | - -Most of this code is unrelated to rendering a docs page. The previous TanChat change correctly removed its implementation from the docs runtime import path, but the lazy chunks still ship as modules in the same Worker. - -## The first docs render, after the platform loads the Worker - -The actual-app probe returned valid docs pages. Three requests that both created a probe instance and rendered docs used 306–346ms of invocation CPU and 559–677ms of invocation wall time. The separate pre-handler delay was still present. - -On the local production build with warm content storage, the first docs response took 135ms to headers, versus 24ms on repeat. Source-mapped CPU samples located work in: - -- cached JSON parsing, especially `readStoredValue` in `src/utils/github-content-cache.server.ts`; -- partner sorting through `comparePartnerIdentity` and its first `localeCompare` calls; -- loading the complete generated blog collection; -- route manifest construction and runtime module initialization; -- React rendering, TanStack Redact traversal, serialization, and Tailwind class merging. - -Examples of local sampled self time were about 8.5ms in cached JSON parsing, 7.4ms in partner comparison, and 5.4ms in blog module initialization. These samples identify functions, not production timings. The profiler also captures runtime/inspector work outside the HTTP interval, so its total sampled active time is not presented as request CPU. - -The standalone binding probes were much smaller than the worst pre-handler delay: three Cache API miss operations took 6–33ms of recorded wall time, and three R2 HEAD miss operations took 111–130ms. These probes are not identical to reading populated docs cache bodies and cannot replace native traces for the actual hit path. - -## What would address the cause - -The next optimization needs to remove bytes and code from the docs-serving Worker upload. More dynamic imports inside the same upload do not address the demonstrated platform cost. - -The largest candidates are moving the client-only icon catalog out of server output, serving generated project template data as assets, and putting OG generation and TanChat behind separate Worker boundaries. Splitting TanChat also needs a deliberate Durable Object namespace plan. Those are proposed follow-up changes, not deployed fixes from this investigation. - -The monolithic rebundle is not recommended: its pre-handler delay persisted and its first docs renders used more CPU, reaching 854ms in this small sample. - -For Cloudflare support, the exact remaining platform question is: which operations account for the gap between HTTP arrival and fetch dispatch when an unused 26MB code upload is attached? The minimal-vs-unimported reproduction avoids framework rendering and storage entirely. Exact internal attribution to code retrieval versus compilation requires platform telemetry beyond the exposed invocation records. - -## Trace access and evidence - -Production native Cloudflare tracing was disabled, although logs and the separate Sentry SDK were configured. Native tracing was enabled on the isolated probes. The native telemetry query endpoint returned 403 with the available credentials, so no native binding span breakdown is claimed. The production CPU profile API succeeded but selected an idle isolate and contained no useful execution samples. That profiler targets an already-loaded isolate and cannot directly profile the preceding load delay. [Cloudflare production profiling](https://developers.cloudflare.com/workers/observability/profiling-in-production/) - -`worker-cold-start-measurements.json` contains 220 probe request records, version IDs, platform CPU/wall measurements, source rankings, and local CPU attribution. `docs-production-performance-measurements.json` contains the production request above. Archived probe and measurement templates are in `worker-cold-start-probes`. - -No production code or cache settings were changed during this investigation. Temporary diagnostic Workers are removed after capture; cleanup results are recorded alongside the measurements. diff --git a/docs/worker-cold-start-measurements.json b/docs/worker-cold-start-measurements.json deleted file mode 100644 index e4d594156..000000000 --- a/docs/worker-cold-start-measurements.json +++ /dev/null @@ -1,8123 +0,0 @@ -{ - "date": "2026-10-15", - "region": "DFW", - "method": "Separate curl connection per request, 0.5 second gaps. after_connection_ms = 1000 * (time_starttransfer - time_pretransfer). First means observed handler count 1 on a generated instance ID. Platform timings joined by cf-ray.", - "scope": "Isolated workers.dev probes, no production routes, application secrets, database, Durable Object bindings, or scheduled tasks. Existing docs content R2 bucket was bound for read probes and cached docs rendering.", - "controls": { - "minimal": "1.36 KiB probe only", - "tiny": "Same probe, but entire site module upload present and never imported", - "full": "Static import of actual application, same probe plus real docs", - "data": "JS bytes concatenated as one inert Data module; no actual site JS or WASM modules", - "no-wasm": "All site JavaScript retained, original compiled OG WASM replaced by empty valid WASM for diagnostic noop calls only", - "single-js": "JS bytes encoded as inert exported string in one module", - "many-js": "Same string data distributed over 1000 exported-string modules", - "monolith": "Actual app rebundled by esbuild into one JS app module, retaining original WASM, plus probe entry" - }, - "important_limits": [ - "First observed invocation is not proof of a platform code-cache miss.", - "Synthetic controls isolate factors but timings are not additive and were not randomized.", - "Non-200 platform responses are retained and excluded from latency summaries.", - "No-wasm control cannot render OG images and is not an application fix.", - "Monolithic rebundle was diagnostic only and was not deployed to production.", - "Reported startup validation time and invocation CPU/wall do not cover all observed pre-handler delay.", - "Native trace query API returned 403 with available credentials. Production native tracing was disabled; probe tracing was enabled.", - "Remote production profile succeeded but contained only root/idle samples, so it does not attribute cold loading." - ], - "workers": [ - { - "worker": "minimal", - "deployed_name": "tanstack-cold-probe-minimal", - "version": "994eeeda-9b1b-44aa-bd93-f11f5a7ca04b", - "upload_kib": 1.36, - "gzip_kib": 0.57, - "reported_startup_ms": 2, - "runs": { - "initial": [ - { - "worker": "minimal", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 202.1, - "total_ms": 204.6, - "tls_ms": 129.2, - "after_connection_ms": 72.8, - "ray": "a4b1ad6b9f70dc12-DFW", - "instance": "140c9fe5-7462-4d82-8a9b-a08772838d52", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "994eeeda-9b1b-44aa-bd93-f11f5a7ca04b" - }, - { - "worker": "minimal", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 154.1, - "total_ms": 154.3, - "tls_ms": 86.2, - "after_connection_ms": 67.8, - "ray": "a4b1ad6fdc82e7af-DFW", - "instance": "4a65acb8-fa22-4c73-bb87-2d9283a70bf9", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 1, - "version": "994eeeda-9b1b-44aa-bd93-f11f5a7ca04b" - }, - { - "worker": "minimal", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 150.7, - "total_ms": 151.1, - "tls_ms": 83.2, - "after_connection_ms": 67.4, - "ray": "a4b1ad73f961fa54-DFW", - "instance": "3858ef92-e0b2-404c-9058-905563a1464c", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "994eeeda-9b1b-44aa-bd93-f11f5a7ca04b" - }, - { - "worker": "minimal", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 149.9, - "total_ms": 150.3, - "tls_ms": 78.1, - "after_connection_ms": 71.8, - "ray": "a4b1ad781d583cd3-DFW", - "instance": "140c9fe5-7462-4d82-8a9b-a08772838d52", - "instance_request": "2", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 3, - "version": "994eeeda-9b1b-44aa-bd93-f11f5a7ca04b" - }, - { - "worker": "minimal", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 183.7, - "total_ms": 185.9, - "tls_ms": 79.8, - "after_connection_ms": 103.8, - "ray": "a4b1ad7c4f6b45e0-DFW", - "instance": "46b5d0c8-f4ec-4adf-bea8-dd5dc67f6edb", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null - }, - { - "worker": "minimal", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 146.5, - "total_ms": 148.9, - "tls_ms": 82.2, - "after_connection_ms": 64.3, - "ray": "a4b1ad80ad545fd1-DFW", - "instance": "3858ef92-e0b2-404c-9058-905563a1464c", - "instance_request": "2", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "994eeeda-9b1b-44aa-bd93-f11f5a7ca04b" - }, - { - "worker": "minimal", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 149.9, - "total_ms": 150.4, - "tls_ms": 79.8, - "after_connection_ms": 70.1, - "ray": "a4b1ad84d80c2fc2-DFW", - "instance": "4a65acb8-fa22-4c73-bb87-2d9283a70bf9", - "instance_request": "2", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 1, - "version": "994eeeda-9b1b-44aa-bd93-f11f5a7ca04b" - }, - { - "worker": "minimal", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 194.6, - "total_ms": 195.0, - "tls_ms": 79.9, - "after_connection_ms": 114.6, - "ray": "a4b1ad88f8abf02e-DFW", - "instance": "b7e7af54-9470-47d3-b1b0-2fc0fe275b62", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "994eeeda-9b1b-44aa-bd93-f11f5a7ca04b" - }, - { - "worker": "minimal", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 145.4, - "total_ms": 145.8, - "tls_ms": 78.7, - "after_connection_ms": 66.7, - "ray": "a4b1ad8d6c849bde-DFW", - "instance": "140c9fe5-7462-4d82-8a9b-a08772838d52", - "instance_request": "3", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "994eeeda-9b1b-44aa-bd93-f11f5a7ca04b" - }, - { - "worker": "minimal", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 151.1, - "total_ms": 151.4, - "tls_ms": 79.1, - "after_connection_ms": 71.9, - "ray": "a4b1ad918baaf06a-DFW", - "instance": "b7e7af54-9470-47d3-b1b0-2fc0fe275b62", - "instance_request": "2", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "994eeeda-9b1b-44aa-bd93-f11f5a7ca04b" - }, - { - "worker": "minimal", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 163.5, - "total_ms": 165.8, - "tls_ms": 79.6, - "after_connection_ms": 83.8, - "ray": "a4b1ad95bfc46c55-DFW", - "instance": "048e5114-d442-4985-8f8f-b7b192e84db1", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 1, - "wall_ms": 2, - "version": "994eeeda-9b1b-44aa-bd93-f11f5a7ca04b" - }, - { - "worker": "minimal", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 147.8, - "total_ms": 148.1, - "tls_ms": 81.7, - "after_connection_ms": 66.1, - "ray": "a4b1ad9a0a2dc05d-DFW", - "instance": "546e662b-64ff-456f-9ad7-4ce28c752276", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "994eeeda-9b1b-44aa-bd93-f11f5a7ca04b" - }, - { - "worker": "minimal", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 262.7, - "total_ms": 265.1, - "tls_ms": 89.1, - "after_connection_ms": 173.6, - "ray": "a4b1ad9e2a2969f8-DFW", - "instance": "612cca99-a59c-4454-a7bd-d37d8f6f960d", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 1, - "wall_ms": 3, - "version": "994eeeda-9b1b-44aa-bd93-f11f5a7ca04b" - }, - { - "worker": "minimal", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 171.9, - "total_ms": 172.2, - "tls_ms": 83.9, - "after_connection_ms": 88.0, - "ray": "a4b1ada2f9a84796-DFW", - "instance": "44313d34-67d1-4ab1-bf0a-9be22bca4d11", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 1, - "wall_ms": 2, - "version": "994eeeda-9b1b-44aa-bd93-f11f5a7ca04b" - }, - { - "worker": "minimal", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 176.0, - "total_ms": 178.3, - "tls_ms": 130.3, - "after_connection_ms": 45.6, - "ray": "a4b1ada79d5e45fe-DFW", - "instance": "4a65acb8-fa22-4c73-bb87-2d9283a70bf9", - "instance_request": "3", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "994eeeda-9b1b-44aa-bd93-f11f5a7ca04b" - }, - { - "worker": "minimal", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 166.6, - "total_ms": 168.9, - "tls_ms": 83.9, - "after_connection_ms": 82.6, - "ray": "a4b1adabacb6e68b-DFW", - "instance": "403ed82b-38e9-4623-8856-74db379ce24b", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 1, - "wall_ms": 2, - "version": "994eeeda-9b1b-44aa-bd93-f11f5a7ca04b" - }, - { - "worker": "minimal", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 134.8, - "total_ms": 137.2, - "tls_ms": 84.7, - "after_connection_ms": 50.1, - "ray": "a4b1adaffa1babf8-DFW", - "instance": "a28c01f9-72df-4373-b844-bb59aa4ab146", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 1, - "version": "994eeeda-9b1b-44aa-bd93-f11f5a7ca04b" - }, - { - "worker": "minimal", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 139.7, - "total_ms": 142.0, - "tls_ms": 79.3, - "after_connection_ms": 60.3, - "ray": "a4b1adb41ef80864-DFW", - "instance": "3858ef92-e0b2-404c-9058-905563a1464c", - "instance_request": "3", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "994eeeda-9b1b-44aa-bd93-f11f5a7ca04b" - }, - { - "worker": "minimal", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 144.1, - "total_ms": 146.1, - "tls_ms": 80.0, - "after_connection_ms": 64.0, - "ray": "a4b1adb83cb6f35f-DFW", - "instance": "546e662b-64ff-456f-9ad7-4ce28c752276", - "instance_request": "2", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "994eeeda-9b1b-44aa-bd93-f11f5a7ca04b" - }, - { - "worker": "minimal", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 148.8, - "total_ms": 149.1, - "tls_ms": 81.7, - "after_connection_ms": 67.0, - "ray": "a4b1adbc5ecb0364-DFW", - "instance": "3858ef92-e0b2-404c-9058-905563a1464c", - "instance_request": "4", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "994eeeda-9b1b-44aa-bd93-f11f5a7ca04b" - } - ] - } - }, - { - "worker": "tiny", - "deployed_name": "tanstack-cold-probe-tiny", - "version": "b7cde89f-c6e2-49e9-b2b5-034bd731e6a1", - "upload_kib": 26263.71, - "gzip_kib": 8459.83, - "reported_startup_ms": 3, - "runs": { - "initial": [ - { - "worker": "tiny", - "run": "initial", - "path": "/noop", - "status": 404, - "ttfb_ms": 1045.3, - "total_ms": 1045.5, - "tls_ms": 732.7, - "ray": "a4b1abfaff64c55c-DFW", - "instance": null, - "instance_request": null, - "phase_ms": null, - "server_timing": null - }, - { - "worker": "tiny", - "run": "initial", - "path": "/noop", - "status": 404, - "ttfb_ms": 619.2, - "total_ms": 621.5, - "tls_ms": 428.6, - "ray": "a4b1ac01dc573470-DFW", - "instance": null, - "instance_request": null, - "phase_ms": null, - "server_timing": null - }, - { - "worker": "tiny", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 2867.0, - "total_ms": 2867.2, - "tls_ms": 264.5, - "ray": "a4b1ac07ef0d46d4-DFW", - "instance": "28b7af4d-c44c-49fd-a1d1-a28e2cea134c", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 2, - "version": "b7cde89f-c6e2-49e9-b2b5-034bd731e6a1" - }, - { - "worker": "tiny", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 589.9, - "total_ms": 592.0, - "tls_ms": 348.0, - "ray": "a4b1ac1dd9b43ac6-DFW", - "instance": "55cadb14-ed85-4c98-ba09-c2ee66798df9", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 1, - "wall_ms": 2, - "version": "b7cde89f-c6e2-49e9-b2b5-034bd731e6a1" - }, - { - "worker": "tiny", - "run": "initial", - "path": "/noop", - "status": 404, - "ttfb_ms": 653.3, - "total_ms": 653.8, - "tls_ms": 412.0, - "ray": "a4b1ac256df1d132-DFW", - "instance": null, - "instance_request": null, - "phase_ms": null, - "server_timing": null - }, - { - "worker": "tiny", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 2460.6, - "total_ms": 2461.0, - "tls_ms": 713.7, - "ray": "a4b1ac300f733467-DFW", - "instance": "7a247333-b00c-45e7-83d4-45791f4db0a3", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null - }, - { - "worker": "tiny", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 1983.6, - "total_ms": 1984.0, - "tls_ms": 734.4, - "ray": "a4b1ac426fc1a922-DFW", - "instance": "2a80dc96-e1db-4c95-8e2f-39aeb113f2d0", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null - }, - { - "worker": "tiny", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 1912.6, - "total_ms": 1913.2, - "tls_ms": 1016.9, - "ray": "a4b1ac54bc0b0dc1-DFW", - "instance": "f8fd25a1-7f7c-4df5-bcf9-6b50b1451d07", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "b7cde89f-c6e2-49e9-b2b5-034bd731e6a1" - }, - { - "worker": "tiny", - "run": "initial", - "path": "/cache", - "status": 200, - "ttfb_ms": 1561.5, - "total_ms": 1562.1, - "tls_ms": 766.5, - "ray": "a4b1ac617d43f085-DFW", - "instance": "6624a15a-bb98-4f51-a04a-51946e16dc20", - "instance_request": "1", - "phase_ms": "19", - "server_timing": null, - "cpu_ms": 1, - "wall_ms": 19, - "version": "b7cde89f-c6e2-49e9-b2b5-034bd731e6a1" - }, - { - "worker": "tiny", - "run": "initial", - "path": "/cache", - "status": 200, - "ttfb_ms": 1684.5, - "total_ms": 1685.1, - "tls_ms": 951.0, - "ray": "a4b1ac707b472ccd-DFW", - "instance": "0916c084-f903-44d5-9e2e-876155768171", - "instance_request": "1", - "phase_ms": "9", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 9, - "version": "b7cde89f-c6e2-49e9-b2b5-034bd731e6a1" - }, - { - "worker": "tiny", - "run": "initial", - "path": "/cache", - "status": 200, - "ttfb_ms": 1834.8, - "total_ms": 1837.4, - "tls_ms": 920.3, - "ray": "a4b1ac7db83d4403-DFW", - "instance": "d9c8c14c-952f-4a1e-8245-df948b9f20e7", - "instance_request": "1", - "phase_ms": "18", - "server_timing": null, - "cpu_ms": 1, - "wall_ms": 19, - "version": "b7cde89f-c6e2-49e9-b2b5-034bd731e6a1" - }, - { - "worker": "tiny", - "run": "initial", - "path": "/r2", - "status": 200, - "ttfb_ms": 2100.8, - "total_ms": 2101.1, - "tls_ms": 1103.2, - "ray": "a4b1ac8cba783b9b-DFW", - "instance": "dbd26777-8535-4042-87d4-10bf0b52b3bf", - "instance_request": "1", - "phase_ms": "156", - "server_timing": null, - "cpu_ms": 1, - "wall_ms": 158, - "version": "b7cde89f-c6e2-49e9-b2b5-034bd731e6a1" - }, - { - "worker": "tiny", - "run": "initial", - "path": "/r2", - "status": 200, - "ttfb_ms": 1774.2, - "total_ms": 1774.6, - "tls_ms": 873.5, - "ray": "a4b1ac9c8eb8acd3-DFW", - "instance": "64e56fa2-c5d7-4461-89f0-458223828f29", - "instance_request": "1", - "phase_ms": "124", - "server_timing": null, - "cpu_ms": 1, - "wall_ms": 127, - "version": "b7cde89f-c6e2-49e9-b2b5-034bd731e6a1" - }, - { - "worker": "tiny", - "run": "initial", - "path": "/r2", - "status": 200, - "ttfb_ms": 2509.1, - "total_ms": 2509.7, - "tls_ms": 1093.9, - "ray": "a4b1acac78c94654-DFW", - "instance": "823a52c1-b8c9-4df4-b1b1-3239a7698f49", - "instance_request": "1", - "phase_ms": "134", - "server_timing": null, - "cpu_ms": 1, - "wall_ms": 137, - "version": "b7cde89f-c6e2-49e9-b2b5-034bd731e6a1" - } - ], - "repeat": [ - { - "worker": "tiny", - "run": "repeat", - "path": "/noop", - "status": 200, - "ttfb_ms": 157.1, - "total_ms": 159.4, - "tls_ms": 79.7, - "after_connection_ms": 77.3, - "ray": "a4b1ad517bda46ce-DFW", - "instance": "823a52c1-b8c9-4df4-b1b1-3239a7698f49", - "instance_request": "2", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 1, - "version": "b7cde89f-c6e2-49e9-b2b5-034bd731e6a1" - }, - { - "worker": "tiny", - "run": "repeat", - "path": "/noop", - "status": 200, - "ttfb_ms": 1003.1, - "total_ms": 1006.1, - "tls_ms": 81.8, - "after_connection_ms": 921.2, - "ray": "a4b1ad55cc5a69bf-DFW", - "instance": "e8b88151-0d30-44e4-bc66-de6b8257e369", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "b7cde89f-c6e2-49e9-b2b5-034bd731e6a1" - }, - { - "worker": "tiny", - "run": "repeat", - "path": "/noop", - "status": 200, - "ttfb_ms": 164.6, - "total_ms": 166.9, - "tls_ms": 86.4, - "after_connection_ms": 78.2, - "ray": "a4b1ad5f5cde9bde-DFW", - "instance": "f8fd25a1-7f7c-4df5-bcf9-6b50b1451d07", - "instance_request": "2", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "b7cde89f-c6e2-49e9-b2b5-034bd731e6a1" - }, - { - "worker": "tiny", - "run": "repeat", - "path": "/noop", - "status": 200, - "ttfb_ms": 1385.5, - "total_ms": 1385.9, - "tls_ms": 78.5, - "after_connection_ms": 1307.0, - "ray": "a4b1ad6388ffb52d-DFW", - "instance": "9a4d0d14-19d4-4a68-86f8-5a35063903d4", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "b7cde89f-c6e2-49e9-b2b5-034bd731e6a1" - }, - { - "worker": "tiny", - "run": "repeat", - "path": "/noop", - "status": 200, - "ttfb_ms": 172.4, - "total_ms": 174.8, - "tls_ms": 92.5, - "after_connection_ms": 79.8, - "ray": "a4b1ad6f8b51daec-DFW", - "instance": "d9c8c14c-952f-4a1e-8245-df948b9f20e7", - "instance_request": "2", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "b7cde89f-c6e2-49e9-b2b5-034bd731e6a1" - }, - { - "worker": "tiny", - "run": "repeat", - "path": "/noop", - "status": 200, - "ttfb_ms": 167.3, - "total_ms": 169.4, - "tls_ms": 83.2, - "after_connection_ms": 84.0, - "ray": "a4b1ad73ce998f63-DFW", - "instance": "d9c8c14c-952f-4a1e-8245-df948b9f20e7", - "instance_request": "3", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "b7cde89f-c6e2-49e9-b2b5-034bd731e6a1" - }, - { - "worker": "tiny", - "run": "repeat", - "path": "/noop", - "status": 200, - "ttfb_ms": 164.4, - "total_ms": 167.1, - "tls_ms": 85.4, - "after_connection_ms": 79.0, - "ray": "a4b1ad781978f2f6-DFW", - "instance": "40a5cd14-6082-4411-b78f-5f06349ad02e", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "b7cde89f-c6e2-49e9-b2b5-034bd731e6a1" - }, - { - "worker": "tiny", - "run": "repeat", - "path": "/noop", - "status": 200, - "ttfb_ms": 1801.8, - "total_ms": 1804.3, - "tls_ms": 81.9, - "after_connection_ms": 1719.9, - "ray": "a4b1ad7c4fbd6c32-DFW", - "instance": "b37b7d50-41e8-4e3a-ac0c-2fe089ad7b17", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 3, - "wall_ms": 6, - "version": "b7cde89f-c6e2-49e9-b2b5-034bd731e6a1" - }, - { - "worker": "tiny", - "run": "repeat", - "path": "/noop", - "status": 200, - "ttfb_ms": 150.8, - "total_ms": 151.0, - "tls_ms": 82.2, - "after_connection_ms": 68.5, - "ray": "a4b1ad8acbb0f2f0-DFW", - "instance": "40a5cd14-6082-4411-b78f-5f06349ad02e", - "instance_request": "2", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "b7cde89f-c6e2-49e9-b2b5-034bd731e6a1" - }, - { - "worker": "tiny", - "run": "repeat", - "path": "/noop", - "status": 200, - "ttfb_ms": 684.9, - "total_ms": 685.0, - "tls_ms": 78.5, - "after_connection_ms": 606.3, - "ray": "a4b1ad8efc023239-DFW", - "instance": "f0434608-eab7-4896-ab27-91f574d9c0fd", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "b7cde89f-c6e2-49e9-b2b5-034bd731e6a1" - }, - { - "worker": "tiny", - "run": "repeat", - "path": "/noop", - "status": 200, - "ttfb_ms": 189.5, - "total_ms": 189.8, - "tls_ms": 86.1, - "after_connection_ms": 103.4, - "ray": "a4b1ad96894c6b40-DFW", - "instance": "b37b7d50-41e8-4e3a-ac0c-2fe089ad7b17", - "instance_request": "2", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 1, - "version": "b7cde89f-c6e2-49e9-b2b5-034bd731e6a1" - }, - { - "worker": "tiny", - "run": "repeat", - "path": "/noop", - "status": 200, - "ttfb_ms": 153.5, - "total_ms": 155.9, - "tls_ms": 81.6, - "after_connection_ms": 71.9, - "ray": "a4b1ad9aed27188a-DFW", - "instance": "f8fd25a1-7f7c-4df5-bcf9-6b50b1451d07", - "instance_request": "3", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "b7cde89f-c6e2-49e9-b2b5-034bd731e6a1" - }, - { - "worker": "tiny", - "run": "repeat", - "path": "/noop", - "status": 200, - "ttfb_ms": 145.5, - "total_ms": 145.7, - "tls_ms": 81.1, - "after_connection_ms": 64.4, - "ray": "a4b1ad9f0b603822-DFW", - "instance": "9a4d0d14-19d4-4a68-86f8-5a35063903d4", - "instance_request": "2", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "b7cde89f-c6e2-49e9-b2b5-034bd731e6a1" - }, - { - "worker": "tiny", - "run": "repeat", - "path": "/noop", - "status": 200, - "ttfb_ms": 160.4, - "total_ms": 163.5, - "tls_ms": 82.4, - "after_connection_ms": 78.0, - "ray": "a4b1ada33a871427-DFW", - "instance": "f0434608-eab7-4896-ab27-91f574d9c0fd", - "instance_request": "2", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "b7cde89f-c6e2-49e9-b2b5-034bd731e6a1" - }, - { - "worker": "tiny", - "run": "repeat", - "path": "/noop", - "status": 200, - "ttfb_ms": 194.5, - "total_ms": 196.9, - "tls_ms": 119.5, - "after_connection_ms": 75.0, - "ray": "a4b1ada7ce5e5aba-DFW", - "instance": "f8fd25a1-7f7c-4df5-bcf9-6b50b1451d07", - "instance_request": "4", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "b7cde89f-c6e2-49e9-b2b5-034bd731e6a1" - }, - { - "worker": "tiny", - "run": "repeat", - "path": "/noop", - "status": 200, - "ttfb_ms": 186.8, - "total_ms": 189.3, - "tls_ms": 83.2, - "after_connection_ms": 103.6, - "ray": "a4b1adac0eb9feb2-DFW", - "instance": "f8fd25a1-7f7c-4df5-bcf9-6b50b1451d07", - "instance_request": "5", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "b7cde89f-c6e2-49e9-b2b5-034bd731e6a1" - }, - { - "worker": "tiny", - "run": "repeat", - "path": "/noop", - "status": 200, - "ttfb_ms": 144.0, - "total_ms": 146.3, - "tls_ms": 85.3, - "after_connection_ms": 58.6, - "ray": "a4b1adb07ed1b1c9-DFW", - "instance": "dbd26777-8535-4042-87d4-10bf0b52b3bf", - "instance_request": "2", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "b7cde89f-c6e2-49e9-b2b5-034bd731e6a1" - }, - { - "worker": "tiny", - "run": "repeat", - "path": "/noop", - "status": 200, - "ttfb_ms": 158.9, - "total_ms": 159.3, - "tls_ms": 101.0, - "after_connection_ms": 57.8, - "ray": "a4b1adb4c8d0f050-DFW", - "instance": "6624a15a-bb98-4f51-a04a-51946e16dc20", - "instance_request": "2", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "b7cde89f-c6e2-49e9-b2b5-034bd731e6a1" - }, - { - "worker": "tiny", - "run": "repeat", - "path": "/noop", - "status": 200, - "ttfb_ms": 142.2, - "total_ms": 144.4, - "tls_ms": 79.2, - "after_connection_ms": 62.9, - "ray": "a4b1adb8d98b61f3-DFW", - "instance": "d9c8c14c-952f-4a1e-8245-df948b9f20e7", - "instance_request": "4", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "b7cde89f-c6e2-49e9-b2b5-034bd731e6a1" - }, - { - "worker": "tiny", - "run": "repeat", - "path": "/noop", - "status": 200, - "ttfb_ms": 3223.5, - "total_ms": 3224.3, - "tls_ms": 82.2, - "after_connection_ms": 3141.2, - "ray": "a4b1adbcfaaaddab-DFW", - "instance": "f8957529-54d5-4e05-a5c2-24ccbad1d7c1", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 1, - "wall_ms": 2, - "version": "b7cde89f-c6e2-49e9-b2b5-034bd731e6a1" - } - ] - } - }, - { - "worker": "full", - "deployed_name": "tanstack-cold-probe-full", - "version": "54beb47a-1efb-4147-bb66-5c2ae0a3a79a", - "upload_kib": 26263.71, - "gzip_kib": 8459.83, - "reported_startup_ms": 35, - "runs": { - "initial": [ - { - "worker": "full", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 2115.7, - "total_ms": 2118.0, - "tls_ms": 370.5, - "after_connection_ms": 1745.1, - "ray": "a4b1aec4fc13f07d-DFW", - "instance": "b51e6b64-daba-4e54-82d3-a3682eb06278", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "54beb47a-1efb-4147-bb66-5c2ae0a3a79a" - }, - { - "worker": "full", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 2324.7, - "total_ms": 2324.9, - "tls_ms": 838.0, - "after_connection_ms": 1486.6, - "ray": "a4b1aedb5b814c1c-DFW", - "instance": "d5ab29e2-1670-46ca-a6ae-238b4287dd4e", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "54beb47a-1efb-4147-bb66-5c2ae0a3a79a" - }, - { - "worker": "full", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 2124.7, - "total_ms": 2128.7, - "tls_ms": 773.4, - "after_connection_ms": 1351.3, - "ray": "a4b1aeebde16f2a1-DFW", - "instance": "c3d79444-3537-4ded-b045-faff1bbd9bad", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "54beb47a-1efb-4147-bb66-5c2ae0a3a79a" - }, - { - "worker": "full", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 2377.4, - "total_ms": 2379.6, - "tls_ms": 80.6, - "after_connection_ms": 2296.7, - "ray": "a4b1aef5ed5f45ef-DFW", - "instance": "ee0f077c-ea19-460b-bec2-6e28d993d288", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 1, - "version": "54beb47a-1efb-4147-bb66-5c2ae0a3a79a" - }, - { - "worker": "full", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 734.8, - "total_ms": 737.2, - "tls_ms": 79.7, - "after_connection_ms": 655.0, - "ray": "a4b1af07f8b32d47-DFW", - "instance": "0483f208-6fd6-40d9-8f1c-fed7ad932bd5", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "54beb47a-1efb-4147-bb66-5c2ae0a3a79a" - }, - { - "worker": "full", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 1107.6, - "total_ms": 1108.0, - "tls_ms": 88.7, - "after_connection_ms": 1018.9, - "ray": "a4b1af0fe9b2488b-DFW", - "instance": "ceb72b82-916e-49a4-9319-3b8343dc0341", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "54beb47a-1efb-4147-bb66-5c2ae0a3a79a" - }, - { - "worker": "full", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 1080.8, - "total_ms": 1083.1, - "tls_ms": 80.0, - "after_connection_ms": 1000.7, - "ray": "a4b1af19fa4ad41c-DFW", - "instance": "ed97f006-eb46-46f2-843f-f754371aaeca", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 1, - "version": "54beb47a-1efb-4147-bb66-5c2ae0a3a79a" - }, - { - "worker": "full", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 2334.3, - "total_ms": 2334.5, - "tls_ms": 82.8, - "after_connection_ms": 2251.4, - "ray": "a4b1af2408136be0-DFW", - "instance": "c981cee4-e136-4863-8a87-25ab87c5f1f2", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 1, - "wall_ms": 2, - "version": "54beb47a-1efb-4147-bb66-5c2ae0a3a79a" - }, - { - "worker": "full", - "run": "initial", - "path": "/cache", - "status": 200, - "ttfb_ms": 168.7, - "total_ms": 171.3, - "tls_ms": 85.2, - "after_connection_ms": 83.4, - "ray": "a4b1af35dbc25cf4-DFW", - "instance": "c3d79444-3537-4ded-b045-faff1bbd9bad", - "instance_request": "2", - "phase_ms": "25", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 24, - "version": "54beb47a-1efb-4147-bb66-5c2ae0a3a79a" - }, - { - "worker": "full", - "run": "initial", - "path": "/cache", - "status": 200, - "ttfb_ms": 2359.6, - "total_ms": 2362.0, - "tls_ms": 82.4, - "after_connection_ms": 2277.2, - "ray": "a4b1af3a2a273587-DFW", - "instance": "41b888c7-340e-4791-afa3-3abd98e67325", - "instance_request": "1", - "phase_ms": "32", - "server_timing": null, - "cpu_ms": 1, - "wall_ms": 33, - "version": "54beb47a-1efb-4147-bb66-5c2ae0a3a79a" - }, - { - "worker": "full", - "run": "initial", - "path": "/cache", - "status": 200, - "ttfb_ms": 202.9, - "total_ms": 203.2, - "tls_ms": 79.1, - "after_connection_ms": 123.7, - "ray": "a4b1af4c1a5d8617-DFW", - "instance": "c3d79444-3537-4ded-b045-faff1bbd9bad", - "instance_request": "3", - "phase_ms": "6", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 6, - "version": "54beb47a-1efb-4147-bb66-5c2ae0a3a79a" - }, - { - "worker": "full", - "run": "initial", - "path": "/r2", - "status": 200, - "ttfb_ms": 272.3, - "total_ms": 274.6, - "tls_ms": 80.2, - "after_connection_ms": 192.0, - "ray": "a4b1af50aa7187f4-DFW", - "instance": "0483f208-6fd6-40d9-8f1c-fed7ad932bd5", - "instance_request": "2", - "phase_ms": "123", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 123, - "version": "54beb47a-1efb-4147-bb66-5c2ae0a3a79a" - }, - { - "worker": "full", - "run": "initial", - "path": "/r2", - "status": 200, - "ttfb_ms": 321.5, - "total_ms": 323.7, - "tls_ms": 80.5, - "after_connection_ms": 241.0, - "ray": "a4b1af55afb947a3-DFW", - "instance": "ee0f077c-ea19-460b-bec2-6e28d993d288", - "instance_request": "2", - "phase_ms": "127", - "server_timing": null, - "cpu_ms": 1, - "wall_ms": 130, - "version": "54beb47a-1efb-4147-bb66-5c2ae0a3a79a" - }, - { - "worker": "full", - "run": "initial", - "path": "/r2", - "status": 200, - "ttfb_ms": 1950.9, - "total_ms": 1953.4, - "tls_ms": 84.6, - "after_connection_ms": 1866.1, - "ray": "a4b1af5aee05e7db-DFW", - "instance": "5d525f91-5667-491a-b7fb-fdb89fc97ee5", - "instance_request": "1", - "phase_ms": "109", - "server_timing": null, - "cpu_ms": 1, - "wall_ms": 111, - "version": "54beb47a-1efb-4147-bb66-5c2ae0a3a79a" - }, - { - "worker": "full", - "run": "initial", - "path": "/docs", - "status": 200, - "ttfb_ms": 522.8, - "total_ms": 654.4, - "tls_ms": 83.5, - "after_connection_ms": 439.2, - "ray": "a4b1af6a6e78a75c-DFW", - "instance": "0483f208-6fd6-40d9-8f1c-fed7ad932bd5", - "instance_request": "3", - "phase_ms": "0", - "server_timing": "app_headers;dur=139.0, db_config;dur=0.0, content_edge_read;dur=268.0, start_handler;dur=139.0, db_used;desc=\"false\", docs_request;desc=\"1\"", - "cpu_ms": 245, - "wall_ms": 1137, - "docs_timing": { - "logType": "docs_timing", - "workerInstance": "8759406b-5f28-4f0a-aa41-024c1800cb0f", - "docsRequest": 1, - "phase": "headers_ready", - "pathname": "/router/latest/docs/routing/routing-concepts", - "ray": "a4b1af6a6e78a75c", - "status": 200, - "headersReadyMs": 139, - "databaseUsed": false, - "phases": [ - { - "name": "db_config", - "startMs": 0, - "durationMs": 0 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 123 - }, - { - "name": "content_edge_read", - "startMs": 123, - "durationMs": 6 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 129 - }, - { - "name": "content_edge_read", - "startMs": 129, - "durationMs": 10 - }, - { - "name": "start_handler", - "startMs": 0, - "durationMs": 139 - } - ] - }, - "version": "54beb47a-1efb-4147-bb66-5c2ae0a3a79a" - }, - { - "worker": "full", - "run": "initial", - "path": "/docs", - "status": 200, - "ttfb_ms": 2047.0, - "total_ms": 2162.7, - "tls_ms": 84.3, - "after_connection_ms": 1962.6, - "ray": "a4b1af71bf586a08-DFW", - "instance": "913c24a0-5e5f-4c6e-9e23-8d2d110d3db2", - "instance_request": "1", - "phase_ms": "0", - "server_timing": "app_headers;dur=292.0, db_config;dur=0.0, content_edge_read;dur=575.0, start_handler;dur=292.0, db_used;desc=\"false\", docs_request;desc=\"1\"", - "cpu_ms": 306, - "wall_ms": 588, - "docs_timing": { - "logType": "docs_timing", - "workerInstance": "7ad7a15b-2e10-45cb-8fe3-879373eb0cb3", - "docsRequest": 1, - "phase": "headers_ready", - "pathname": "/router/latest/docs/routing/routing-concepts", - "ray": "a4b1af71bf586a08", - "status": 200, - "headersReadyMs": 292, - "databaseUsed": false, - "phases": [ - { - "name": "db_config", - "startMs": 0, - "durationMs": 0 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 283 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 283 - }, - { - "name": "content_edge_read", - "startMs": 283, - "durationMs": 9 - }, - { - "name": "start_handler", - "startMs": 0, - "durationMs": 292 - } - ] - }, - "version": "54beb47a-1efb-4147-bb66-5c2ae0a3a79a" - }, - { - "worker": "full", - "run": "initial", - "path": "/docs", - "status": 200, - "ttfb_ms": 1738.1, - "total_ms": 1856.5, - "tls_ms": 89.0, - "after_connection_ms": 1649.0, - "ray": "a4b1af827f0728b4-DFW", - "instance": "660484cd-6418-4fd1-881d-420d0abc4c3e", - "instance_request": "1", - "phase_ms": "0", - "server_timing": "app_headers;dur=197.0, db_config;dur=0.0, content_edge_read;dur=389.0, start_handler;dur=197.0, db_used;desc=\"false\", docs_request;desc=\"1\"", - "cpu_ms": 346, - "wall_ms": 559, - "docs_timing": { - "logType": "docs_timing", - "workerInstance": "2ee5eedc-3d83-42ce-a10c-1b8cf6583125", - "docsRequest": 1, - "phase": "headers_ready", - "pathname": "/router/latest/docs/routing/routing-concepts", - "ray": "a4b1af827f0728b4", - "status": 200, - "headersReadyMs": 197, - "databaseUsed": false, - "phases": [ - { - "name": "db_config", - "startMs": 0, - "durationMs": 0 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 191 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 192 - }, - { - "name": "content_edge_read", - "startMs": 191, - "durationMs": 6 - }, - { - "name": "start_handler", - "startMs": 0, - "durationMs": 197 - } - ] - }, - "version": "54beb47a-1efb-4147-bb66-5c2ae0a3a79a" - }, - { - "worker": "full", - "run": "initial", - "path": "/docs", - "status": 200, - "ttfb_ms": 2676.7, - "total_ms": 2811.5, - "tls_ms": 209.3, - "after_connection_ms": 2467.3, - "ray": "a4b1af9218656c82-DFW", - "instance": "a3751a35-b68c-41e9-881d-20fb84d6c1ea", - "instance_request": "1", - "phase_ms": "0", - "server_timing": "app_headers;dur=354.0, db_config;dur=0.0, content_edge_read;dur=694.0, start_handler;dur=354.0, db_used;desc=\"false\", docs_request;desc=\"1\"", - "cpu_ms": 317, - "wall_ms": 677, - "docs_timing": { - "logType": "docs_timing", - "workerInstance": "38ac2249-4edc-40ec-897e-e1d615e8d228", - "docsRequest": 1, - "phase": "headers_ready", - "pathname": "/router/latest/docs/routing/routing-concepts", - "ray": "a4b1af9218656c82", - "status": 200, - "headersReadyMs": 354, - "databaseUsed": false, - "phases": [ - { - "name": "db_config", - "startMs": 0, - "durationMs": 0 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 339 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 340 - }, - { - "name": "content_edge_read", - "startMs": 339, - "durationMs": 15 - }, - { - "name": "start_handler", - "startMs": 0, - "durationMs": 354 - } - ] - }, - "version": "54beb47a-1efb-4147-bb66-5c2ae0a3a79a" - }, - { - "worker": "full", - "run": "initial", - "path": "/docs", - "status": 200, - "ttfb_ms": 511.7, - "total_ms": 630.0, - "tls_ms": 78.9, - "after_connection_ms": 432.8, - "ray": "a4b1afa61e99f06e-DFW", - "instance": "b51e6b64-daba-4e54-82d3-a3682eb06278", - "instance_request": "2", - "phase_ms": "0", - "server_timing": "app_headers;dur=165.0, db_config;dur=0.0, content_edge_read;dur=323.0, start_handler;dur=165.0, db_used;desc=\"false\", docs_request;desc=\"1\"", - "cpu_ms": 184, - "wall_ms": 349, - "docs_timing": { - "logType": "docs_timing", - "workerInstance": "fd0a77b9-37dd-43b5-98bc-9d275bf007a1", - "docsRequest": 1, - "phase": "headers_ready", - "pathname": "/router/latest/docs/routing/routing-concepts", - "ray": "a4b1afa61e99f06e", - "status": 200, - "headersReadyMs": 165, - "databaseUsed": false, - "phases": [ - { - "name": "db_config", - "startMs": 0, - "durationMs": 0 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 157 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 158 - }, - { - "name": "content_edge_read", - "startMs": 157, - "durationMs": 8 - }, - { - "name": "start_handler", - "startMs": 0, - "durationMs": 165 - } - ] - }, - "version": "54beb47a-1efb-4147-bb66-5c2ae0a3a79a" - }, - { - "worker": "full", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 202.7, - "total_ms": 205.1, - "tls_ms": 84.2, - "after_connection_ms": 118.5, - "ray": "a4b1afad5b7a6bcc-DFW", - "instance": "a3751a35-b68c-41e9-881d-20fb84d6c1ea", - "instance_request": "2", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 1, - "version": "54beb47a-1efb-4147-bb66-5c2ae0a3a79a" - }, - { - "worker": "full", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 167.1, - "total_ms": 167.3, - "tls_ms": 86.2, - "after_connection_ms": 80.9, - "ray": "a4b1afb1d82a66dd-DFW", - "instance": "913c24a0-5e5f-4c6e-9e23-8d2d110d3db2", - "instance_request": "2", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "54beb47a-1efb-4147-bb66-5c2ae0a3a79a" - } - ] - } - }, - { - "worker": "data", - "deployed_name": "tanstack-cold-probe-data", - "version": "7abef817-42f3-4947-b156-bf4a38e62cb0", - "upload_kib": 22615.06, - "gzip_kib": 6934.42, - "reported_startup_ms": 1, - "runs": { - "initial": [ - { - "worker": "data", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 389.0, - "total_ms": 389.5, - "tls_ms": 167.6, - "after_connection_ms": 221.3, - "ray": "a4b1b0262ff1ddb0-DFW", - "instance": "25c8cafb-8a2b-4916-8b2a-1cdcaf889f5b", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null - }, - { - "worker": "data", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 592.9, - "total_ms": 593.2, - "tls_ms": 214.2, - "after_connection_ms": 378.6, - "ray": "a4b1b02c89b34630-DFW", - "instance": "f9784f66-0d48-4a56-9f51-6fccfa573c39", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null - }, - { - "worker": "data", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 471.9, - "total_ms": 472.1, - "tls_ms": 221.9, - "after_connection_ms": 249.9, - "ray": "a4b1b03389c7a9f5-DFW", - "instance": "c6f8e8f5-2925-4480-babd-3707039093d0", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null - }, - { - "worker": "data", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 549.3, - "total_ms": 549.5, - "tls_ms": 229.5, - "after_connection_ms": 319.7, - "ray": "a4b1b039cb9ab476-DFW", - "instance": "c77d984f-cfee-4063-ae91-f820a0953f30", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 1, - "wall_ms": 3, - "version": "7abef817-42f3-4947-b156-bf4a38e62cb0" - }, - { - "worker": "data", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 551.6, - "total_ms": 554.3, - "tls_ms": 236.9, - "after_connection_ms": 314.7, - "ray": "a4b1b0408aeae718-DFW", - "instance": "cd8ff136-62a5-4ae4-9302-912ed0f8907a", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 1, - "version": "7abef817-42f3-4947-b156-bf4a38e62cb0" - }, - { - "worker": "data", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 216.4, - "total_ms": 218.7, - "tls_ms": 167.1, - "after_connection_ms": 49.2, - "ray": "a4b1b0464a1e5494-DFW", - "instance": "c77d984f-cfee-4063-ae91-f820a0953f30", - "instance_request": "2", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "7abef817-42f3-4947-b156-bf4a38e62cb0" - }, - { - "worker": "data", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 264.2, - "total_ms": 264.4, - "tls_ms": 79.0, - "after_connection_ms": 185.1, - "ray": "a4b1b04a5eabf887-DFW", - "instance": "41af4d94-e749-45bc-b7d0-c44330035ea3", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 1, - "wall_ms": 2, - "version": "7abef817-42f3-4947-b156-bf4a38e62cb0" - }, - { - "worker": "data", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 144.4, - "total_ms": 146.8, - "tls_ms": 79.7, - "after_connection_ms": 64.7, - "ray": "a4b1b04f3e76ebf6-DFW", - "instance": "cd8ff136-62a5-4ae4-9302-912ed0f8907a", - "instance_request": "2", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "7abef817-42f3-4947-b156-bf4a38e62cb0" - }, - { - "worker": "data", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 211.8, - "total_ms": 214.1, - "tls_ms": 105.9, - "after_connection_ms": 105.8, - "ray": "a4b1b0538ada46cc-DFW", - "instance": "f9784f66-0d48-4a56-9f51-6fccfa573c39", - "instance_request": "2", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 1, - "version": "7abef817-42f3-4947-b156-bf4a38e62cb0" - }, - { - "worker": "data", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 347.9, - "total_ms": 350.2, - "tls_ms": 80.4, - "after_connection_ms": 267.5, - "ray": "a4b1b057eead670d-DFW", - "instance": "b4f06967-0af7-41e6-9492-9c32307923fc", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null - }, - { - "worker": "data", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 174.1, - "total_ms": 176.8, - "tls_ms": 78.6, - "after_connection_ms": 95.5, - "ray": "a4b1b05d4f61cb67-DFW", - "instance": "c77d984f-cfee-4063-ae91-f820a0953f30", - "instance_request": "3", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "7abef817-42f3-4947-b156-bf4a38e62cb0" - }, - { - "worker": "data", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 557.4, - "total_ms": 557.7, - "tls_ms": 82.8, - "after_connection_ms": 474.5, - "ray": "a4b1b061bbfc4854-DFW", - "instance": "986b3d5c-403c-42e5-aeff-bae8fb878a7f", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null - }, - { - "worker": "data", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 228.7, - "total_ms": 229.0, - "tls_ms": 78.5, - "after_connection_ms": 150.2, - "ray": "a4b1b0685aa9460b-DFW", - "instance": "f9784f66-0d48-4a56-9f51-6fccfa573c39", - "instance_request": "3", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 1, - "version": "7abef817-42f3-4947-b156-bf4a38e62cb0" - }, - { - "worker": "data", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 507.2, - "total_ms": 507.6, - "tls_ms": 86.9, - "after_connection_ms": 420.3, - "ray": "a4b1b06d1a381002-DFW", - "instance": "d6aab238-7341-446c-918e-759314e69cd8", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "7abef817-42f3-4947-b156-bf4a38e62cb0" - }, - { - "worker": "data", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 145.6, - "total_ms": 148.0, - "tls_ms": 79.8, - "after_connection_ms": 65.7, - "ray": "a4b1b07368d76a82-DFW", - "instance": "b3fa874b-5d78-417d-988b-1302ed8e1fa2", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "7abef817-42f3-4947-b156-bf4a38e62cb0" - }, - { - "worker": "data", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 135.0, - "total_ms": 135.2, - "tls_ms": 79.9, - "after_connection_ms": 55.0, - "ray": "a4b1b077891069d3-DFW", - "instance": "b3fa874b-5d78-417d-988b-1302ed8e1fa2", - "instance_request": "2", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "7abef817-42f3-4947-b156-bf4a38e62cb0" - }, - { - "worker": "data", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 553.6, - "total_ms": 556.0, - "tls_ms": 83.2, - "after_connection_ms": 470.3, - "ray": "a4b1b07ba8386c33-DFW", - "instance": "8a5a0daa-0720-435f-9937-f6bbcee5374a", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null - }, - { - "worker": "data", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 407.8, - "total_ms": 410.1, - "tls_ms": 90.2, - "after_connection_ms": 317.5, - "ray": "a4b1b0826a99b16f-DFW", - "instance": "0c1dbb8a-bd41-4d36-b000-7e39cf10a1c3", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 1, - "wall_ms": 2, - "version": "7abef817-42f3-4947-b156-bf4a38e62cb0" - }, - { - "worker": "data", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 169.3, - "total_ms": 171.5, - "tls_ms": 83.6, - "after_connection_ms": 85.7, - "ray": "a4b1b0881efe295c-DFW", - "instance": "c77d984f-cfee-4063-ae91-f820a0953f30", - "instance_request": "4", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 1, - "version": "7abef817-42f3-4947-b156-bf4a38e62cb0" - }, - { - "worker": "data", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 220.4, - "total_ms": 222.9, - "tls_ms": 139.4, - "after_connection_ms": 81.0, - "ray": "a4b1b08cbe5b1021-DFW", - "instance": "26fc7ac0-d10b-4908-b56b-efb180b93375", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "7abef817-42f3-4947-b156-bf4a38e62cb0" - } - ] - } - }, - { - "worker": "no-wasm", - "deployed_name": "tanstack-cold-probe-no-wasm", - "version": "064f1ab1-74a8-4525-83de-495090637549", - "upload_kib": 22617.0, - "gzip_kib": 6933.89, - "reported_startup_ms": 2, - "runs": { - "initial": [ - { - "worker": "no-wasm", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 2033.7, - "total_ms": 2036.1, - "tls_ms": 212.2, - "after_connection_ms": 1821.5, - "ray": "a4b1b0b96eee6ba9-DFW", - "instance": "3856de84-fb4c-4d0a-af7d-495ccf831619", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null - }, - { - "worker": "no-wasm", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 847.8, - "total_ms": 850.4, - "tls_ms": 81.0, - "after_connection_ms": 766.7, - "ray": "a4b1b0c878fed8db-DFW", - "instance": "f27aa11c-dc50-4bcc-8ca0-97da53e9f2ee", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null - }, - { - "worker": "no-wasm", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 1011.6, - "total_ms": 1011.9, - "tls_ms": 82.4, - "after_connection_ms": 929.2, - "ray": "a4b1b0d1089e7d9f-DFW", - "instance": "3b1cc40c-137b-4a81-a435-c23df0cade24", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null - }, - { - "worker": "no-wasm", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 1547.3, - "total_ms": 1547.6, - "tls_ms": 149.6, - "after_connection_ms": 1397.6, - "ray": "a4b1b0dbcc218835-DFW", - "instance": "24589a27-ef31-4f17-9c5e-59b3b0b1cd31", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 1, - "version": "064f1ab1-74a8-4525-83de-495090637549" - }, - { - "worker": "no-wasm", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 1037.7, - "total_ms": 1040.2, - "tls_ms": 176.3, - "after_connection_ms": 861.4, - "ray": "a4b1b0e809a3f68c-DFW", - "instance": "f467a255-3342-4266-a562-0676ed133bd6", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "064f1ab1-74a8-4525-83de-495090637549" - }, - { - "worker": "no-wasm", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 955.8, - "total_ms": 958.1, - "tls_ms": 82.2, - "after_connection_ms": 873.5, - "ray": "a4b1b0f12b69e68b-DFW", - "instance": "f934780e-e25a-49ca-8235-3e749a7aa713", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "064f1ab1-74a8-4525-83de-495090637549" - }, - { - "worker": "no-wasm", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 133.9, - "total_ms": 136.2, - "tls_ms": 82.3, - "after_connection_ms": 51.5, - "ray": "a4b1b0fa59ab377b-DFW", - "instance": "24589a27-ef31-4f17-9c5e-59b3b0b1cd31", - "instance_request": "2", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "064f1ab1-74a8-4525-83de-495090637549" - }, - { - "worker": "no-wasm", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 845.6, - "total_ms": 846.1, - "tls_ms": 79.0, - "after_connection_ms": 766.6, - "ray": "a4b1b0fe6f4c6f16-DFW", - "instance": "c068998c-0ffd-4bed-b428-9265b9c08944", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 1, - "version": "064f1ab1-74a8-4525-83de-495090637549" - }, - { - "worker": "no-wasm", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 1698.1, - "total_ms": 1698.5, - "tls_ms": 81.7, - "after_connection_ms": 1616.4, - "ray": "a4b1b106efbb3160-DFW", - "instance": "3a14a23a-79a7-4045-8b1c-b5e78f43dbcc", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 1, - "wall_ms": 3, - "version": "064f1ab1-74a8-4525-83de-495090637549" - }, - { - "worker": "no-wasm", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 159.4, - "total_ms": 161.7, - "tls_ms": 81.2, - "after_connection_ms": 78.2, - "ray": "a4b1b114bb9aaad5-DFW", - "instance": "24589a27-ef31-4f17-9c5e-59b3b0b1cd31", - "instance_request": "3", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "064f1ab1-74a8-4525-83de-495090637549" - }, - { - "worker": "no-wasm", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 147.2, - "total_ms": 149.6, - "tls_ms": 79.6, - "after_connection_ms": 67.5, - "ray": "a4b1b118fb7edc67-DFW", - "instance": "3a14a23a-79a7-4045-8b1c-b5e78f43dbcc", - "instance_request": "2", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 2, - "version": "064f1ab1-74a8-4525-83de-495090637549" - }, - { - "worker": "no-wasm", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 208.0, - "total_ms": 208.4, - "tls_ms": 116.6, - "after_connection_ms": 91.4, - "ray": "a4b1b11d8e85b94c-DFW", - "instance": "24589a27-ef31-4f17-9c5e-59b3b0b1cd31", - "instance_request": "4", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "064f1ab1-74a8-4525-83de-495090637549" - }, - { - "worker": "no-wasm", - "run": "initial", - "path": "/noop", - "status": 404, - "ttfb_ms": 131.6, - "total_ms": 131.9, - "tls_ms": 80.8, - "after_connection_ms": 50.7, - "ray": "a4b1b121cc58f0b6-DFW", - "instance": null, - "instance_request": null, - "phase_ms": null, - "server_timing": null - }, - { - "worker": "no-wasm", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 167.9, - "total_ms": 170.2, - "tls_ms": 80.2, - "after_connection_ms": 87.6, - "ray": "a4b1b125cc5b2d41-DFW", - "instance": "3a14a23a-79a7-4045-8b1c-b5e78f43dbcc", - "instance_request": "3", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 1, - "version": "064f1ab1-74a8-4525-83de-495090637549" - }, - { - "worker": "no-wasm", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 149.5, - "total_ms": 149.7, - "tls_ms": 82.6, - "after_connection_ms": 66.9, - "ray": "a4b1b12a1e492628-DFW", - "instance": "f467a255-3342-4266-a562-0676ed133bd6", - "instance_request": "2", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "064f1ab1-74a8-4525-83de-495090637549" - }, - { - "worker": "no-wasm", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 144.0, - "total_ms": 146.2, - "tls_ms": 77.1, - "after_connection_ms": 66.9, - "ray": "a4b1b12e3d1c3479-DFW", - "instance": "3a14a23a-79a7-4045-8b1c-b5e78f43dbcc", - "instance_request": "4", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 2, - "version": "064f1ab1-74a8-4525-83de-495090637549" - }, - { - "worker": "no-wasm", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 170.9, - "total_ms": 171.2, - "tls_ms": 81.8, - "after_connection_ms": 89.0, - "ray": "a4b1b1326aedb476-DFW", - "instance": "24589a27-ef31-4f17-9c5e-59b3b0b1cd31", - "instance_request": "5", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "064f1ab1-74a8-4525-83de-495090637549" - }, - { - "worker": "no-wasm", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 130.5, - "total_ms": 132.7, - "tls_ms": 78.7, - "after_connection_ms": 51.8, - "ray": "a4b1b136ae245494-DFW", - "instance": "24589a27-ef31-4f17-9c5e-59b3b0b1cd31", - "instance_request": "6", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "064f1ab1-74a8-4525-83de-495090637549" - }, - { - "worker": "no-wasm", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 914.1, - "total_ms": 917.0, - "tls_ms": 78.1, - "after_connection_ms": 836.0, - "ray": "a4b1b13ab8615298-DFW", - "instance": "a20827d8-83e2-47ed-936c-792b663bd1e2", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null - }, - { - "worker": "no-wasm", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 139.4, - "total_ms": 140.0, - "tls_ms": 81.9, - "after_connection_ms": 57.4, - "ray": "a4b1b143b879a8b3-DFW", - "instance": "f467a255-3342-4266-a562-0676ed133bd6", - "instance_request": "3", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "064f1ab1-74a8-4525-83de-495090637549" - }, - { - "worker": "no-wasm", - "run": "initial", - "path": "/noop", - "status": 500, - "ttfb_ms": 282.8, - "total_ms": 286.3, - "tls_ms": 81.8, - "after_connection_ms": 200.9, - "ray": "a4b1b147d9f6f063-DFW", - "instance": null, - "instance_request": null, - "phase_ms": null, - "server_timing": null - }, - { - "worker": "no-wasm", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 174.2, - "total_ms": 174.8, - "tls_ms": 86.3, - "after_connection_ms": 87.8, - "ray": "a4b1b14ce8814d98-DFW", - "instance": "f934780e-e25a-49ca-8235-3e749a7aa713", - "instance_request": "2", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "064f1ab1-74a8-4525-83de-495090637549" - }, - { - "worker": "no-wasm", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 137.3, - "total_ms": 141.9, - "tls_ms": 84.1, - "after_connection_ms": 53.1, - "ray": "a4b1b151582938f4-DFW", - "instance": "f467a255-3342-4266-a562-0676ed133bd6", - "instance_request": "4", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "064f1ab1-74a8-4525-83de-495090637549" - }, - { - "worker": "no-wasm", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 157.6, - "total_ms": 158.0, - "tls_ms": 83.7, - "after_connection_ms": 73.9, - "ray": "a4b1b1557aabb52a-DFW", - "instance": "f467a255-3342-4266-a562-0676ed133bd6", - "instance_request": "5", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "064f1ab1-74a8-4525-83de-495090637549" - } - ], - "settled": [ - { - "worker": "no-wasm", - "run": "settled", - "path": "/noop", - "status": 200, - "ttfb_ms": 701.6, - "total_ms": 704.1, - "tls_ms": 128.6, - "after_connection_ms": 572.9, - "ray": "a4b1bd392f231234-DFW", - "instance": "0f87a187-a175-4ebc-a9cc-b1e5514bc1c9", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "064f1ab1-74a8-4525-83de-495090637549" - }, - { - "worker": "no-wasm", - "run": "settled", - "path": "/noop", - "status": 200, - "ttfb_ms": 1410.4, - "total_ms": 1412.8, - "tls_ms": 84.7, - "after_connection_ms": 1325.6, - "ray": "a4b1bd409fe92caa-DFW", - "instance": "ca212110-d2b0-4ecd-bada-ce7f5e2c070b", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 1, - "version": "064f1ab1-74a8-4525-83de-495090637549" - }, - { - "worker": "no-wasm", - "run": "settled", - "path": "/noop", - "status": 200, - "ttfb_ms": 154.1, - "total_ms": 156.5, - "tls_ms": 95.5, - "after_connection_ms": 58.5, - "ray": "a4b1bd4cc98e7c9d-DFW", - "instance": "0f87a187-a175-4ebc-a9cc-b1e5514bc1c9", - "instance_request": "2", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "064f1ab1-74a8-4525-83de-495090637549" - }, - { - "worker": "no-wasm", - "run": "settled", - "path": "/noop", - "status": 200, - "ttfb_ms": 159.4, - "total_ms": 161.7, - "tls_ms": 80.8, - "after_connection_ms": 78.5, - "ray": "a4b1bd50daba6e6f-DFW", - "instance": "0f87a187-a175-4ebc-a9cc-b1e5514bc1c9", - "instance_request": "3", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "064f1ab1-74a8-4525-83de-495090637549" - }, - { - "worker": "no-wasm", - "run": "settled", - "path": "/noop", - "status": 200, - "ttfb_ms": 2254.2, - "total_ms": 2256.7, - "tls_ms": 83.9, - "after_connection_ms": 2170.3, - "ray": "a4b1bd551d7afc87-DFW", - "instance": "51162afe-54b1-4b6d-ba78-ea84c5ca481d", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 1, - "version": "064f1ab1-74a8-4525-83de-495090637549" - }, - { - "worker": "no-wasm", - "run": "settled", - "path": "/noop", - "status": 200, - "ttfb_ms": 1002.6, - "total_ms": 1005.2, - "tls_ms": 82.8, - "after_connection_ms": 919.7, - "ray": "a4b1bd667f1ff030-DFW", - "instance": "7cb70131-3a0b-42c1-86e2-036511875327", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 1, - "version": "064f1ab1-74a8-4525-83de-495090637549" - }, - { - "worker": "no-wasm", - "run": "settled", - "path": "/noop", - "status": 200, - "ttfb_ms": 143.1, - "total_ms": 145.5, - "tls_ms": 80.1, - "after_connection_ms": 62.9, - "ray": "a4b1bd6fff41b901-DFW", - "instance": "51162afe-54b1-4b6d-ba78-ea84c5ca481d", - "instance_request": "2", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "064f1ab1-74a8-4525-83de-495090637549" - }, - { - "worker": "no-wasm", - "run": "settled", - "path": "/noop", - "status": 200, - "ttfb_ms": 871.3, - "total_ms": 873.7, - "tls_ms": 78.5, - "after_connection_ms": 792.7, - "ray": "a4b1bd742d4398b0-DFW", - "instance": "7126bf4c-947d-40c9-a9e9-4a6948987d5d", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 1, - "version": "064f1ab1-74a8-4525-83de-495090637549" - }, - { - "worker": "no-wasm", - "run": "settled", - "path": "/noop", - "status": 200, - "ttfb_ms": 948.2, - "total_ms": 948.6, - "tls_ms": 83.5, - "after_connection_ms": 864.6, - "ray": "a4b1bd7ceb3fc641-DFW", - "instance": "cc1cf90e-7d54-4e8b-a3f3-0f036f5a6666", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "064f1ab1-74a8-4525-83de-495090637549" - }, - { - "worker": "no-wasm", - "run": "settled", - "path": "/noop", - "status": 200, - "ttfb_ms": 2019.6, - "total_ms": 2022.8, - "tls_ms": 85.4, - "after_connection_ms": 1934.1, - "ray": "a4b1bd861a0a6bfb-DFW", - "instance": "81f33339-fede-4c8d-8d43-92c7f2e1d601", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 1, - "version": "064f1ab1-74a8-4525-83de-495090637549" - }, - { - "worker": "no-wasm", - "run": "settled", - "path": "/noop", - "status": 200, - "ttfb_ms": 138.7, - "total_ms": 141.0, - "tls_ms": 78.2, - "after_connection_ms": 60.4, - "ray": "a4b1bd95fb26d990-DFW", - "instance": "7126bf4c-947d-40c9-a9e9-4a6948987d5d", - "instance_request": "2", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "064f1ab1-74a8-4525-83de-495090637549" - }, - { - "worker": "no-wasm", - "run": "settled", - "path": "/noop", - "status": 200, - "ttfb_ms": 162.1, - "total_ms": 164.5, - "tls_ms": 78.2, - "after_connection_ms": 83.9, - "ray": "a4b1bd9a0baaf78b-DFW", - "instance": "51162afe-54b1-4b6d-ba78-ea84c5ca481d", - "instance_request": "3", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 1, - "version": "064f1ab1-74a8-4525-83de-495090637549" - }, - { - "worker": "no-wasm", - "run": "settled", - "path": "/noop", - "status": 200, - "ttfb_ms": 227.9, - "total_ms": 230.2, - "tls_ms": 109.1, - "after_connection_ms": 118.7, - "ray": "a4b1bd9e9c1d1427-DFW", - "instance": "51162afe-54b1-4b6d-ba78-ea84c5ca481d", - "instance_request": "4", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 1, - "version": "064f1ab1-74a8-4525-83de-495090637549" - }, - { - "worker": "no-wasm", - "run": "settled", - "path": "/noop", - "status": 200, - "ttfb_ms": 155.5, - "total_ms": 157.9, - "tls_ms": 80.2, - "after_connection_ms": 75.3, - "ray": "a4b1bda2fe10857d-DFW", - "instance": "cc1cf90e-7d54-4e8b-a3f3-0f036f5a6666", - "instance_request": "2", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "064f1ab1-74a8-4525-83de-495090637549" - }, - { - "worker": "no-wasm", - "run": "settled", - "path": "/noop", - "status": 200, - "ttfb_ms": 182.9, - "total_ms": 185.3, - "tls_ms": 78.1, - "after_connection_ms": 104.8, - "ray": "a4b1bda72e557d9f-DFW", - "instance": "0f87a187-a175-4ebc-a9cc-b1e5514bc1c9", - "instance_request": "4", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "064f1ab1-74a8-4525-83de-495090637549" - }, - { - "worker": "no-wasm", - "run": "settled", - "path": "/noop", - "status": 200, - "ttfb_ms": 154.5, - "total_ms": 156.8, - "tls_ms": 85.0, - "after_connection_ms": 69.5, - "ray": "a4b1bdab9d9ef787-DFW", - "instance": "51162afe-54b1-4b6d-ba78-ea84c5ca481d", - "instance_request": "5", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 1, - "version": "064f1ab1-74a8-4525-83de-495090637549" - } - ] - } - }, - { - "worker": "single-js", - "deployed_name": "tanstack-cold-probe-single-js", - "version": "b25cb085-0e77-4053-be83-70ce147db3cc", - "upload_kib": 23239.25, - "gzip_kib": 6970.87, - "reported_startup_ms": 3, - "runs": { - "initial": [ - { - "worker": "single-js", - "run": "initial", - "path": "/noop", - "status": 404, - "ttfb_ms": 1272.6, - "total_ms": 1273.0, - "tls_ms": 762.3, - "after_connection_ms": 510.3, - "ray": "a4b1b34c5d60c4f5-DFW", - "instance": null, - "instance_request": null, - "phase_ms": null, - "server_timing": null - }, - { - "worker": "single-js", - "run": "initial", - "path": "/noop", - "status": 404, - "ttfb_ms": 1253.3, - "total_ms": 1253.6, - "tls_ms": 816.5, - "after_connection_ms": 436.8, - "ray": "a4b1b3572e483ac1-DFW", - "instance": null, - "instance_request": null, - "phase_ms": null, - "server_timing": null - }, - { - "worker": "single-js", - "run": "initial", - "path": "/noop", - "status": 404, - "ttfb_ms": 199.2, - "total_ms": 199.5, - "tls_ms": 121.6, - "after_connection_ms": 77.5, - "ray": "a4b1b35bcb226b3d-DFW", - "instance": null, - "instance_request": null, - "phase_ms": null, - "server_timing": null - }, - { - "worker": "single-js", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 579.9, - "total_ms": 580.1, - "tls_ms": 86.1, - "after_connection_ms": 493.7, - "ray": "a4b1b36008310ce7-DFW", - "instance": "9ed67df5-9b75-482c-b39e-ab549a8ccfa0", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null - }, - { - "worker": "single-js", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 558.9, - "total_ms": 559.2, - "tls_ms": 97.0, - "after_connection_ms": 461.8, - "ray": "a4b1b366eee2eff2-DFW", - "instance": "4938d0fe-9b3f-42b6-a516-11b2e5c91d6b", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "b25cb085-0e77-4053-be83-70ce147db3cc" - }, - { - "worker": "single-js", - "run": "initial", - "path": "/noop", - "status": 404, - "ttfb_ms": 128.7, - "total_ms": 128.9, - "tls_ms": 81.3, - "after_connection_ms": 47.3, - "ray": "a4b1b36d8867feb2-DFW", - "instance": null, - "instance_request": null, - "phase_ms": null, - "server_timing": null - }, - { - "worker": "single-js", - "run": "initial", - "path": "/noop", - "status": 404, - "ttfb_ms": 170.6, - "total_ms": 170.8, - "tls_ms": 102.0, - "after_connection_ms": 68.5, - "ray": "a4b1b371ae34aad5-DFW", - "instance": null, - "instance_request": null, - "phase_ms": null, - "server_timing": null - }, - { - "worker": "single-js", - "run": "initial", - "path": "/noop", - "status": 404, - "ttfb_ms": 127.4, - "total_ms": 129.7, - "tls_ms": 88.0, - "after_connection_ms": 39.4, - "ray": "a4b1b375df454403-DFW", - "instance": null, - "instance_request": null, - "phase_ms": null, - "server_timing": null - }, - { - "worker": "single-js", - "run": "initial", - "path": "/noop", - "status": 500, - "ttfb_ms": 314.2, - "total_ms": 316.2, - "tls_ms": 90.4, - "after_connection_ms": 223.7, - "ray": "a4b1b379fbab6bcc-DFW", - "instance": null, - "instance_request": null, - "phase_ms": null, - "server_timing": null - }, - { - "worker": "single-js", - "run": "initial", - "path": "/noop", - "status": 404, - "ttfb_ms": 144.0, - "total_ms": 146.8, - "tls_ms": 83.1, - "after_connection_ms": 60.8, - "ray": "a4b1b37f2c92ebf6-DFW", - "instance": null, - "instance_request": null, - "phase_ms": null, - "server_timing": null - }, - { - "worker": "single-js", - "run": "initial", - "path": "/noop", - "status": 404, - "ttfb_ms": 131.8, - "total_ms": 134.2, - "tls_ms": 78.0, - "after_connection_ms": 53.7, - "ray": "a4b1b38349ae52e4-DFW", - "instance": null, - "instance_request": null, - "phase_ms": null, - "server_timing": null - }, - { - "worker": "single-js", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 573.1, - "total_ms": 575.4, - "tls_ms": 96.1, - "after_connection_ms": 476.8, - "ray": "a4b1b3877f5f0864-DFW", - "instance": "276cc60f-d808-4657-9063-6a75fae27857", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "b25cb085-0e77-4053-be83-70ce147db3cc" - }, - { - "worker": "single-js", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 501.5, - "total_ms": 503.8, - "tls_ms": 78.8, - "after_connection_ms": 422.6, - "ray": "a4b1b38e29b56dd6-DFW", - "instance": "f1d62490-ce29-460d-9e55-d0475b66ff90", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 1, - "version": "b25cb085-0e77-4053-be83-70ce147db3cc" - }, - { - "worker": "single-js", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 608.5, - "total_ms": 608.9, - "tls_ms": 80.3, - "after_connection_ms": 528.1, - "ray": "a4b1b3949ba0c6dd-DFW", - "instance": "48d8bcd1-630d-490f-8ce3-cf1989ad48c0", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null - }, - { - "worker": "single-js", - "run": "initial", - "path": "/noop", - "status": 500, - "ttfb_ms": 288.0, - "total_ms": 290.4, - "tls_ms": 87.1, - "after_connection_ms": 200.8, - "ray": "a4b1b39ba80d3875-DFW", - "instance": null, - "instance_request": null, - "phase_ms": null, - "server_timing": null - }, - { - "worker": "single-js", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 744.1, - "total_ms": 746.5, - "tls_ms": 84.0, - "after_connection_ms": 660.1, - "ray": "a4b1b3a0b85e37ee-DFW", - "instance": "5d1415d7-7440-4b13-a644-5d924dbc03de", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null - }, - { - "worker": "single-js", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 572.3, - "total_ms": 574.6, - "tls_ms": 77.7, - "after_connection_ms": 494.5, - "ray": "a4b1b3a89e045e24-DFW", - "instance": "459bfc0d-bbe6-442d-bfad-571043f29a48", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null - }, - { - "worker": "single-js", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 1351.7, - "total_ms": 1354.0, - "tls_ms": 90.0, - "after_connection_ms": 1261.6, - "ray": "a4b1b3af88216be6-DFW", - "instance": "683f1c76-3f17-4c45-9709-ca46377bf41d", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null - }, - { - "worker": "single-js", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 132.4, - "total_ms": 134.8, - "tls_ms": 86.0, - "after_connection_ms": 46.2, - "ray": "a4b1b3bb38098c58-DFW", - "instance": "046914df-9532-4923-a254-a17fe35a1b97", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "b25cb085-0e77-4053-be83-70ce147db3cc" - }, - { - "worker": "single-js", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 601.1, - "total_ms": 603.5, - "tls_ms": 79.9, - "after_connection_ms": 521.1, - "ray": "a4b1b3bf3c7c69d8-DFW", - "instance": "5794abb7-f144-4de9-b171-92e6f7bd2734", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "b25cb085-0e77-4053-be83-70ce147db3cc" - }, - { - "worker": "single-js", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 634.0, - "total_ms": 636.4, - "tls_ms": 84.3, - "after_connection_ms": 549.6, - "ray": "a4b1b3c659afb66c-DFW", - "instance": "402c81cd-95ae-4192-8705-2d497c44c873", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null - }, - { - "worker": "single-js", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 630.0, - "total_ms": 630.7, - "tls_ms": 88.3, - "after_connection_ms": 541.7, - "ray": "a4b1b3cd9edff0a0-DFW", - "instance": "c77a9901-96ed-49fc-ab46-d4eeaa6093b5", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null - }, - { - "worker": "single-js", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 147.8, - "total_ms": 150.1, - "tls_ms": 79.7, - "after_connection_ms": 68.0, - "ray": "a4b1b3d4b937f082-DFW", - "instance": "c77a9901-96ed-49fc-ab46-d4eeaa6093b5", - "instance_request": "2", - "phase_ms": "0", - "server_timing": null - }, - { - "worker": "single-js", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 654.7, - "total_ms": 655.4, - "tls_ms": 83.8, - "after_connection_ms": 570.9, - "ray": "a4b1b3d8e8ea3da4-DFW", - "instance": "8403290a-8426-4c3d-a5d5-19db1f5e8ced", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null - } - ], - "settled": [ - { - "worker": "single-js", - "run": "settled", - "path": "/noop", - "status": 200, - "ttfb_ms": 582.5, - "total_ms": 585.0, - "tls_ms": 128.9, - "after_connection_ms": 453.5, - "ray": "a4b1bd27de0f6528-DFW", - "instance": "2be62297-0369-4634-98de-999bd64ad5f6", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "b25cb085-0e77-4053-be83-70ce147db3cc" - }, - { - "worker": "single-js", - "run": "settled", - "path": "/noop", - "status": 200, - "ttfb_ms": 690.6, - "total_ms": 692.9, - "tls_ms": 82.3, - "after_connection_ms": 608.2, - "ray": "a4b1bd2e6ee7f052-DFW", - "instance": "c57ce07c-b465-4964-9c53-39a7e972bf20", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 1, - "wall_ms": 2, - "version": "b25cb085-0e77-4053-be83-70ce147db3cc" - }, - { - "worker": "single-js", - "run": "settled", - "path": "/noop", - "status": 200, - "ttfb_ms": 2049.3, - "total_ms": 2049.8, - "tls_ms": 84.7, - "after_connection_ms": 1964.6, - "ray": "a4b1bd360e9f469c-DFW", - "instance": "a7b69aeb-b219-41bc-a1b5-735bc4dfefac", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 1, - "wall_ms": 1, - "version": "b25cb085-0e77-4053-be83-70ce147db3cc" - }, - { - "worker": "single-js", - "run": "settled", - "path": "/noop", - "status": 200, - "ttfb_ms": 604.8, - "total_ms": 607.1, - "tls_ms": 86.8, - "after_connection_ms": 517.9, - "ray": "a4b1bd4628b1fa6c-DFW", - "instance": "806f8b9c-01d2-4e09-9696-12cb1ba9a48d", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "b25cb085-0e77-4053-be83-70ce147db3cc" - }, - { - "worker": "single-js", - "run": "settled", - "path": "/noop", - "status": 200, - "ttfb_ms": 697.6, - "total_ms": 700.1, - "tls_ms": 93.4, - "after_connection_ms": 604.1, - "ray": "a4b1bd4d3a2ce55e-DFW", - "instance": "0e62ed3b-0cc6-4ceb-b0e1-821e9b21da0f", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 1, - "version": "b25cb085-0e77-4053-be83-70ce147db3cc" - }, - { - "worker": "single-js", - "run": "settled", - "path": "/noop", - "status": 200, - "ttfb_ms": 710.2, - "total_ms": 712.6, - "tls_ms": 85.1, - "after_connection_ms": 625.0, - "ray": "a4b1bd54df1c67ae-DFW", - "instance": "1ccb4d10-1c6a-4c57-8bb5-568d99019656", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 1, - "wall_ms": 1, - "version": "b25cb085-0e77-4053-be83-70ce147db3cc" - }, - { - "worker": "single-js", - "run": "settled", - "path": "/noop", - "status": 200, - "ttfb_ms": 188.1, - "total_ms": 190.5, - "tls_ms": 100.3, - "after_connection_ms": 87.7, - "ray": "a4b1bd5c9b9e5aba-DFW", - "instance": "806f8b9c-01d2-4e09-9696-12cb1ba9a48d", - "instance_request": "2", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 1, - "version": "b25cb085-0e77-4053-be83-70ce147db3cc" - }, - { - "worker": "single-js", - "run": "settled", - "path": "/noop", - "status": 200, - "ttfb_ms": 157.7, - "total_ms": 158.1, - "tls_ms": 79.9, - "after_connection_ms": 77.7, - "ray": "a4b1bd60edbcf78b-DFW", - "instance": "0e62ed3b-0cc6-4ceb-b0e1-821e9b21da0f", - "instance_request": "2", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "b25cb085-0e77-4053-be83-70ce147db3cc" - }, - { - "worker": "single-js", - "run": "settled", - "path": "/noop", - "status": 200, - "ttfb_ms": 189.2, - "total_ms": 191.7, - "tls_ms": 88.0, - "after_connection_ms": 101.1, - "ray": "a4b1bd652be24600-DFW", - "instance": "a7b69aeb-b219-41bc-a1b5-735bc4dfefac", - "instance_request": "2", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 1, - "version": "b25cb085-0e77-4053-be83-70ce147db3cc" - }, - { - "worker": "single-js", - "run": "settled", - "path": "/noop", - "status": 200, - "ttfb_ms": 457.3, - "total_ms": 459.6, - "tls_ms": 363.1, - "after_connection_ms": 94.1, - "ray": "a4b1bd6b6b1d69c6-DFW", - "instance": "1ccb4d10-1c6a-4c57-8bb5-568d99019656", - "instance_request": "2", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 1, - "version": "b25cb085-0e77-4053-be83-70ce147db3cc" - }, - { - "worker": "single-js", - "run": "settled", - "path": "/noop", - "status": 200, - "ttfb_ms": 130.6, - "total_ms": 133.0, - "tls_ms": 82.0, - "after_connection_ms": 48.5, - "ray": "a4b1bd6fca55f06e-DFW", - "instance": "c57ce07c-b465-4964-9c53-39a7e972bf20", - "instance_request": "2", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "b25cb085-0e77-4053-be83-70ce147db3cc" - }, - { - "worker": "single-js", - "run": "settled", - "path": "/noop", - "status": 200, - "ttfb_ms": 607.3, - "total_ms": 609.5, - "tls_ms": 81.1, - "after_connection_ms": 526.1, - "ray": "a4b1bd73eb9c8b23-DFW", - "instance": "1ae0abee-b15b-4116-8226-19a109d7f0a1", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "b25cb085-0e77-4053-be83-70ce147db3cc" - }, - { - "worker": "single-js", - "run": "settled", - "path": "/noop", - "status": 200, - "ttfb_ms": 158.3, - "total_ms": 160.7, - "tls_ms": 83.4, - "after_connection_ms": 74.9, - "ray": "a4b1bd7aeaa23064-DFW", - "instance": "0e62ed3b-0cc6-4ceb-b0e1-821e9b21da0f", - "instance_request": "3", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "b25cb085-0e77-4053-be83-70ce147db3cc" - }, - { - "worker": "single-js", - "run": "settled", - "path": "/noop", - "status": 200, - "ttfb_ms": 130.1, - "total_ms": 130.5, - "tls_ms": 78.5, - "after_connection_ms": 51.6, - "ray": "a4b1bd7f28fdc0e5-DFW", - "instance": "2be62297-0369-4634-98de-999bd64ad5f6", - "instance_request": "2", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 1, - "version": "b25cb085-0e77-4053-be83-70ce147db3cc" - }, - { - "worker": "single-js", - "run": "settled", - "path": "/noop", - "status": 200, - "ttfb_ms": 137.3, - "total_ms": 139.8, - "tls_ms": 82.2, - "after_connection_ms": 55.0, - "ray": "a4b1bd833dc369de-DFW", - "instance": "1ccb4d10-1c6a-4c57-8bb5-568d99019656", - "instance_request": "3", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "b25cb085-0e77-4053-be83-70ce147db3cc" - }, - { - "worker": "single-js", - "run": "settled", - "path": "/noop", - "status": 200, - "ttfb_ms": 170.4, - "total_ms": 170.9, - "tls_ms": 81.7, - "after_connection_ms": 88.6, - "ray": "a4b1bd8759cb37ee-DFW", - "instance": "806f8b9c-01d2-4e09-9696-12cb1ba9a48d", - "instance_request": "3", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "b25cb085-0e77-4053-be83-70ce147db3cc" - } - ] - } - }, - { - "worker": "many-js", - "deployed_name": "tanstack-cold-probe-many-js", - "version": "a0943789-5e3e-4c5c-88dc-fa2c990fb267", - "upload_kib": 23256.81, - "gzip_kib": 7085.31, - "reported_startup_ms": 2, - "runs": { - "initial": [ - { - "worker": "many-js", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 597.1, - "total_ms": 600.3, - "tls_ms": 131.5, - "after_connection_ms": 465.5, - "ray": "a4b1b4f44d7cceb7-DFW", - "instance": "4c0eed89-05a5-4a11-80ca-6478b6f9f64d", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null - }, - { - "worker": "many-js", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 158.6, - "total_ms": 160.9, - "tls_ms": 88.3, - "after_connection_ms": 70.2, - "ray": "a4b1b4fafb1b51ac-DFW", - "instance": "4c0eed89-05a5-4a11-80ca-6478b6f9f64d", - "instance_request": "2", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "a0943789-5e3e-4c5c-88dc-fa2c990fb267" - }, - { - "worker": "many-js", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 588.6, - "total_ms": 589.1, - "tls_ms": 163.6, - "after_connection_ms": 425.0, - "ray": "a4b1b4ffabe624e9-DFW", - "instance": "8a62c4b0-4136-410a-8b1a-fbd2101c9356", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null - }, - { - "worker": "many-js", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 491.6, - "total_ms": 494.1, - "tls_ms": 84.4, - "after_connection_ms": 407.1, - "ray": "a4b1b5061d04cd65-DFW", - "instance": "f944d1a1-5b17-4bfc-a29f-0a0708823c4f", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "a0943789-5e3e-4c5c-88dc-fa2c990fb267" - }, - { - "worker": "many-js", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 524.2, - "total_ms": 526.5, - "tls_ms": 80.8, - "after_connection_ms": 443.4, - "ray": "a4b1b50c5b051234-DFW", - "instance": "75975720-4d65-42a7-a414-abf11d8dabbc", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 1, - "version": "a0943789-5e3e-4c5c-88dc-fa2c990fb267" - }, - { - "worker": "many-js", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 563.3, - "total_ms": 563.6, - "tls_ms": 85.0, - "after_connection_ms": 478.3, - "ray": "a4b1b512dc2e133e-DFW", - "instance": "dc47fe8d-001f-4e0f-8b69-fe4b6a1dd6aa", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null - }, - { - "worker": "many-js", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 154.7, - "total_ms": 155.2, - "tls_ms": 78.4, - "after_connection_ms": 76.2, - "ray": "a4b1b5199da6504f-DFW", - "instance": "4c0eed89-05a5-4a11-80ca-6478b6f9f64d", - "instance_request": "3", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 1, - "version": "a0943789-5e3e-4c5c-88dc-fa2c990fb267" - }, - { - "worker": "many-js", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 157.1, - "total_ms": 159.5, - "tls_ms": 83.6, - "after_connection_ms": 73.4, - "ray": "a4b1b51dd9c9e86c-DFW", - "instance": "f944d1a1-5b17-4bfc-a29f-0a0708823c4f", - "instance_request": "2", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "a0943789-5e3e-4c5c-88dc-fa2c990fb267" - }, - { - "worker": "many-js", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 533.7, - "total_ms": 536.0, - "tls_ms": 80.5, - "after_connection_ms": 453.2, - "ray": "a4b1b5220b58a9f5-DFW", - "instance": "91858874-ba7a-4eb3-b7e8-929ac2932a22", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null - }, - { - "worker": "many-js", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 159.3, - "total_ms": 159.6, - "tls_ms": 101.6, - "after_connection_ms": 57.6, - "ray": "a4b1b528e9e3cd65-DFW", - "instance": "f944d1a1-5b17-4bfc-a29f-0a0708823c4f", - "instance_request": "3", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "a0943789-5e3e-4c5c-88dc-fa2c990fb267" - }, - { - "worker": "many-js", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 617.4, - "total_ms": 617.7, - "tls_ms": 145.5, - "after_connection_ms": 471.8, - "ray": "a4b1b52d5cdaf098-DFW", - "instance": "6fc22ec6-a3fc-4ecf-8e2d-0a1efc4a8949", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null - }, - { - "worker": "many-js", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 160.7, - "total_ms": 163.1, - "tls_ms": 82.9, - "after_connection_ms": 77.7, - "ray": "a4b1b5340f499b88-DFW", - "instance": "75975720-4d65-42a7-a414-abf11d8dabbc", - "instance_request": "2", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "a0943789-5e3e-4c5c-88dc-fa2c990fb267" - }, - { - "worker": "many-js", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 367.2, - "total_ms": 367.5, - "tls_ms": 80.9, - "after_connection_ms": 286.3, - "ray": "a4b1b53849dd8de5-DFW", - "instance": "9c27da3f-2e4a-47fc-9185-02981acc06e9", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 1, - "wall_ms": 1, - "version": "a0943789-5e3e-4c5c-88dc-fa2c990fb267" - }, - { - "worker": "many-js", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 524.1, - "total_ms": 526.3, - "tls_ms": 85.6, - "after_connection_ms": 438.4, - "ray": "a4b1b53dc88df02e-DFW", - "instance": "9a8ab7bb-6c3b-4e62-819d-123974fc2eff", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null - }, - { - "worker": "many-js", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 515.0, - "total_ms": 517.2, - "tls_ms": 81.1, - "after_connection_ms": 433.8, - "ray": "a4b1b544488d1002-DFW", - "instance": "41557c45-7979-4076-87b1-08f4b1004989", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null - }, - { - "worker": "many-js", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 442.7, - "total_ms": 445.1, - "tls_ms": 78.3, - "after_connection_ms": 364.4, - "ray": "a4b1b54aaa4d3ad5-DFW", - "instance": "db3d348a-8a99-4730-937f-466d635da7a7", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "a0943789-5e3e-4c5c-88dc-fa2c990fb267" - }, - { - "worker": "many-js", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 741.9, - "total_ms": 742.2, - "tls_ms": 81.4, - "after_connection_ms": 660.4, - "ray": "a4b1b550ad06143c-DFW", - "instance": "9cd96f1c-cdf9-4817-832a-0a9c25f24ede", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null - }, - { - "worker": "many-js", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 165.5, - "total_ms": 167.9, - "tls_ms": 84.0, - "after_connection_ms": 81.4, - "ray": "a4b1b5588976fa34-DFW", - "instance": "4c0eed89-05a5-4a11-80ca-6478b6f9f64d", - "instance_request": "4", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "a0943789-5e3e-4c5c-88dc-fa2c990fb267" - }, - { - "worker": "many-js", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 152.6, - "total_ms": 152.8, - "tls_ms": 83.7, - "after_connection_ms": 68.8, - "ray": "a4b1b55ccd9bf0b5-DFW", - "instance": "6fc22ec6-a3fc-4ecf-8e2d-0a1efc4a8949", - "instance_request": "2", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "a0943789-5e3e-4c5c-88dc-fa2c990fb267" - }, - { - "worker": "many-js", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 162.8, - "total_ms": 163.1, - "tls_ms": 80.2, - "after_connection_ms": 82.5, - "ray": "a4b1b560f8f42be4-DFW", - "instance": "75975720-4d65-42a7-a414-abf11d8dabbc", - "instance_request": "3", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "a0943789-5e3e-4c5c-88dc-fa2c990fb267" - }, - { - "worker": "many-js", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 159.3, - "total_ms": 159.6, - "tls_ms": 80.7, - "after_connection_ms": 78.5, - "ray": "a4b1b5653ba92c52-DFW", - "instance": "75975720-4d65-42a7-a414-abf11d8dabbc", - "instance_request": "4", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 1, - "version": "a0943789-5e3e-4c5c-88dc-fa2c990fb267" - }, - { - "worker": "many-js", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 563.3, - "total_ms": 565.7, - "tls_ms": 79.1, - "after_connection_ms": 484.2, - "ray": "a4b1b5696b46d132-DFW", - "instance": "14fd4001-bb6a-420f-9237-b262a1c0568d", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null - }, - { - "worker": "many-js", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 159.5, - "total_ms": 161.9, - "tls_ms": 82.8, - "after_connection_ms": 76.6, - "ray": "a4b1b5702c0df0b5-DFW", - "instance": "6fc22ec6-a3fc-4ecf-8e2d-0a1efc4a8949", - "instance_request": "3", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 1, - "version": "a0943789-5e3e-4c5c-88dc-fa2c990fb267" - }, - { - "worker": "many-js", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 502.5, - "total_ms": 502.8, - "tls_ms": 88.4, - "after_connection_ms": 414.0, - "ray": "a4b1b5746865f075-DFW", - "instance": "05da536c-3714-470d-ae14-483322437ca0", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null - } - ] - } - }, - { - "worker": "monolith", - "deployed_name": "tanstack-cold-probe-monolith", - "version": "8934b2f8-bf8c-40f2-bc46-eb37dd4c059b", - "upload_kib": 26244.8, - "gzip_kib": 8413.79, - "reported_startup_ms": 87, - "runs": { - "initial": [ - { - "worker": "monolith", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 1053.1, - "total_ms": 1055.5, - "tls_ms": 141.6, - "after_connection_ms": 911.5, - "ray": "a4b1b871fc74a86e-DFW", - "instance": "243d8377-2cea-4d41-92bc-16acbad1785d", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null - }, - { - "worker": "monolith", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 958.0, - "total_ms": 960.3, - "tls_ms": 84.8, - "after_connection_ms": 873.2, - "ray": "a4b1b87b793eae6e-DFW", - "instance": "a6a9e844-914e-4fac-aa4c-de2e4ce1acb7", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null - }, - { - "worker": "monolith", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 2016.5, - "total_ms": 2018.6, - "tls_ms": 77.4, - "after_connection_ms": 1939.0, - "ray": "a4b1b8849b6869d9-DFW", - "instance": "5158eb0a-4236-4509-8ff2-4a2e1bbd054d", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null - }, - { - "worker": "monolith", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 1339.1, - "total_ms": 1341.3, - "tls_ms": 80.5, - "after_connection_ms": 1258.5, - "ray": "a4b1b8948f895549-DFW", - "instance": "a17aaf4f-d508-49d8-807f-7a07a5a580c1", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 1, - "version": "8934b2f8-bf8c-40f2-bc46-eb37dd4c059b" - }, - { - "worker": "monolith", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 963.4, - "total_ms": 965.8, - "tls_ms": 79.8, - "after_connection_ms": 883.5, - "ray": "a4b1b8a01afe5843-DFW", - "instance": "e95d8ca5-e614-472b-b454-a5252a0b65ca", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "8934b2f8-bf8c-40f2-bc46-eb37dd4c059b" - }, - { - "worker": "monolith", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 142.7, - "total_ms": 142.9, - "tls_ms": 76.6, - "after_connection_ms": 66.0, - "ray": "a4b1b8a95f3d686c-DFW", - "instance": "e95d8ca5-e614-472b-b454-a5252a0b65ca", - "instance_request": "2", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "8934b2f8-bf8c-40f2-bc46-eb37dd4c059b" - }, - { - "worker": "monolith", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 226.0, - "total_ms": 228.4, - "tls_ms": 108.1, - "after_connection_ms": 117.9, - "ray": "a4b1b8adaa17bd3d-DFW", - "instance": "a6a9e844-914e-4fac-aa4c-de2e4ce1acb7", - "instance_request": "2", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "8934b2f8-bf8c-40f2-bc46-eb37dd4c059b" - }, - { - "worker": "monolith", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 1872.1, - "total_ms": 1875.0, - "tls_ms": 513.7, - "after_connection_ms": 1358.4, - "ray": "a4b1b8b4eb4c6b30-DFW", - "instance": "612c9735-bfc4-4a9f-8191-1f21fe820843", - "instance_request": "1", - "phase_ms": "0", - "server_timing": null - }, - { - "worker": "monolith", - "run": "initial", - "path": "/cache", - "status": 200, - "ttfb_ms": 1065.3, - "total_ms": 1067.7, - "tls_ms": 316.7, - "after_connection_ms": 748.5, - "ray": "a4b1b8c28d4a5549-DFW", - "instance": "7d65ab5c-b397-4a19-82bd-729992d5eeea", - "instance_request": "1", - "phase_ms": "8", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 8, - "version": "8934b2f8-bf8c-40f2-bc46-eb37dd4c059b" - }, - { - "worker": "monolith", - "run": "initial", - "path": "/cache", - "status": 200, - "ttfb_ms": 1293.3, - "total_ms": 1296.0, - "tls_ms": 79.0, - "after_connection_ms": 1214.2, - "ray": "a4b1b8caff58005c-DFW", - "instance": "45cdd671-fbba-4a3f-86b9-190c99180b7f", - "instance_request": "1", - "phase_ms": "9", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 9, - "version": "8934b2f8-bf8c-40f2-bc46-eb37dd4c059b" - }, - { - "worker": "monolith", - "run": "initial", - "path": "/cache", - "status": 200, - "ttfb_ms": 1146.5, - "total_ms": 1147.0, - "tls_ms": 83.3, - "after_connection_ms": 1063.2, - "ray": "a4b1b8d65a12a66d-DFW", - "instance": "8b1e0943-6a26-4fa6-b325-ca5dc9263ba8", - "instance_request": "1", - "phase_ms": "10", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 11, - "version": "8934b2f8-bf8c-40f2-bc46-eb37dd4c059b" - }, - { - "worker": "monolith", - "run": "initial", - "path": "/r2", - "status": 200, - "ttfb_ms": 596.4, - "total_ms": 596.7, - "tls_ms": 80.7, - "after_connection_ms": 515.7, - "ray": "a4b1b8e0b8656a3f-DFW", - "instance": "5158eb0a-4236-4509-8ff2-4a2e1bbd054d", - "instance_request": "2", - "phase_ms": "352", - "server_timing": null, - "cpu_ms": 2, - "wall_ms": 356, - "version": "8934b2f8-bf8c-40f2-bc46-eb37dd4c059b" - }, - { - "worker": "monolith", - "run": "initial", - "path": "/r2", - "status": 200, - "ttfb_ms": 381.1, - "total_ms": 381.4, - "tls_ms": 82.5, - "after_connection_ms": 298.5, - "ray": "a4b1b8e7bed71d52-DFW", - "instance": "243d8377-2cea-4d41-92bc-16acbad1785d", - "instance_request": "2", - "phase_ms": "238", - "server_timing": null, - "cpu_ms": 1, - "wall_ms": 239, - "version": "8934b2f8-bf8c-40f2-bc46-eb37dd4c059b" - }, - { - "worker": "monolith", - "run": "initial", - "path": "/r2", - "status": 200, - "ttfb_ms": 1309.1, - "total_ms": 1311.6, - "tls_ms": 82.5, - "after_connection_ms": 1226.6, - "ray": "a4b1b8ed599ff0a9-DFW", - "instance": "1b92c489-f902-4819-848c-8130e63712d4", - "instance_request": "1", - "phase_ms": "181", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 182, - "version": "8934b2f8-bf8c-40f2-bc46-eb37dd4c059b" - }, - { - "worker": "monolith", - "run": "initial", - "path": "/docs", - "status": 200, - "ttfb_ms": 618.8, - "total_ms": 736.4, - "tls_ms": 82.7, - "after_connection_ms": 536.0, - "ray": "a4b1b8f8cebd7d9f-DFW", - "instance": "a6a9e844-914e-4fac-aa4c-de2e4ce1acb7", - "instance_request": "3", - "phase_ms": "0", - "server_timing": "app_headers;dur=58.0, db_config;dur=0.0, content_edge_read;dur=106.0, start_handler;dur=58.0, db_used;desc=\"false\", docs_request;desc=\"1\"", - "cpu_ms": 520, - "wall_ms": 5317, - "version": "8934b2f8-bf8c-40f2-bc46-eb37dd4c059b", - "docs_timing": { - "logType": "docs_timing", - "workerInstance": "217bca47-2eb1-475e-8e4a-3988409b6a45", - "docsRequest": 1, - "phase": "headers_ready", - "pathname": "/router/latest/docs/routing/routing-concepts", - "ray": "a4b1b8f8cebd7d9f", - "status": 200, - "headersReadyMs": 58, - "databaseUsed": false, - "phases": [ - { - "name": "db_config", - "startMs": 0, - "durationMs": 0 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 48 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 49 - }, - { - "name": "content_edge_read", - "startMs": 49, - "durationMs": 9 - }, - { - "name": "start_handler", - "startMs": 0, - "durationMs": 58 - } - ] - } - }, - { - "worker": "monolith", - "run": "initial", - "path": "/docs", - "status": 200, - "ttfb_ms": 1340.1, - "total_ms": 1455.9, - "tls_ms": 78.5, - "after_connection_ms": 1261.6, - "ray": "a4b1b9009e8472f9-DFW", - "instance": "d3d3fd18-52fb-491d-8dc2-9f66d9647593", - "instance_request": "1", - "phase_ms": "0", - "server_timing": "app_headers;dur=59.0, db_config;dur=0.0, content_edge_read;dur=111.0, start_handler;dur=59.0, db_used;desc=\"false\", docs_request;desc=\"1\"", - "cpu_ms": 301, - "wall_ms": 361, - "version": "8934b2f8-bf8c-40f2-bc46-eb37dd4c059b", - "docs_timing": { - "logType": "docs_timing", - "workerInstance": "f65874e1-20c8-48a1-8bdc-62eacfc988fa", - "docsRequest": 1, - "phase": "headers_ready", - "pathname": "/router/latest/docs/routing/routing-concepts", - "ray": "a4b1b9009e8472f9", - "status": 200, - "headersReadyMs": 59, - "databaseUsed": false, - "phases": [ - { - "name": "db_config", - "startMs": 0, - "durationMs": 0 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 52 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 52 - }, - { - "name": "content_edge_read", - "startMs": 52, - "durationMs": 7 - }, - { - "name": "start_handler", - "startMs": 0, - "durationMs": 59 - } - ] - } - }, - { - "worker": "monolith", - "run": "initial", - "path": "/docs", - "status": 200, - "ttfb_ms": 1124.6, - "total_ms": 1243.1, - "tls_ms": 84.4, - "after_connection_ms": 1040.1, - "ray": "a4b1b90cec306701-DFW", - "instance": "5158eb0a-4236-4509-8ff2-4a2e1bbd054d", - "instance_request": "3", - "phase_ms": "0", - "server_timing": "app_headers;dur=100.0, db_config;dur=0.0, content_edge_read;dur=184.0, start_handler;dur=100.0, db_used;desc=\"false\", docs_request;desc=\"1\"", - "cpu_ms": 854, - "wall_ms": 935, - "version": "8934b2f8-bf8c-40f2-bc46-eb37dd4c059b", - "docs_timing": { - "logType": "docs_timing", - "workerInstance": "ee8c12e6-8e07-4418-8fa7-6a0dc5c0cf4d", - "docsRequest": 1, - "phase": "headers_ready", - "pathname": "/router/latest/docs/routing/routing-concepts", - "ray": "a4b1b90cec306701", - "status": 200, - "headersReadyMs": 100, - "databaseUsed": false, - "phases": [ - { - "name": "db_config", - "startMs": 0, - "durationMs": 0 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 84 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 88 - }, - { - "name": "content_edge_read", - "startMs": 88, - "durationMs": 12 - }, - { - "name": "start_handler", - "startMs": 0, - "durationMs": 100 - } - ] - } - }, - { - "worker": "monolith", - "run": "initial", - "path": "/docs", - "status": 200, - "ttfb_ms": 389.0, - "total_ms": 507.0, - "tls_ms": 85.7, - "after_connection_ms": 303.3, - "ray": "a4b1b917eb806a08-DFW", - "instance": "5158eb0a-4236-4509-8ff2-4a2e1bbd054d", - "instance_request": "4", - "phase_ms": "0", - "server_timing": "app_headers;dur=17.0, db_config;dur=0.0, content_edge_read;dur=28.0, start_handler;dur=17.0, db_used;desc=\"false\", docs_request;desc=\"2\"", - "cpu_ms": 197, - "wall_ms": 220, - "version": "8934b2f8-bf8c-40f2-bc46-eb37dd4c059b", - "docs_timing": { - "logType": "docs_timing", - "workerInstance": "ee8c12e6-8e07-4418-8fa7-6a0dc5c0cf4d", - "docsRequest": 2, - "phase": "headers_ready", - "pathname": "/router/latest/docs/routing/routing-concepts", - "ray": "a4b1b917eb806a08", - "status": 200, - "headersReadyMs": 17, - "databaseUsed": false, - "phases": [ - { - "name": "db_config", - "startMs": 0, - "durationMs": 0 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 10 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 11 - }, - { - "name": "content_edge_read", - "startMs": 10, - "durationMs": 7 - }, - { - "name": "start_handler", - "startMs": 0, - "durationMs": 17 - } - ] - } - }, - { - "worker": "monolith", - "run": "initial", - "path": "/docs", - "status": 200, - "ttfb_ms": 2686.4, - "total_ms": 2807.6, - "tls_ms": 84.8, - "after_connection_ms": 2601.5, - "ray": "a4b1b91e5cae466b-DFW", - "instance": "8e1e845c-74ac-44b1-abf4-6156c15fd840", - "instance_request": "1", - "phase_ms": "0", - "server_timing": "app_headers;dur=102.0, db_config;dur=0.0, content_edge_read;dur=188.0, start_handler;dur=102.0, db_used;desc=\"false\", docs_request;desc=\"1\"", - "cpu_ms": 666, - "wall_ms": 768, - "version": "8934b2f8-bf8c-40f2-bc46-eb37dd4c059b", - "docs_timing": { - "logType": "docs_timing", - "workerInstance": "025218ac-39f6-4a39-8036-3b1ff140b450", - "docsRequest": 1, - "phase": "headers_ready", - "pathname": "/router/latest/docs/routing/routing-concepts", - "ray": "a4b1b91e5cae466b", - "status": 200, - "headersReadyMs": 102, - "databaseUsed": false, - "phases": [ - { - "name": "db_config", - "startMs": 0, - "durationMs": 0 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 86 - }, - { - "name": "content_edge_read", - "startMs": 0, - "durationMs": 88 - }, - { - "name": "content_edge_read", - "startMs": 88, - "durationMs": 14 - }, - { - "name": "start_handler", - "startMs": 0, - "durationMs": 102 - } - ] - } - }, - { - "worker": "monolith", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 157.4, - "total_ms": 157.9, - "tls_ms": 82.9, - "after_connection_ms": 74.3, - "ray": "a4b1b9332d1c6dd6-DFW", - "instance": "e95d8ca5-e614-472b-b454-a5252a0b65ca", - "instance_request": "3", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 0, - "version": "8934b2f8-bf8c-40f2-bc46-eb37dd4c059b" - }, - { - "worker": "monolith", - "run": "initial", - "path": "/noop", - "status": 200, - "ttfb_ms": 172.8, - "total_ms": 175.1, - "tls_ms": 85.0, - "after_connection_ms": 87.7, - "ray": "a4b1b937687d46d7-DFW", - "instance": "8e1e845c-74ac-44b1-abf4-6156c15fd840", - "instance_request": "2", - "phase_ms": "0", - "server_timing": null, - "cpu_ms": 0, - "wall_ms": 1, - "version": "8934b2f8-bf8c-40f2-bc46-eb37dd4c059b" - } - ] - } - } - ], - "largest_server_chunks": [ - { - "file": "ds.iconography.lazy-CQF6TLzF.js", - "bytes": 3804141, - "source_count": 2592, - "selected_sources": [ - "../../../src/components/ds/phosphor-icons.generated.ts", - "../../../src/routes/ds.iconography.lazy.tsx" - ] - }, - { - "file": "takumi_wasm_bg-MflJu3FC.wasm", - "bytes": 3734240, - "source_count": null, - "selected_sources": [] - }, - { - "file": "ai-QFQlMoNQ.js", - "bytes": 1899843, - "source_count": 1, - "selected_sources": [ - "../../../node_modules/.pnpm/@tanstack+create@0.70.1/node_modules/@tanstack/create/dist/generated/worker/frameworks/react/add-ons/ai.js" - ] - }, - { - "file": "App-CceFJ2uL.js", - "bytes": 1232478, - "source_count": 812, - "selected_sources": [ - "../../../src/chat/components/useUrlMessageFocus.ts", - "../../../src/chat/components/ConversationView.tsx", - "../../../src/chat/components/useNavigatorResize.ts", - "../../../src/chat/components/ConversationNavigator.tsx", - "../../../src/chat/components/CommandPalette.tsx", - "../../../src/chat/components/appearance-account.ts", - "../../../src/chat/components/WorkspaceCommands.tsx", - "../../../src/chat/components/SettingsFocusSection.tsx", - "../../../src/chat/components/Onboarding.tsx", - "../../../src/chat/components/bootstrap-onboarding.ts", - "../../../src/chat/components/AppearanceSettings.tsx", - "../../../src/chat/components/App.tsx" - ] - }, - { - "file": "run-models-C5RraMbZ.js", - "bytes": 1013948, - "source_count": 318, - "selected_sources": [ - "../../../src/chat/core/routing.ts", - "../../../src/chat/server/model-attachments.ts", - "../../../src/chat/server/run-models.ts" - ] - }, - { - "file": "blog-DfBvCpTe.js", - "bytes": 841491, - "source_count": 3, - "selected_sources": [ - "../../../src/utils/blog-format.ts", - "../../../.content-collections/generated/allPosts.js", - "../../../src/utils/blog.ts" - ] - }, - { - "file": "conversation-CfC_FNYP.js", - "bytes": 689033, - "source_count": 144, - "selected_sources": [ - "../../../src/chat/server/provider-observation.ts", - "../../../src/chat/server/providers.ts", - "../../../src/chat/server/discovery-model.ts", - "../../../src/chat/server/jev-router.ts", - "../../../src/chat/core/answers.ts", - "../../../src/chat/core/research-loop.ts", - "../../../src/chat/server/research.ts", - "../../../src/chat/server/provider-token-totals.ts", - "../../../src/chat/server/usage-cost.ts", - "../../../src/chat/server/usage.ts", - "../../../src/chat/server/kody-setup-readiness.ts", - "../../../src/chat/server/conversation.ts" - ] - }, - { - "file": "discovery-integrations-9BcnTPsE.js", - "bytes": 591551, - "source_count": 96, - "selected_sources": [ - "../../../node_modules/.pnpm/@babel+types@7.29.8/node_modules/@babel/types/lib/validators/generated/index.js", - "../../../node_modules/.pnpm/@babel+types@7.29.8/node_modules/@babel/types/lib/builders/generated/lowercase.js", - "../../../node_modules/.pnpm/@babel+types@7.29.8/node_modules/@babel/types/lib/builders/generated/uppercase.js", - "../../../node_modules/.pnpm/@babel+types@7.29.8/node_modules/@babel/types/lib/builders/generated/index.js", - "../../../node_modules/.pnpm/@babel+types@7.29.8/node_modules/@babel/types/lib/asserts/generated/index.js", - "../../../node_modules/.pnpm/@babel+types@7.29.8/node_modules/@babel/types/lib/constants/generated/index.js", - "../../../src/chat/server/kody-actions.ts", - "../../../src/chat/server/type-contract.ts", - "../../../src/chat/server/discovery-integrations/kody-contract.ts", - "../../../src/chat/server/discovery-integrations/contract.ts", - "../../../src/chat/server/discovery-integrations/kody.ts", - "../../../src/chat/server/discovery-integrations/index.ts" - ] - }, - { - "file": "sdk-DVisKDdM.js", - "bytes": 522967, - "source_count": 435, - "selected_sources": [ - "../../../node_modules/.pnpm/@opentelemetry+instrumentation-tedious@0.33.0_@opentelemetry+api@1.9.1/node_modules/@opentelemetry/instrumentation-tedious/build/src/instrumentation.js", - "../../../node_modules/.pnpm/@opentelemetry+instrumentation-tedious@0.33.0_@opentelemetry+api@1.9.1/node_modules/@opentelemetry/instrumentation-tedious/build/src/index.js", - "../../../node_modules/.pnpm/@opentelemetry+instrumentation-generic-pool@0.57.0_@opentelemetry+api@1.9.1/node_modules/@opentelemetry/instrumentation-generic-pool/build/src/version.js", - "../../../node_modules/.pnpm/@opentelemetry+instrumentation-generic-pool@0.57.0_@opentelemetry+api@1.9.1/node_modules/@opentelemetry/instrumentation-generic-pool/build/src/instrumentation.js", - "../../../node_modules/.pnpm/@opentelemetry+instrumentation-generic-pool@0.57.0_@opentelemetry+api@1.9.1/node_modules/@opentelemetry/instrumentation-generic-pool/build/src/index.js", - "../../../node_modules/.pnpm/@opentelemetry+instrumentation-amqplib@0.61.0_@opentelemetry+api@1.9.1/node_modules/@opentelemetry/instrumentation-amqplib/build/src/semconv.js", - "../../../node_modules/.pnpm/@opentelemetry+instrumentation-amqplib@0.61.0_@opentelemetry+api@1.9.1/node_modules/@opentelemetry/instrumentation-amqplib/build/src/semconv-obsolete.js", - "../../../node_modules/.pnpm/@opentelemetry+instrumentation-amqplib@0.61.0_@opentelemetry+api@1.9.1/node_modules/@opentelemetry/instrumentation-amqplib/build/src/types.js", - "../../../node_modules/.pnpm/@opentelemetry+instrumentation-amqplib@0.61.0_@opentelemetry+api@1.9.1/node_modules/@opentelemetry/instrumentation-amqplib/build/src/utils.js", - "../../../node_modules/.pnpm/@opentelemetry+instrumentation-amqplib@0.61.0_@opentelemetry+api@1.9.1/node_modules/@opentelemetry/instrumentation-amqplib/build/src/version.js", - "../../../node_modules/.pnpm/@opentelemetry+instrumentation-amqplib@0.61.0_@opentelemetry+api@1.9.1/node_modules/@opentelemetry/instrumentation-amqplib/build/src/amqplib.js", - "../../../node_modules/.pnpm/@opentelemetry+instrumentation-amqplib@0.61.0_@opentelemetry+api@1.9.1/node_modules/@opentelemetry/instrumentation-amqplib/build/src/index.js" - ] - }, - { - "file": "chunk-K5T4RW27-CjFykgqp.js", - "bytes": 481708, - "source_count": 176, - "selected_sources": [ - "../../../node_modules/.pnpm/chevrotain@11.1.2/node_modules/chevrotain/lib/src/lang/lang_extensions.js", - "../../../node_modules/.pnpm/chevrotain@11.1.2/node_modules/chevrotain/lib/src/parse/cst/cst_visitor.js", - "../../../node_modules/.pnpm/chevrotain@11.1.2/node_modules/chevrotain/lib/src/parse/parser/traits/tree_builder.js", - "../../../node_modules/.pnpm/chevrotain@11.1.2/node_modules/chevrotain/lib/src/parse/parser/traits/lexer_adapter.js", - "../../../node_modules/.pnpm/chevrotain@11.1.2/node_modules/chevrotain/lib/src/parse/parser/traits/recognizer_api.js", - "../../../node_modules/.pnpm/chevrotain@11.1.2/node_modules/chevrotain/lib/src/parse/parser/traits/recognizer_engine.js", - "../../../node_modules/.pnpm/chevrotain@11.1.2/node_modules/chevrotain/lib/src/parse/parser/traits/error_handler.js", - "../../../node_modules/.pnpm/chevrotain@11.1.2/node_modules/chevrotain/lib/src/parse/parser/traits/context_assist.js", - "../../../node_modules/.pnpm/chevrotain@11.1.2/node_modules/chevrotain/lib/src/parse/parser/traits/gast_recorder.js", - "../../../node_modules/.pnpm/chevrotain@11.1.2/node_modules/chevrotain/lib/src/parse/parser/traits/perf_tracer.js", - "../../../node_modules/.pnpm/chevrotain@11.1.2/node_modules/chevrotain/lib/src/parse/parser/utils/apply_mixins.js", - "../../../node_modules/.pnpm/chevrotain@11.1.2/node_modules/chevrotain/lib/src/parse/parser/parser.js" - ] - }, - { - "file": "server-BP6igsKL.js", - "bytes": 447071, - "source_count": 256, - "selected_sources": [] - }, - { - "file": "cytoscape.esm-j_LpqIHe.js", - "bytes": 438713, - "source_count": 1, - "selected_sources": [] - } - ], - "local_requests": [ - { - "label": "first", - "status": 200, - "headersMs": 134.701333, - "totalMs": 141.52879199999998, - "bytes": 359590, - "timing": "app_headers;dur=112.0, db_config;dur=1.0, content_edge_read;dur=12.0, start_handler;dur=108.0, db_used;desc=\"false\", docs_request;desc=\"1\"", - "samples": 953 - }, - { - "label": "repeat", - "status": 200, - "headersMs": 23.98745800000006, - "totalMs": 26.91979200000003, - "bytes": 357139, - "timing": "app_headers;dur=15.0, db_config;dur=0.0, content_edge_read;dur=2.0, start_handler;dur=14.0, db_used;desc=\"false\", docs_request;desc=\"2\"", - "samples": 653 - } - ], - "local_cpu_attribution": { - "first": { - "activeMs": 162.52, - "idleMs": 198.15, - "functions": [ - { - "source": "runtime", - "name": "(program)", - "self_ms": 27.77 - }, - { - "source": "runtime", - "name": "run", - "self_ms": 15.55 - }, - { - "source": "../../../src/utils/github-content-cache.server.ts", - "name": "Tt", - "line": 324, - "self_ms": 8.52 - }, - { - "source": "../../../src/utils/partner-placement.ts", - "name": "F", - "line": 101, - "self_ms": 7.4 - }, - { - "source": "runtime", - "name": "text", - "self_ms": 5.8 - }, - { - "source": "assets/blog-DfBvCpTe.js", - "name": "", - "self_ms": 5.37 - }, - { - "source": "runtime", - "name": "(garbage collector)", - "self_ms": 4.78 - }, - { - "source": "assets/rolldown-runtime-DwyjGMXk.js", - "name": "u", - "self_ms": 3.52 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+start-server-core@1.169.39/node_modules/@tanstack/start-server-core/dist/esm/router-manifest.js", - "name": "Da", - "line": 13, - "self_ms": 3.48 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+redact@0.1.4_vite@8.0.16_@types+node@25.5.0_esbuild@0.27.4_jiti@2.7.0_tsx@4.21.0_yaml@2.9.0_/node_modules/@tanstack/redact/dist/server/walk.js", - "name": "gi", - "line": 269, - "self_ms": 3.19 - }, - { - "source": "../../../node_modules/.pnpm/tailwind-merge@3.5.0/node_modules/tailwind-merge/dist/bundle-mjs.mjs", - "name": "ye", - "line": 68, - "self_ms": 2.42 - }, - { - "source": "../../../node_modules/.pnpm/seroval@1.6.7/node_modules/seroval/dist/index.js", - "name": "ge", - "line": 167, - "self_ms": 2.06 - }, - { - "source": "runtime", - "name": "readdir", - "self_ms": 1.43 - }, - { - "source": "assets/rolldown-runtime-DwyjGMXk.js", - "name": "", - "self_ms": 1.41 - }, - { - "source": "../../../src/utils/request-timing.server.ts", - "name": "S", - "line": 90, - "self_ms": 1.41 - }, - { - "source": "../../../src/utils/documents.server.ts", - "name": "", - "line": 1093, - "self_ms": 1.28 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+redact@0.1.4_vite@8.0.16_@types+node@25.5.0_esbuild@0.27.4_jiti@2.7.0_tsx@4.21.0_yaml@2.9.0_/node_modules/@tanstack/redact/dist/server/walk.js", - "name": "mn", - "line": 93, - "self_ms": 1.27 - }, - { - "source": "runtime", - "name": "put", - "self_ms": 1.23 - }, - { - "source": "assets/rolldown-runtime-DwyjGMXk.js", - "name": "P", - "self_ms": 0.9 - }, - { - "source": "assets/documents.server-nSmHm7yy.js", - "name": "", - "self_ms": 0.9 - }, - { - "source": "../../../node_modules/.pnpm/tailwind-merge@3.5.0/node_modules/tailwind-merge/dist/bundle-mjs.mjs", - "name": "o", - "line": 245, - "self_ms": 0.8 - }, - { - "source": "runtime", - "name": "ReadableStream", - "self_ms": 0.78 - }, - { - "source": "../../../src/utils/docs.functions.ts?tss-serverfn-split", - "name": "", - "line": 362, - "self_ms": 0.76 - }, - { - "source": "../../../src/utils/github-content-cache.server.ts", - "name": "V", - "line": 455, - "self_ms": 0.66 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+start-client-core@1.170.34/node_modules/@tanstack/start-client-core/dist/esm/createServerFn.js", - "name": "server", - "line": 193, - "self_ms": 0.65 - }, - { - "source": "../../../node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/core/core.js", - "name": "n", - "line": 6, - "self_ms": 0.64 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+router-core@1.171.34/node_modules/@tanstack/router-core/dist/esm/new-process-route-tree.js", - "name": "a", - "line": 255, - "self_ms": 0.64 - }, - { - "source": "../../../node_modules/.pnpm/valibot@1.3.1_typescript@6.0.2/node_modules/valibot/dist/index.mjs", - "name": "be", - "line": 7240, - "self_ms": 0.63 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+redact@0.1.4_vite@8.0.16_@types+node@25.5.0_esbuild@0.27.4_jiti@2.7.0_tsx@4.21.0_yaml@2.9.0_/node_modules/@tanstack/redact/dist/server/walk.js", - "name": "Om", - "line": 160, - "self_ms": 0.59 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+markdown@1.0.0_octane@0.1.13_react-dom@19.2.3_react@19.2.3__react@19.2.3_vite_be296f75eff2a49ec73fb9e97ef8d921/node_modules/@tanstack/markdown/dist/extensions/framework.js", - "name": "U", - "line": 2, - "self_ms": 0.59 - }, - { - "source": "../../../node_modules/.pnpm/parse5@7.3.0/node_modules/parse5/dist/tokenizer/index.js", - "name": "_appendCharToCurrentCharacterToken", - "line": 442, - "self_ms": 0.58 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+highlight@1.0.0/node_modules/@tanstack/highlight/dist/internal/patterns.js", - "name": "_", - "line": 4, - "self_ms": 0.57 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+markdown@1.0.0_octane@0.1.13_react-dom@19.2.3_react@19.2.3__react@19.2.3_vite_be296f75eff2a49ec73fb9e97ef8d921/node_modules/@tanstack/markdown/dist/parser.js", - "name": "we", - "line": 313, - "self_ms": 0.56 - }, - { - "source": "assets/github-content-cache.server-QuLP0RGF.js", - "name": "", - "self_ms": 0.53 - }, - { - "source": "../../../src/utils/documents.server.ts", - "name": "Ut", - "line": 1070, - "self_ms": 0.52 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+router-core@1.171.34/node_modules/@tanstack/router-core/dist/esm/ssr/transformStreamWithRouter.js", - "name": "G", - "line": 456, - "self_ms": 0.52 - }, - { - "source": "assets/router-6StV-lzu.js", - "name": "", - "self_ms": 0.51 - }, - { - "source": "../../../node_modules/.pnpm/isbot@5.1.37/node_modules/isbot/index.mjs", - "name": "Jm", - "line": 202, - "self_ms": 0.51 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+router-core@1.171.34/node_modules/@tanstack/router-core/dist/esm/route.js", - "name": "Ji.init", - "line": 21, - "self_ms": 0.51 - }, - { - "source": "../../../src/utils/docsNavTabs.ts", - "name": "f", - "line": 31, - "self_ms": 0.5 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+router-core@1.171.34/node_modules/@tanstack/router-core/dist/esm/new-process-route-tree.js", - "name": "Ht", - "line": 45, - "self_ms": 0.5 - }, - { - "source": "../../../node_modules/.pnpm/tailwind-merge@3.5.0/node_modules/tailwind-merge/dist/bundle-mjs.mjs", - "name": "b", - "line": 471, - "self_ms": 0.47 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+redact@0.1.4_vite@8.0.16_@types+node@25.5.0_esbuild@0.27.4_jiti@2.7.0_tsx@4.21.0_yaml@2.9.0_/node_modules/@tanstack/redact/dist/react/element.js", - "name": "_t", - "line": 8, - "self_ms": 0.45 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+highlight@1.0.0/node_modules/@tanstack/highlight/dist/internal/script.js", - "name": "C", - "line": 43, - "self_ms": 0.45 - }, - { - "source": "../../../node_modules/.pnpm/tailwind-merge@3.5.0/node_modules/tailwind-merge/dist/bundle-mjs.mjs", - "name": "Ze", - "line": 351, - "self_ms": 0.44 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+redact@0.1.4_vite@8.0.16_@types+node@25.5.0_esbuild@0.27.4_jiti@2.7.0_tsx@4.21.0_yaml@2.9.0_/node_modules/@tanstack/redact/dist/server/walk.js", - "name": "re", - "line": 63, - "self_ms": 0.44 - }, - { - "source": "../../../src/utils/markdown/processor.ts", - "name": "oe", - "line": 37, - "self_ms": 0.4 - }, - { - "source": "../../../src/utils/documents.server.ts", - "name": "qa", - "line": 1121, - "self_ms": 0.39 - }, - { - "source": "assets/schemas-Ct7VXAhV.js", - "name": "", - "self_ms": 0.39 - }, - { - "source": "../../../node_modules/.pnpm/tailwind-merge@3.5.0/node_modules/tailwind-merge/dist/bundle-mjs.mjs", - "name": "getClassGroupId", - "line": 37, - "self_ms": 0.39 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+markdown@1.0.0_octane@0.1.13_react-dom@19.2.3_react@19.2.3__react@19.2.3_vite_be296f75eff2a49ec73fb9e97ef8d921/node_modules/@tanstack/markdown/dist/parser.js", - "name": "c", - "line": 50, - "self_ms": 0.39 - }, - { - "source": "runtime", - "name": "match", - "self_ms": 0.39 - }, - { - "source": "../../../node_modules/.pnpm/tailwind-merge@3.5.0/node_modules/tailwind-merge/dist/bundle-mjs.mjs", - "name": "n", - "line": 463, - "self_ms": 0.39 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+router-core@1.171.34/node_modules/@tanstack/router-core/dist/esm/ssr/htmlBoundaryScanner.js", - "name": "Gs", - "line": 13, - "self_ms": 0.39 - }, - { - "source": "../../../node_modules/.pnpm/parse5@7.3.0/node_modules/parse5/dist/tokenizer/index.js", - "name": "_emitCodePoint", - "line": 456, - "self_ms": 0.39 - }, - { - "source": "runtime", - "name": "read", - "self_ms": 0.38 - }, - { - "source": "../../../node_modules/.pnpm/@opentelemetry+semantic-conventions@1.40.0/node_modules/@opentelemetry/semantic-conventions/build/esm/internal/utils.js", - "name": "E", - "line": 22, - "self_ms": 0.38 - }, - { - "source": "../../../node_modules/.pnpm/seroval@1.6.7/node_modules/seroval/dist/index.js", - "name": "sl", - "line": 152, - "self_ms": 0.34 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+highlight@1.0.0/node_modules/@tanstack/highlight/dist/core.js", - "name": "K", - "line": 148, - "self_ms": 0.34 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+redact@0.1.4_vite@8.0.16_@types+node@25.5.0_esbuild@0.27.4_jiti@2.7.0_tsx@4.21.0_yaml@2.9.0_/node_modules/@tanstack/redact/dist/server/walk.js", - "name": "Mm", - "line": 298, - "self_ms": 0.33 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+markdown@1.0.0_octane@0.1.13_react-dom@19.2.3_react@19.2.3__react@19.2.3_vite_be296f75eff2a49ec73fb9e97ef8d921/node_modules/@tanstack/markdown/dist/inline.js", - "name": "_", - "line": 2, - "self_ms": 0.33 - }, - { - "source": "../../../src/server/runtime/host.server.ts", - "name": "dn", - "line": 92, - "self_ms": 0.33 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+highlight@1.0.0/node_modules/@tanstack/highlight/dist/internal/script.js", - "name": "ze", - "line": 282, - "self_ms": 0.29 - }, - { - "source": "../../../node_modules/.pnpm/seroval@1.6.7/node_modules/seroval/dist/index.js", - "name": "mh", - "line": 2574, - "self_ms": 0.27 - }, - { - "source": "runtime", - "name": "", - "self_ms": 0.27 - }, - { - "source": "node-internal:internal_querystring", - "name": "", - "self_ms": 0.27 - }, - { - "source": "../../../src/server/runtime/blob-storage.server.ts", - "name": "c", - "line": 186, - "self_ms": 0.27 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+markdown@1.0.0_octane@0.1.13_react-dom@19.2.3_react@19.2.3__react@19.2.3_vite_be296f75eff2a49ec73fb9e97ef8d921/node_modules/@tanstack/markdown/dist/parser.js", - "name": "g", - "line": 128, - "self_ms": 0.27 - }, - { - "source": "../../../node_modules/.pnpm/tailwind-merge@3.5.0/node_modules/tailwind-merge/dist/bundle-mjs.mjs", - "name": "yr", - "line": 589, - "self_ms": 0.26 - }, - { - "source": "assets/partners-BTN_k5aB.js", - "name": "", - "self_ms": 0.26 - }, - { - "source": "../../../src/utils/partner-placement.ts", - "name": "R2", - "line": 121, - "self_ms": 0.26 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+react-router@1.170.41_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@tanstack/react-router/dist/esm/router.js", - "name": "tp", - "line": 19, - "self_ms": 0.26 - }, - { - "source": "../../../node_modules/.pnpm/@sentry+core@10.47.0/node_modules/@sentry/core/build/esm/scope.js", - "name": "it", - "line": 76, - "self_ms": 0.26 - }, - { - "source": "runtime", - "name": "now", - "self_ms": 0.26 - }, - { - "source": "../../../src/utils/markdown/filterFrameworkContent.ts", - "name": "D", - "line": 36, - "self_ms": 0.26 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+redact@0.1.4_vite@8.0.16_@types+node@25.5.0_esbuild@0.27.4_jiti@2.7.0_tsx@4.21.0_yaml@2.9.0_/node_modules/@tanstack/redact/dist/server/stream.js", - "name": "ac", - "line": 34, - "self_ms": 0.26 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+redact@0.1.4_vite@8.0.16_@types+node@25.5.0_esbuild@0.27.4_jiti@2.7.0_tsx@4.21.0_yaml@2.9.0_/node_modules/@tanstack/redact/dist/server/stream.js", - "name": "p", - "line": 253, - "self_ms": 0.26 - }, - { - "source": "../../../node_modules/.pnpm/debug@4.4.3/node_modules/debug/src/common.js", - "name": "s", - "line": 60, - "self_ms": 0.26 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+router-core@1.171.34/node_modules/@tanstack/router-core/dist/esm/load-server.js", - "name": "Mu", - "line": 403, - "self_ms": 0.26 - }, - { - "source": "../../../node_modules/.pnpm/parse5@7.3.0/node_modules/parse5/dist/tree-adapters/default.js", - "name": "createElement", - "line": 17, - "self_ms": 0.26 - }, - { - "source": "../../../node_modules/.pnpm/seroval@1.6.7/node_modules/seroval/dist/index.js", - "name": "F", - "line": 2321, - "self_ms": 0.26 - }, - { - "source": "../../../src/utils/utils.ts", - "name": "N", - "line": 165, - "self_ms": 0.26 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+router-core@1.171.34/node_modules/@tanstack/router-core/dist/esm/load-server.js", - "name": "Bu", - "line": 539, - "self_ms": 0.26 - }, - { - "source": "runtime", - "name": "Headers", - "self_ms": 0.26 - }, - { - "source": "../../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/browser/dist/compose/compose-scalar.js", - "name": "", - "line": 71, - "self_ms": 0.26 - }, - { - "source": "../../../node_modules/.pnpm/parse5@7.3.0/node_modules/parse5/dist/parser/index.js", - "name": "onCharacter", - "line": 635, - "self_ms": 0.26 - }, - { - "source": "../../../src/utils/documents.server.ts", - "name": "$a", - "line": 1326, - "self_ms": 0.26 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+router-core@1.171.34/node_modules/@tanstack/router-core/dist/esm/router.js", - "name": "", - "line": 855, - "self_ms": 0.25 - }, - { - "source": "../../../src/utils/documents.server.ts", - "name": "Je", - "line": 1143, - "self_ms": 0.25 - }, - { - "source": "assets/dist-BZ4LQB0H.js", - "name": "", - "self_ms": 0.25 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+start-server-core@1.169.39/node_modules/@tanstack/start-server-core/dist/esm/createStartHandler.js", - "name": "", - "line": 274, - "self_ms": 0.25 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+router-core@1.171.34/node_modules/@tanstack/router-core/dist/esm/router.js", - "name": "s", - "line": 251, - "self_ms": 0.25 - }, - { - "source": "../../../src/utils/documents.server.ts", - "name": "", - "line": 1333, - "self_ms": 0.25 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+highlight@1.0.0/node_modules/@tanstack/highlight/dist/core.js", - "name": "R", - "line": 117, - "self_ms": 0.24 - }, - { - "source": "../../../src/components/LibraryLayout.tsx", - "name": "", - "line": 997, - "self_ms": 0.21 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+markdown@1.0.0_octane@0.1.13_react-dom@19.2.3_react@19.2.3__react@19.2.3_vite_be296f75eff2a49ec73fb9e97ef8d921/node_modules/@tanstack/markdown/dist/parser.js", - "name": "N", - "line": 443, - "self_ms": 0.19 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+router-core@1.171.34/node_modules/@tanstack/router-core/dist/esm/utils.js", - "name": "oe", - "line": 91, - "self_ms": 0.17 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+markdown@1.0.0_octane@0.1.13_react-dom@19.2.3_react@19.2.3__react@19.2.3_vite_be296f75eff2a49ec73fb9e97ef8d921/node_modules/@tanstack/markdown/dist/extensions/framework.js", - "name": "", - "line": 7, - "self_ms": 0.17 - }, - { - "source": "../../../src/utils/markdown/processor.ts", - "name": "de", - "line": 20, - "self_ms": 0.17 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+markdown@1.0.0_octane@0.1.13_react-dom@19.2.3_react@19.2.3__react@19.2.3_vite_be296f75eff2a49ec73fb9e97ef8d921/node_modules/@tanstack/markdown/dist/parser.js", - "name": "ce", - "line": 437, - "self_ms": 0.16 - }, - { - "source": "../../../src/components/markdown/FrameworkContent.tsx", - "name": "lr", - "line": 21, - "self_ms": 0.16 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+redact@0.1.4_vite@8.0.16_@types+node@25.5.0_esbuild@0.27.4_jiti@2.7.0_tsx@4.21.0_yaml@2.9.0_/node_modules/@tanstack/redact/dist/server/dispatcher.js", - "name": "useMemo", - "line": 83, - "self_ms": 0.16 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+markdown@1.0.0_octane@0.1.13_react-dom@19.2.3_react@19.2.3__react@19.2.3_vite_be296f75eff2a49ec73fb9e97ef8d921/node_modules/@tanstack/markdown/dist/react.js", - "name": "f", - "line": 11, - "self_ms": 0.16 - }, - { - "source": "node-internal:internal_inspect", - "name": "formatWithOptions", - "self_ms": 0.14 - }, - { - "source": "../../../node_modules/.pnpm/@sentry+core@10.47.0/node_modules/@sentry/core/build/esm/asyncContext/stackStrategy.js", - "name": "getScope", - "line": 68, - "self_ms": 0.14 - }, - { - "source": "../../../src/utils/partners.tsx", - "name": "_0", - "line": 175, - "self_ms": 0.14 - }, - { - "source": "../../../node_modules/.pnpm/seroval@1.6.7/node_modules/seroval/dist/index.js", - "name": "Os", - "line": 1939, - "self_ms": 0.14 - }, - { - "source": "../../src/utils/docs-html-headers.server.ts", - "name": "J", - "line": 5, - "self_ms": 0.14 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+start-server-core@1.169.39/node_modules/@tanstack/start-server-core/dist/esm/request-response.js", - "name": "", - "line": 58, - "self_ms": 0.14 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+start-server-core@1.169.39/node_modules/@tanstack/start-server-core/dist/esm/createStartHandler.js", - "name": "Jo", - "line": 26, - "self_ms": 0.14 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+markdown@1.0.0_octane@0.1.13_react-dom@19.2.3_react@19.2.3__react@19.2.3_vite_be296f75eff2a49ec73fb9e97ef8d921/node_modules/@tanstack/markdown/dist/extensions/headings.js", - "name": "V", - "line": 13, - "self_ms": 0.14 - }, - { - "source": "runtime", - "name": "URL", - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+router-core@1.171.34/node_modules/@tanstack/router-core/dist/esm/router.js", - "name": "fu", - "line": 96, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+start-server-core@1.169.39/node_modules/@tanstack/start-server-core/dist/esm/early-hints.js", - "name": "yo", - "line": 80, - "self_ms": 0.13 - }, - { - "source": "../../../src/utils/env.functions.ts", - "name": "_", - "line": 1, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+start-server-core@1.169.39/node_modules/@tanstack/start-server-core/dist/esm/transformAssetUrls.js", - "name": "Oo", - "line": 153, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/parse5@7.3.0/node_modules/parse5/dist/common/unicode.js", - "name": "", - "line": 9, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/seroval@1.6.7/node_modules/seroval/dist/index.js", - "name": "J", - "line": 2662, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+react-query@5.102.8_react@19.2.3/node_modules/@tanstack/react-query/build/modern/useBaseQuery.js", - "name": "React.useState", - "line": 27, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+router-core@1.171.34/node_modules/@tanstack/router-core/dist/esm/router.js", - "name": "buildLocation", - "line": 245, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@radix-ui+react-primitive@2.1.3_@types+react-dom@19.2.3_@types+react@19.2.14__@types+re_412fca877c3e29a339aeb07f39bb1abf/node_modules/@radix-ui/react-primitive/dist/index.mjs", - "name": "", - "line": 25, - "self_ms": 0.13 - }, - { - "source": "assets/schemas-DwJQzDBF.js", - "name": "", - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/jszip@3.10.1/node_modules/jszip/lib/stream/GenericWorker.js", - "name": "", - "line": 263, - "self_ms": 0.13 - }, - { - "source": "runtime", - "name": "entries", - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+markdown@1.0.0_octane@0.1.13_react-dom@19.2.3_react@19.2.3__react@19.2.3_vite_be296f75eff2a49ec73fb9e97ef8d921/node_modules/@tanstack/markdown/dist/parser.js", - "name": "w", - "line": 146, - "self_ms": 0.13 - }, - { - "source": "runtime", - "name": "RegExp: ^ {0,3}(?:`+|~+)\\s*$", - "self_ms": 0.13 - }, - { - "source": "runtime", - "name": "RegExp: [\\u0000-\\u001F\\u007F\\s]+", - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+router-core@1.171.34/node_modules/@tanstack/router-core/dist/esm/ssr/ssr-server.js", - "name": "li", - "line": 72, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@opentelemetry+instrumentation-mysql@0.60.0_@opentelemetry+api@1.9.1/node_modules/@opentelemetry/instrumentation-mysql/build/src/version.js", - "name": "", - "line": 21, - "self_ms": 0.13 - }, - { - "source": "../../../src/utils/partners.tsx", - "name": "h0", - "line": 1985, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/valibot@1.3.1_typescript@6.0.2/node_modules/valibot/dist/index.mjs", - "name": "j", - "line": 404, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/pako@1.0.11/node_modules/pako/lib/zlib/deflate.js", - "name": "", - "line": 1865, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+react-router@1.170.41_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@tanstack/react-router/dist/esm/route.js", - "name": "Hh", - "line": 93, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+react-router-ssr-query@1.167.2_@tanstack+query-core@5.102.8_@tanstack+react-q_21713144354376ef39f15289cdf6f1a2/node_modules/@tanstack/react-router-ssr-query/dist/esm/index.js", - "name": "xg", - "line": 6, - "self_ms": 0.13 - }, - { - "source": "../../../src/utils/docs.ts", - "name": "q", - "line": 159, - "self_ms": 0.13 - }, - { - "source": "../../../src/utils/documents.server.ts", - "name": "ya", - "line": 846, - "self_ms": 0.13 - }, - { - "source": "../../../src/utils/markdown/processor.ts", - "name": "ae", - "line": 124, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+markdown@1.0.0_octane@0.1.13_react-dom@19.2.3_react@19.2.3__react@19.2.3_vite_be296f75eff2a49ec73fb9e97ef8d921/node_modules/@tanstack/markdown/dist/extensions/comment-components.js", - "name": "_", - "line": 7, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/seroval@1.6.7/node_modules/seroval/dist/index.js", - "name": "yh", - "line": 2641, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@radix-ui+react-context@1.1.2_@types+react@19.2.14_react@19.2.3/node_modules/@radix-ui/react-context/dist/index.mjs", - "name": "", - "line": 66, - "self_ms": 0.13 - }, - { - "source": "runtime", - "name": "RegExp: [&<>]", - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+highlight@1.0.0/node_modules/@tanstack/highlight/dist/core.js", - "name": "v", - "line": 142, - "self_ms": 0.13 - }, - { - "source": "../../../src/utils/docs.functions.ts?tss-serverfn-split", - "name": "node", - "line": 583, - "self_ms": 0.13 - }, - { - "source": "runtime", - "name": "fetch", - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@sentry+core@10.47.0/node_modules/@sentry/core/build/esm/asyncContext/stackStrategy.js", - "name": "_pushScope", - "line": 89, - "self_ms": 0.13 - }, - { - "source": "node-internal:internal_fs_sync", - "name": "readdirSync", - "self_ms": 0.13 - }, - { - "source": "cloudflare-internal:http", - "name": "", - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@opentelemetry+instrumentation-pg@0.66.0_@opentelemetry+api@1.9.1/node_modules/@opentelemetry/instrumentation-pg/build/src/version.js", - "name": "", - "line": 21, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/classic/schemas.js", - "name": "Va", - "line": 186, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/valibot@1.3.1_typescript@6.0.2/node_modules/valibot/dist/index.mjs", - "name": "K", - "line": 1947, - "self_ms": 0.13 - }, - { - "source": "assets/TrafficSign.es-YCoTTu2w.js", - "name": "", - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/valibot@1.3.1_typescript@6.0.2/node_modules/valibot/dist/index.mjs", - "name": "te", - "line": 5244, - "self_ms": 0.13 - }, - { - "source": "../../../src/routes/index.tsx", - "name": "edgeAnchor", - "line": 281, - "self_ms": 0.13 - }, - { - "source": "assets/docs-webhook-sources-DGwy3Y6E.js", - "name": "", - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+start-client-core@1.170.34/node_modules/@tanstack/start-client-core/dist/esm/createServerFn.js", - "name": "ye", - "line": 153, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+start-server-core@1.169.39/node_modules/@tanstack/start-server-core/dist/esm/finalManifest.js", - "name": "r", - "line": 99, - "self_ms": 0.13 - }, - { - "source": "../../../src/libraries/libraries.ts", - "name": "X", - "line": 998, - "self_ms": 0.13 - }, - { - "source": "../../../src/queries/docsConfig.ts", - "name": "h", - "line": 17, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/browser/dist/parse/lexer.js", - "name": "parseDocument", - "line": 317, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/browser/dist/doc/Document.js", - "name": "setSchema", - "line": 252, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+markdown@1.0.0_octane@0.1.13_react-dom@19.2.3_react@19.2.3__react@19.2.3_vite_be296f75eff2a49ec73fb9e97ef8d921/node_modules/@tanstack/markdown/dist/parser.js", - "name": "xe", - "line": 329, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+markdown@1.0.0_octane@0.1.13_react-dom@19.2.3_react@19.2.3__react@19.2.3_vite_be296f75eff2a49ec73fb9e97ef8d921/node_modules/@tanstack/markdown/dist/parser.js", - "name": "l", - "line": 237, - "self_ms": 0.13 - }, - { - "source": "../../../src/utils/markdown/processor.ts", - "name": "w", - "line": 215, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/parse5@7.3.0/node_modules/parse5/dist/tokenizer/index.js", - "name": "_runParsingLoop", - "line": 205, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@radix-ui+react-context@1.1.2_@types+react@19.2.14_react@19.2.3/node_modules/@radix-ui/react-context/dist/index.mjs", - "name": "React.useMemo", - "line": 48, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/tailwind-merge@3.5.0/node_modules/tailwind-merge/dist/bundle-mjs.mjs", - "name": "get", - "line": 204, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+router-core@1.171.34/node_modules/@tanstack/router-core/dist/esm/sieve-cache.js", - "name": "set", - "line": 25, - "self_ms": 0.13 - }, - { - "source": "../../../src/components/LibraryLayout.tsx", - "name": "", - "line": 929, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+react-router@1.170.41_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@tanstack/react-router/dist/esm/link.js", - "name": "React$1.forwardRef", - "line": 314, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+markdown@1.0.0_octane@0.1.13_react-dom@19.2.3_react@19.2.3__react@19.2.3_vite_be296f75eff2a49ec73fb9e97ef8d921/node_modules/@tanstack/markdown/dist/react.js", - "name": "v", - "line": 7, - "self_ms": 0.13 - }, - { - "source": "../../../src/utils/github-content-cache.server.ts", - "name": "Nt", - "line": 1022, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+query-core@5.102.8/node_modules/@tanstack/query-core/build/modern/queryCache.js", - "name": "", - "line": 52, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@sentry+core@10.47.0/node_modules/@sentry/core/build/esm/tracing/trace.js", - "name": "me.status", - "line": 72, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@opentelemetry+api@1.9.1/node_modules/@opentelemetry/api/build/esm/diag-api.js", - "name": "", - "line": 16, - "self_ms": 0.13 - }, - { - "source": "assets/intent.functions-Ct5UaBoC.js", - "name": "", - "self_ms": 0.13 - }, - { - "source": "assets/blog-Bc_YYqxE.js", - "name": "", - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/tailwind-merge@3.5.0/node_modules/tailwind-merge/dist/bundle-mjs.mjs", - "name": "ze", - "line": 165, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/tailwind-merge@3.5.0/node_modules/tailwind-merge/dist/bundle-mjs.mjs", - "name": "$e", - "line": 143, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+start-server-core@1.169.39/node_modules/@tanstack/start-server-core/dist/esm/createStartHandler.js", - "name": "u", - "line": 172, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+router-core@1.171.34/node_modules/@tanstack/router-core/dist/esm/new-process-route-tree.js", - "name": "qe", - "line": 170, - "self_ms": 0.13 - }, - { - "source": "../../../src/utils/github-content-cache.server.ts", - "name": "c", - "line": 1297, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/browser/dist/public-api.js", - "name": "Tn", - "line": 38, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/browser/dist/parse/lexer.js", - "name": "lex", - "line": 150, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/browser/dist/parse/parser.js", - "name": "scalar", - "line": 428, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/browser/dist/compose/compose-doc.js", - "name": "yn", - "line": 6, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/browser/dist/compose/resolve-flow-scalar.js", - "name": "on", - "line": 41, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+markdown@1.0.0_octane@0.1.13_react-dom@19.2.3_react@19.2.3__react@19.2.3_vite_be296f75eff2a49ec73fb9e97ef8d921/node_modules/@tanstack/markdown/dist/extensions/callouts.js", - "name": "J", - "line": 7, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+markdown@1.0.0_octane@0.1.13_react-dom@19.2.3_react@19.2.3__react@19.2.3_vite_be296f75eff2a49ec73fb9e97ef8d921/node_modules/@tanstack/markdown/dist/inline.js", - "name": "M", - "line": 21, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+markdown@1.0.0_octane@0.1.13_react-dom@19.2.3_react@19.2.3__react@19.2.3_vite_be296f75eff2a49ec73fb9e97ef8d921/node_modules/@tanstack/markdown/dist/inline.js", - "name": "oe", - "line": 326, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/parse5@7.3.0/node_modules/parse5/dist/tree-adapters/default.js", - "name": "insertText", - "line": 88, - "self_ms": 0.13 - }, - { - "source": "../../../src/utils/seo.ts", - "name": "w", - "line": 77, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+query-core@5.102.8/node_modules/@tanstack/query-core/build/modern/hydration.js", - "name": "Cs", - "line": 28, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+redact@0.1.4_vite@8.0.16_@types+node@25.5.0_esbuild@0.27.4_jiti@2.7.0_tsx@4.21.0_yaml@2.9.0_/node_modules/@tanstack/redact/dist/server/escape.js", - "name": "pr", - "line": 68, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+query-core@5.102.8/node_modules/@tanstack/query-core/build/modern/queryObserver.js", - "name": "", - "line": 291, - "self_ms": 0.13 - }, - { - "source": "../../../src/components/Navbar.tsx", - "name": "Ad", - "line": 81, - "self_ms": 0.13 - }, - { - "source": "runtime", - "name": "RegExp: [&\"<>]", - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+react-router@1.170.41_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@tanstack/react-router/dist/esm/route.js", - "name": "Hh.useParams", - "line": 113, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+markdown@1.0.0_octane@0.1.13_react-dom@19.2.3_react@19.2.3__react@19.2.3_vite_be296f75eff2a49ec73fb9e97ef8d921/node_modules/@tanstack/markdown/dist/react.js", - "name": "b", - "line": 176, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+highlight@1.0.0/node_modules/@tanstack/highlight/dist/core.js", - "name": "c", - "line": 43, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+redact@0.1.4_vite@8.0.16_@types+node@25.5.0_esbuild@0.27.4_jiti@2.7.0_tsx@4.21.0_yaml@2.9.0_/node_modules/@tanstack/redact/dist/core/resource-hints.js", - "name": "Er", - "line": 11, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+router-core@1.171.34/node_modules/@tanstack/router-core/dist/esm/ssr/transformStreamWithRouter.js", - "name": "Rr", - "line": 157, - "self_ms": 0.13 - }, - { - "source": "../../src/server.ts", - "name": "", - "line": 228, - "self_ms": 0.13 - }, - { - "source": "../../../src/utils/documents.server.ts", - "name": "", - "line": 1157, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@sentry+core@10.47.0/node_modules/@sentry/core/build/esm/utils/handleCallbackErrors.js", - "name": "", - "line": 58, - "self_ms": 0.13 - }, - { - "source": "node-internal:internal_net", - "name": "", - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@opentelemetry+instrumentation-express@0.62.0_@opentelemetry+api@1.9.1/node_modules/@opentelemetry/instrumentation-express/build/src/version.js", - "name": "", - "line": 21, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@opentelemetry+instrumentation-redis@0.62.0_@opentelemetry+api@1.9.1/node_modules/@opentelemetry/instrumentation-redis/build/src/version.js", - "name": "", - "line": 21, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/valibot@1.3.1_typescript@6.0.2/node_modules/valibot/dist/index.mjs", - "name": "me", - "line": 7140, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/classic/schemas.js", - "name": "e.check", - "line": 21, - "self_ms": 0.13 - }, - { - "source": "assets/match-sorter.esm-B_qnfP2X.js", - "name": "", - "line": null, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+react-router@1.170.41_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@tanstack/react-router/dist/esm/lazyRouteComponent.js", - "name": "bg", - "line": 15, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/tailwind-merge@3.5.0/node_modules/tailwind-merge/dist/bundle-mjs.mjs", - "name": "x", - "line": 635, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+query-core@5.102.8/node_modules/@tanstack/query-core/build/modern/queryClient.js", - "name": "Ts", - "line": 17, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+router-core@1.171.34/node_modules/@tanstack/router-core/dist/esm/path.js", - "name": "Pi", - "line": 14, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+start-server-core@1.169.39/node_modules/@tanstack/start-server-core/dist/esm/createStartHandler.js", - "name": "u", - "line": 483, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+router-core@1.171.34/node_modules/@tanstack/router-core/dist/esm/router.js", - "name": "matchRoutesLightweight", - "line": 778, - "self_ms": 0.13 - }, - { - "source": "assets/ArrowsOutLineHorizontal.es-CUEx7LoN.js", - "name": "", - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/valibot@1.3.1_typescript@6.0.2/node_modules/valibot/dist/index.mjs", - "name": "H", - "line": 3215, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+query-core@5.102.8/node_modules/@tanstack/query-core/build/modern/query.js", - "name": "fetch", - "line": 156, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+start-client-core@1.170.34/node_modules/@tanstack/start-client-core/dist/esm/createServerFn.js", - "name": "Object.assign", - "line": 45, - "self_ms": 0.13 - }, - { - "source": "assets/browser-U4zUUJM6.js", - "name": "", - "self_ms": 0.13 - }, - { - "source": "../../../src/utils/github-content-cache.server.ts", - "name": "Vt", - "line": 1369, - "self_ms": 0.13 - }, - { - "source": "../../../src/utils/config.ts?tss-serverfn-split", - "name": "parseDocsConfig", - "line": 74, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/browser/dist/compose/resolve-block-map.js", - "name": "zs", - "line": 9, - "self_ms": 0.13 - }, - { - "source": "../../../src/utils/documents.server.ts", - "name": "va", - "line": 912, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+markdown@1.0.0_octane@0.1.13_react-dom@19.2.3_react@19.2.3__react@19.2.3_vite_be296f75eff2a49ec73fb9e97ef8d921/node_modules/@tanstack/markdown/dist/inline.js", - "name": "H", - "line": 319, - "self_ms": 0.13 - }, - { - "source": "../../../src/utils/markdown/processor.ts", - "name": "", - "line": 319, - "self_ms": 0.13 - }, - { - "source": "../../../src/utils/markdown/live-example.ts", - "name": "re", - "line": 209, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/parse5@7.3.0/node_modules/parse5/dist/parser/index.js", - "name": "getFragmentParser", - "line": 119, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/parse5@7.3.0/node_modules/parse5/dist/parser/index.js", - "name": "getFragment", - "line": 141, - "self_ms": 0.13 - }, - { - "source": "../../../src/utils/documents.server.ts", - "name": "Ga", - "line": 1027, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+router-core@1.171.34/node_modules/@tanstack/router-core/dist/esm/load-server.js", - "name": "Fu", - "line": 343, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+router-core@1.171.34/node_modules/@tanstack/router-core/dist/esm/load-server.js", - "name": "Nu", - "line": 371, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/seroval@1.6.7/node_modules/seroval/dist/index.js", - "name": "Br", - "line": 1179, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+redact@0.1.4_vite@8.0.16_@types+node@25.5.0_esbuild@0.27.4_jiti@2.7.0_tsx@4.21.0_yaml@2.9.0_/node_modules/@tanstack/redact/dist/server/walk.js", - "name": "as", - "line": 37, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+redact@0.1.4_vite@8.0.16_@types+node@25.5.0_esbuild@0.27.4_jiti@2.7.0_tsx@4.21.0_yaml@2.9.0_/node_modules/@tanstack/redact/dist/server/resource-hints.js", - "name": "addHost", - "line": 69, - "self_ms": 0.13 - }, - { - "source": "../../../src/contexts/SearchContext.tsx", - "name": "", - "line": 119, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+redact@0.1.4_vite@8.0.16_@types+node@25.5.0_esbuild@0.27.4_jiti@2.7.0_tsx@4.21.0_yaml@2.9.0_/node_modules/@tanstack/redact/dist/server/escape.js", - "name": "_m", - "line": 131, - "self_ms": 0.13 - }, - { - "source": "../../../src/components/Navbar.tsx", - "name": "", - "line": 383, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+router-core@1.171.34/node_modules/@tanstack/router-core/dist/esm/new-process-route-tree.js", - "name": "Rn", - "line": 285, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+query-core@5.102.8/node_modules/@tanstack/query-core/build/modern/removable.js", - "name": "scheduleGc", - "line": 10, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+react-router@1.170.41_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@tanstack/react-router/dist/esm/useMatch.js", - "name": "je", - "line": 22, - "self_ms": 0.13 - }, - { - "source": "../../../src/utils/docsNavTabs.ts", - "name": "c", - "line": 99, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+highlight@1.0.0/node_modules/@tanstack/highlight/dist/internal/code-fence.js", - "name": "$", - "line": 77, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+highlight@1.0.0/node_modules/@tanstack/highlight/dist/internal/script.js", - "name": "y", - "line": 37, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+redact@0.1.4_vite@8.0.16_@types+node@25.5.0_esbuild@0.27.4_jiti@2.7.0_tsx@4.21.0_yaml@2.9.0_/node_modules/@tanstack/redact/dist/server/stream.js", - "name": "Um", - "line": 188, - "self_ms": 0.13 - }, - { - "source": "../../src/utils/prod-diagnostics.server.ts", - "name": "c", - "line": 79, - "self_ms": 0.13 - }, - { - "source": "../../../src/utils/request-timing.server.ts", - "name": "pull", - "line": 106, - "self_ms": 0.13 - }, - { - "source": "assets/esm-CmcjpCbh.js", - "name": "", - "self_ms": 0.13 - }, - { - "source": "assets/esm-Ce-Mi024.js", - "name": "", - "self_ms": 0.13 - }, - { - "source": "node-internal:internal_zlib_base", - "name": "", - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@opentelemetry+api@1.9.1/node_modules/@opentelemetry/api/build/esm/internal/global-utils.js", - "name": "", - "line": 53, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/supports-color@5.5.0/node_modules/supports-color/index.js", - "name": "f", - "line": 122, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@sentry+core@10.47.0/node_modules/@sentry/core/build/esm/utils/misc.js", - "name": "lr", - "line": 127, - "self_ms": 0.13 - }, - { - "source": "assets/dist-CCiojUqn.js", - "name": "", - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/valibot@1.3.1_typescript@6.0.2/node_modules/valibot/dist/index.mjs", - "name": "ce", - "line": 6385, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/tailwind-merge@3.5.0/node_modules/tailwind-merge/dist/bundle-mjs.mjs", - "name": "E", - "line": 541, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+router-core@1.171.34/node_modules/@tanstack/router-core/dist/esm/path.js", - "name": "hs", - "line": 119, - "self_ms": 0.13 - }, - { - "source": "assets/dist-CJf1wIqo.js", - "name": "", - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/zustand@5.0.12_@types+react@19.2.14_react@19.2.3_use-sync-external-store@1.6.0_react@19.2.3_/node_modules/zustand/esm/vanilla.mjs", - "name": "l", - "line": 1, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+query-core@5.102.8/node_modules/@tanstack/query-core/build/modern/queryClient.js", - "name": "ensureQueryData", - "line": 75, - "self_ms": 0.13 - }, - { - "source": "../../../src/utils/documents.server.ts", - "name": "W", - "line": 1197, - "self_ms": 0.13 - }, - { - "source": "../../src/utils/prod-diagnostics.server.ts", - "name": "t", - "line": 113, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/browser/dist/parse/parser.js", - "name": "next", - "line": 173, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/browser/dist/parse/parser.js", - "name": "blockMap", - "line": 479, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/browser/dist/compose/composer.js", - "name": "compose", - "line": 129, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/browser/dist/public-api.js", - "name": "En", - "line": 58, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+markdown@1.0.0_octane@0.1.13_react-dom@19.2.3_react@19.2.3__react@19.2.3_vite_be296f75eff2a49ec73fb9e97ef8d921/node_modules/@tanstack/markdown/dist/extensions/docs.js", - "name": "X", - "line": 6, - "self_ms": 0.13 - }, - { - "source": "runtime", - "name": "RegExp: ^\\s*$", - "self_ms": 0.13 - }, - { - "source": "../../../src/utils/markdown/processor.ts", - "name": "ce", - "line": 134, - "self_ms": 0.13 - }, - { - "source": "../../../src/routes/_library/$libraryId/$version.docs.tsx", - "name": "headers", - "line": 23, - "self_ms": 0.13 - }, - { - "source": "../../../src/utils/docs-embed-headers.ts", - "name": "x", - "line": 12, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/seroval@1.6.7/node_modules/seroval/dist/index.js", - "name": "Fr", - "line": 400, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+react-router@1.170.41_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@tanstack/react-router/dist/esm/headContentUtils.js", - "name": "qs", - "line": 7, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+router-core@1.171.34/node_modules/@tanstack/router-core/dist/esm/path.js", - "name": "ds", - "line": 45, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+query-core@5.102.8/node_modules/@tanstack/query-core/build/modern/queryObserver.js", - "name": "createResult", - "line": 182, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+highlight@1.0.0/node_modules/@tanstack/highlight/dist/internal/script.js", - "name": "ye", - "line": 196, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+router-ssr-query-core@1.169.2_@tanstack+query-core@5.102.8_@tanstack+router-core@1.171.34/node_modules/@tanstack/router-ssr-query-core/dist/esm/index.js", - "name": "_", - "line": 86, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+react-start@1.168.60_esbuild@0.27.4_react-dom@19.2.3_react@19.2.3__react@19.2_b22d3cffd4a0ac63d50c71211c37abf6/node_modules/@tanstack/react-start/dist/default-entry/esm/server.js", - "name": "fetch", - "line": 5, - "self_ms": 0.13 - }, - { - "source": "node-internal:internal_fs_utils", - "name": "validateReaddirArgs", - "self_ms": 0.13 - }, - { - "source": "node-internal:internal_http_agent", - "name": "", - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@opentelemetry+core@2.6.1_@opentelemetry+api@1.9.1/node_modules/@opentelemetry/core/build/esm/utils/timeout.js", - "name": "", - "line": 39, - "self_ms": 0.13 - }, - { - "source": "assets/sdk-DVisKDdM.js", - "name": "", - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@opentelemetry+instrumentation-http@0.214.0_@opentelemetry+api@1.9.1/node_modules/@opentelemetry/instrumentation-http/build/src/internal-types.js", - "name": "", - "line": 28, - "self_ms": 0.13 - }, - { - "source": "assets/auth.functions-BstwcUzq.js", - "name": "", - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/tailwind-merge@3.5.0/node_modules/tailwind-merge/dist/bundle-mjs.mjs", - "name": "_e", - "line": 116, - "self_ms": 0.13 - }, - { - "source": "runtime", - "name": "get process", - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+router-core@1.171.34/node_modules/@tanstack/router-core/dist/esm/router.js", - "name": "getMatchedRoutes", - "line": 235, - "self_ms": 0.13 - }, - { - "source": "assets/_tanstack-start-manifest_v-BBqkB58P.js", - "name": "s", - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+query-core@5.102.8/node_modules/@tanstack/query-core/build/modern/queryClient.js", - "name": "fetchQuery", - "line": 171, - "self_ms": 0.13 - }, - { - "source": "../../../src/utils/docs-redirects.ts", - "name": "U", - "line": 29, - "self_ms": 0.13 - }, - { - "source": "runtime", - "name": "getStore", - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/seroval@1.6.7/node_modules/seroval/dist/index.js", - "name": "Jd", - "line": 2357, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+react-start-server@1.167.46_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@tanstack/react-start-server/dist/esm/defaultStreamHandler.js", - "name": "", - "line": 5, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+redact@0.1.4_vite@8.0.16_@types+node@25.5.0_esbuild@0.27.4_jiti@2.7.0_tsx@4.21.0_yaml@2.9.0_/node_modules/@tanstack/redact/dist/server/escape.js", - "name": "hr", - "line": 20, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+react-router@1.170.41_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@tanstack/react-router/dist/esm/link.js", - "name": "wa", - "line": 211, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+router-core@1.171.34/node_modules/@tanstack/router-core/dist/esm/new-process-route-tree.js", - "name": "Vc", - "line": 229, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+router-core@1.171.34/node_modules/@tanstack/router-core/dist/esm/ssr/handlerCallback.js", - "name": "ja", - "line": 2, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@sentry+core@10.47.0/node_modules/@sentry/core/build/esm/tracing/trace.js", - "name": "Yr", - "line": 39, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@sentry+core@10.47.0/node_modules/@sentry/core/build/esm/utils/misc.js", - "name": "I", - "line": 22, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@opentelemetry+instrumentation-mongoose@0.60.0_@opentelemetry+api@1.9.1/node_modules/@opentelemetry/instrumentation-mongoose/build/src/version.js", - "name": "", - "line": 21, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+highlight@1.0.0/node_modules/@tanstack/highlight/dist/theme.js", - "name": "o", - "line": 51, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+history@1.162.4/node_modules/@tanstack/history/dist/esm/index.js", - "name": "zi", - "line": 446, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+router-core@1.171.34/node_modules/@tanstack/router-core/dist/esm/new-process-route-tree.js", - "name": "Yc", - "line": 368, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/valibot@1.3.1_typescript@6.0.2/node_modules/valibot/dist/index.mjs", - "name": "~run", - "line": 5390, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+react-router@1.170.41_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@tanstack/react-router/dist/esm/headContentUtils.js", - "name": "", - "line": 101, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+react-router@1.170.41_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@tanstack/react-router/dist/esm/Asset.js", - "name": "Ca", - "line": 14, - "self_ms": 0.13 - }, - { - "source": "../../../src/components/ToastProvider.tsx", - "name": "$e", - "line": 24, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+redact@0.1.4_vite@8.0.16_@types+node@25.5.0_esbuild@0.27.4_jiti@2.7.0_tsx@4.21.0_yaml@2.9.0_/node_modules/@tanstack/redact/dist/react/children.js", - "name": "", - "line": 61, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@radix-ui+react-context@1.1.2_@types+react@19.2.14_react@19.2.3/node_modules/@radix-ui/react-context/dist/index.mjs", - "name": "React.useMemo", - "line": 71, - "self_ms": 0.13 - }, - { - "source": "../../../src/components/Footer.tsx", - "name": "v", - "line": 127, - "self_ms": 0.13 - }, - { - "source": "../../../src/components/Footer.tsx", - "name": "s", - "line": 106, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/sonner@2.0.7_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/sonner/dist/index.mjs", - "name": "", - "line": 916, - "self_ms": 0.13 - }, - { - "source": "../../../src/utils/github-content-cache.server.ts", - "name": "x", - "line": 606, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/jszip@3.10.1/node_modules/jszip/lib/zipObject.js", - "name": "", - "line": 133, - "self_ms": 0.12 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+start-server-core@1.169.39/node_modules/@tanstack/start-server-core/dist/esm/createStartHandler.js", - "name": "H", - "line": 350, - "self_ms": 0.12 - }, - { - "source": "../../../src/server/runtime/blob-storage.server.ts", - "name": "b", - "line": 272, - "self_ms": 0.12 - }, - { - "source": "../../../node_modules/.pnpm/tailwind-merge@3.5.0/node_modules/tailwind-merge/dist/bundle-mjs.mjs", - "name": "getConflictingClassGroupIds", - "line": 46, - "self_ms": 0.12 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+react-router@1.170.41_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@tanstack/react-router/dist/esm/link.js", - "name": "Sa", - "line": 34, - "self_ms": 0.12 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+redact@0.1.4_vite@8.0.16_@types+node@25.5.0_esbuild@0.27.4_jiti@2.7.0_tsx@4.21.0_yaml@2.9.0_/node_modules/@tanstack/redact/dist/core/attributes.js", - "name": "Ja", - "line": 7, - "self_ms": 0.12 - }, - { - "source": "../../../src/components/MegaMenuItem.tsx", - "name": "M", - "line": 39, - "self_ms": 0.12 - }, - { - "source": "../../../src/utils/docsNavTabs.ts", - "name": "d", - "line": 156, - "self_ms": 0.12 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+react-router@1.170.41_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@tanstack/react-router/dist/esm/link.js", - "name": "zh", - "line": 243, - "self_ms": 0.12 - }, - { - "source": "../../../src/utils/github-content-cache.server.ts", - "name": "Bt", - "line": 1227, - "self_ms": 0.12 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+query-core@5.102.8/node_modules/@tanstack/query-core/build/modern/queryObserver.js", - "name": "setOptions", - "line": 58, - "self_ms": 0.12 - }, - { - "source": "../../../src/components/LibraryLayout.tsx", - "name": "Xt", - "line": 663, - "self_ms": 0.12 - }, - { - "source": "../../../node_modules/.pnpm/@opentelemetry+core@2.6.1_@opentelemetry+api@1.9.1/node_modules/@opentelemetry/core/build/esm/common/global-error-handler.js", - "name": "", - "line": 24, - "self_ms": 0.12 - }, - { - "source": "../../../src/ui/Tooltip.tsx", - "name": "Be", - "line": 14, - "self_ms": 0.12 - }, - { - "source": "../../../src/components/Select.tsx", - "name": "K", - "line": 28, - "self_ms": 0.12 - }, - { - "source": "../../../node_modules/.pnpm/zustand@5.0.12_@types+react@19.2.14_react@19.2.3_use-sync-external-store@1.6.0_react@19.2.3_/node_modules/zustand/esm/react.mjs", - "name": "I", - "line": 5, - "self_ms": 0.12 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+router-core@1.171.34/node_modules/@tanstack/router-core/dist/esm/ssr/hydrationScripts.js", - "name": "Fp", - "line": 36, - "self_ms": 0.12 - }, - { - "source": "../../../node_modules/.pnpm/seroval@1.6.7/node_modules/seroval/dist/index.js", - "name": "da", - "line": 2696, - "self_ms": 0.12 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+react-router@1.170.41_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@tanstack/react-router/dist/esm/route.js", - "name": "Uh.useRouteContext", - "line": 187, - "self_ms": 0.12 - }, - { - "source": "../../../node_modules/.pnpm/lru-cache@11.2.7/node_modules/lru-cache/dist/esm/index.min.js", - "name": "j", - "line": 1, - "self_ms": 0.12 - }, - { - "source": "../../../node_modules/.pnpm/seroval@1.6.7/node_modules/seroval/dist/index.js", - "name": "oa", - "line": 1618, - "self_ms": 0.12 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+redact@0.1.4_vite@8.0.16_@types+node@25.5.0_esbuild@0.27.4_jiti@2.7.0_tsx@4.21.0_yaml@2.9.0_/node_modules/@tanstack/redact/dist/react/memo.js", - "name": "_init", - "line": 19, - "self_ms": 0.12 - }, - { - "source": "../../../src/utils/partners.tsx", - "name": "F0", - "line": 2261, - "self_ms": 0.12 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+react-router@1.170.41_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@tanstack/react-router/dist/esm/ssr/renderRouterToStream.js", - "name": "zg", - "line": 6, - "self_ms": 0.12 - }, - { - "source": "../../../src/components/ds/ui/PartnerTierLogo.tsx", - "name": "k", - "line": 44, - "self_ms": 0.12 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+start-server-core@1.169.39/node_modules/@tanstack/start-server-core/dist/esm/request-response.js", - "name": "", - "line": 45, - "self_ms": 0.12 - }, - { - "source": "../../../node_modules/.pnpm/seroval@1.6.7/node_modules/seroval/dist/index.js", - "name": "_t", - "line": 756, - "self_ms": 0.11 - }, - { - "source": "assets/builtin_esm-external-require-events-BxdsvtrH.js", - "name": "", - "self_ms": 0.11 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+router-core@1.171.34/node_modules/@tanstack/router-core/dist/esm/router.js", - "name": "matchRoutes", - "line": 228, - "self_ms": 0.11 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+markdown@1.0.0_octane@0.1.13_react-dom@19.2.3_react@19.2.3__react@19.2.3_vite_be296f75eff2a49ec73fb9e97ef8d921/node_modules/@tanstack/markdown/dist/parser.js", - "name": "parseBlocks", - "line": 93, - "self_ms": 0.11 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+redact@0.1.4_vite@8.0.16_@types+node@25.5.0_esbuild@0.27.4_jiti@2.7.0_tsx@4.21.0_yaml@2.9.0_/node_modules/@tanstack/redact/dist/server/escape.js", - "name": "Xa", - "line": 3, - "self_ms": 0.1 - }, - { - "source": "../../../node_modules/.pnpm/@phosphor-icons+react@2.1.10_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@phosphor-icons/react/dist/lib/IconBase.es.js", - "name": "e.forwardRef", - "line": 3, - "self_ms": 0.1 - }, - { - "source": "../../../node_modules/.pnpm/seroval@1.6.7/node_modules/seroval/dist/index.js", - "name": "Mr", - "line": 838, - "self_ms": 0.1 - }, - { - "source": "../../../node_modules/.pnpm/@phosphor-icons+react@2.1.10_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@phosphor-icons/react/dist/csr/LinkedinLogo.es.js", - "name": "o.forwardRef", - "line": 4, - "self_ms": 0.09 - }, - { - "source": "../../../src/components/VersionSelect.tsx", - "name": "ke", - "line": 12, - "self_ms": 0.09 - }, - { - "source": "../../../src/server/runtime/blob-storage.server.ts", - "name": "g", - "line": 145, - "self_ms": 0.09 - }, - { - "source": "../../../node_modules/.pnpm/parse5@7.3.0/node_modules/parse5/dist/common/unicode.js", - "name": "it", - "line": 46, - "self_ms": 0.09 - }, - { - "source": "../../../node_modules/.pnpm/parse5@7.3.0/node_modules/parse5/dist/tree-adapters/default.js", - "name": "appendChild", - "line": 42, - "self_ms": 0.09 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+router-core@1.171.34/node_modules/@tanstack/router-core/dist/esm/new-process-route-tree.js", - "name": "Hc", - "line": 15, - "self_ms": 0.09 - }, - { - "source": "../../../node_modules/.pnpm/sonner@2.0.7_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/sonner/dist/index.mjs", - "name": "pe", - "line": 123, - "self_ms": 0.09 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+redact@0.1.4_vite@8.0.16_@types+node@25.5.0_esbuild@0.27.4_jiti@2.7.0_tsx@4.21.0_yaml@2.9.0_/node_modules/@tanstack/redact/dist/core/resource-hints.js", - "name": "Qa", - "line": 3, - "self_ms": 0.07 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+start-server-core@1.169.39/node_modules/@tanstack/start-server-core/dist/esm/early-hints.js", - "name": "j", - "line": 12, - "self_ms": 0.07 - }, - { - "source": "../../../src/hooks/useCurrentUser.ts", - "name": "select", - "line": 15, - "self_ms": 0.07 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+router-core@1.171.34/node_modules/@tanstack/router-core/dist/esm/ssr/hydrationScripts.js", - "name": "clearTimeoutIfSet", - "line": 117, - "self_ms": 0.06 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+router-core@1.171.34/node_modules/@tanstack/router-core/dist/esm/route.js", - "name": "get id", - "line": 11, - "self_ms": 0.06 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+redact@0.1.4_vite@8.0.16_@types+node@25.5.0_esbuild@0.27.4_jiti@2.7.0_tsx@4.21.0_yaml@2.9.0_/node_modules/@tanstack/redact/dist/react/jsx-runtime.js", - "name": "le", - "line": 4, - "self_ms": 0.05 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+redact@0.1.4_vite@8.0.16_@types+node@25.5.0_esbuild@0.27.4_jiti@2.7.0_tsx@4.21.0_yaml@2.9.0_/node_modules/@tanstack/redact/dist/server/walk.js", - "name": "a", - "line": 304, - "self_ms": 0.05 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+react-router@1.170.41_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@tanstack/react-router/dist/esm/Asset.js", - "name": "ip", - "line": 68, - "self_ms": 0.05 - }, - { - "source": "../../../node_modules/.pnpm/parse5@7.3.0/node_modules/parse5/dist/tokenizer/index.js", - "name": "write", - "line": 235, - "self_ms": 0.04 - }, - { - "source": "../../../node_modules/.pnpm/parse5@7.3.0/node_modules/parse5/dist/parser/index.js", - "name": "Xs", - "line": 60, - "self_ms": 0.04 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+router-core@1.171.34/node_modules/@tanstack/router-core/dist/esm/route.js", - "name": "get fullPath", - "line": 17, - "self_ms": 0.02 - } - ], - "sources": [ - { - "source": "runtime", - "self_ms": 60.19 - }, - { - "source": "../../../src/utils/github-content-cache.server.ts", - "self_ms": 9.82 - }, - { - "source": "../../../src/utils/partner-placement.ts", - "self_ms": 7.66 - }, - { - "source": "../../../node_modules/.pnpm/tailwind-merge@3.5.0/node_modules/tailwind-merge/dist/bundle-mjs.mjs", - "self_ms": 6.06 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+redact@0.1.4_vite@8.0.16_@types+node@25.5.0_esbuild@0.27.4_jiti@2.7.0_tsx@4.21.0_yaml@2.9.0_/node_modules/@tanstack/redact/dist/server/walk.js", - "self_ms": 6 - }, - { - "source": "assets/rolldown-runtime-DwyjGMXk.js", - "self_ms": 5.83 - }, - { - "source": "assets/blog-DfBvCpTe.js", - "self_ms": 5.37 - }, - { - "source": "../../../node_modules/.pnpm/seroval@1.6.7/node_modules/seroval/dist/index.js", - "self_ms": 4.16 - }, - { - "source": "../../../src/utils/documents.server.ts", - "self_ms": 3.59 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+start-server-core@1.169.39/node_modules/@tanstack/start-server-core/dist/esm/router-manifest.js", - "self_ms": 3.48 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+markdown@1.0.0_octane@0.1.13_react-dom@19.2.3_react@19.2.3__react@19.2.3_vite_be296f75eff2a49ec73fb9e97ef8d921/node_modules/@tanstack/markdown/dist/parser.js", - "self_ms": 2.07 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+router-core@1.171.34/node_modules/@tanstack/router-core/dist/esm/new-process-route-tree.js", - "self_ms": 1.74 - }, - { - "source": "../../../src/utils/request-timing.server.ts", - "self_ms": 1.54 - }, - { - "source": "../../../node_modules/.pnpm/valibot@1.3.1_typescript@6.0.2/node_modules/valibot/dist/index.mjs", - "self_ms": 1.53 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+router-core@1.171.34/node_modules/@tanstack/router-core/dist/esm/router.js", - "self_ms": 1.13 - }, - { - "source": "../../../node_modules/.pnpm/parse5@7.3.0/node_modules/parse5/dist/tokenizer/index.js", - "self_ms": 1.13 - }, - { - "source": "../../../src/utils/markdown/processor.ts", - "self_ms": 1.08 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+highlight@1.0.0/node_modules/@tanstack/highlight/dist/internal/script.js", - "self_ms": 0.99 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+start-client-core@1.170.34/node_modules/@tanstack/start-client-core/dist/esm/createServerFn.js", - "self_ms": 0.91 - }, - { - "source": "assets/documents.server-nSmHm7yy.js", - "self_ms": 0.9 - }, - { - "source": "../../../src/utils/docs.functions.ts?tss-serverfn-split", - "self_ms": 0.89 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+highlight@1.0.0/node_modules/@tanstack/highlight/dist/core.js", - "self_ms": 0.83 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+start-server-core@1.169.39/node_modules/@tanstack/start-server-core/dist/esm/createStartHandler.js", - "self_ms": 0.77 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+router-core@1.171.34/node_modules/@tanstack/router-core/dist/esm/load-server.js", - "self_ms": 0.77 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+markdown@1.0.0_octane@0.1.13_react-dom@19.2.3_react@19.2.3__react@19.2.3_vite_be296f75eff2a49ec73fb9e97ef8d921/node_modules/@tanstack/markdown/dist/extensions/framework.js", - "self_ms": 0.77 - }, - { - "source": "../../../src/utils/docsNavTabs.ts", - "self_ms": 0.76 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+markdown@1.0.0_octane@0.1.13_react-dom@19.2.3_react@19.2.3__react@19.2.3_vite_be296f75eff2a49ec73fb9e97ef8d921/node_modules/@tanstack/markdown/dist/inline.js", - "self_ms": 0.71 - }, - { - "source": "../../../node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/core/core.js", - "self_ms": 0.64 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+redact@0.1.4_vite@8.0.16_@types+node@25.5.0_esbuild@0.27.4_jiti@2.7.0_tsx@4.21.0_yaml@2.9.0_/node_modules/@tanstack/redact/dist/server/stream.js", - "self_ms": 0.64 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+router-core@1.171.34/node_modules/@tanstack/router-core/dist/esm/ssr/transformStreamWithRouter.js", - "self_ms": 0.64 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+router-core@1.171.34/node_modules/@tanstack/router-core/dist/esm/route.js", - "self_ms": 0.59 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+highlight@1.0.0/node_modules/@tanstack/highlight/dist/internal/patterns.js", - "self_ms": 0.57 - }, - { - "source": "../../../node_modules/.pnpm/parse5@7.3.0/node_modules/parse5/dist/parser/index.js", - "self_ms": 0.55 - }, - { - "source": "assets/github-content-cache.server-QuLP0RGF.js", - "self_ms": 0.53 - }, - { - "source": "assets/router-6StV-lzu.js", - "self_ms": 0.51 - }, - { - "source": "../../../node_modules/.pnpm/isbot@5.1.37/node_modules/isbot/index.mjs", - "self_ms": 0.51 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+react-router@1.170.41_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@tanstack/react-router/dist/esm/link.js", - "self_ms": 0.5 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+redact@0.1.4_vite@8.0.16_@types+node@25.5.0_esbuild@0.27.4_jiti@2.7.0_tsx@4.21.0_yaml@2.9.0_/node_modules/@tanstack/redact/dist/server/escape.js", - "self_ms": 0.49 - }, - { - "source": "../../../src/server/runtime/blob-storage.server.ts", - "self_ms": 0.48 - }, - { - "source": "../../../node_modules/.pnpm/parse5@7.3.0/node_modules/parse5/dist/tree-adapters/default.js", - "self_ms": 0.47 - }, - { - "source": "../../../src/components/LibraryLayout.tsx", - "self_ms": 0.46 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+redact@0.1.4_vite@8.0.16_@types+node@25.5.0_esbuild@0.27.4_jiti@2.7.0_tsx@4.21.0_yaml@2.9.0_/node_modules/@tanstack/redact/dist/react/element.js", - "self_ms": 0.45 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+markdown@1.0.0_octane@0.1.13_react-dom@19.2.3_react@19.2.3__react@19.2.3_vite_be296f75eff2a49ec73fb9e97ef8d921/node_modules/@tanstack/markdown/dist/react.js", - "self_ms": 0.42 - }, - { - "source": "../../../src/utils/partners.tsx", - "self_ms": 0.39 - }, - { - "source": "assets/schemas-Ct7VXAhV.js", - "self_ms": 0.39 - }, - { - "source": "../../../node_modules/.pnpm/@radix-ui+react-context@1.1.2_@types+react@19.2.14_react@19.2.3/node_modules/@radix-ui/react-context/dist/index.mjs", - "self_ms": 0.39 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+router-core@1.171.34/node_modules/@tanstack/router-core/dist/esm/ssr/htmlBoundaryScanner.js", - "self_ms": 0.39 - }, - { - "source": "../../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/browser/dist/parse/parser.js", - "self_ms": 0.38 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+router-core@1.171.34/node_modules/@tanstack/router-core/dist/esm/path.js", - "self_ms": 0.38 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+react-router@1.170.41_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@tanstack/react-router/dist/esm/route.js", - "self_ms": 0.38 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+query-core@5.102.8/node_modules/@tanstack/query-core/build/modern/queryClient.js", - "self_ms": 0.38 - }, - { - "source": "../../../node_modules/.pnpm/@opentelemetry+semantic-conventions@1.40.0/node_modules/@opentelemetry/semantic-conventions/build/esm/internal/utils.js", - "self_ms": 0.38 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+query-core@5.102.8/node_modules/@tanstack/query-core/build/modern/queryObserver.js", - "self_ms": 0.38 - }, - { - "source": "../../../src/server/runtime/host.server.ts", - "self_ms": 0.33 - }, - { - "source": "../../../node_modules/.pnpm/@sentry+core@10.47.0/node_modules/@sentry/core/build/esm/asyncContext/stackStrategy.js", - "self_ms": 0.27 - }, - { - "source": "node-internal:internal_querystring", - "self_ms": 0.27 - }, - { - "source": "assets/partners-BTN_k5aB.js", - "self_ms": 0.26 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+react-router@1.170.41_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@tanstack/react-router/dist/esm/router.js", - "self_ms": 0.26 - }, - { - "source": "../../../node_modules/.pnpm/@sentry+core@10.47.0/node_modules/@sentry/core/build/esm/scope.js", - "self_ms": 0.26 - }, - { - "source": "../../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/browser/dist/parse/lexer.js", - "self_ms": 0.26 - }, - { - "source": "../../../node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/classic/schemas.js", - "self_ms": 0.26 - }, - { - "source": "../../../src/utils/markdown/filterFrameworkContent.ts", - "self_ms": 0.26 - }, - { - "source": "../../../src/components/Navbar.tsx", - "self_ms": 0.26 - }, - { - "source": "../../../node_modules/.pnpm/debug@4.4.3/node_modules/debug/src/common.js", - "self_ms": 0.26 - }, - { - "source": "../../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/browser/dist/public-api.js", - "self_ms": 0.26 - }, - { - "source": "../../../src/utils/utils.ts", - "self_ms": 0.26 - }, - { - "source": "../../../node_modules/.pnpm/@sentry+core@10.47.0/node_modules/@sentry/core/build/esm/tracing/trace.js", - "self_ms": 0.26 - }, - { - "source": "../../src/utils/prod-diagnostics.server.ts", - "self_ms": 0.26 - }, - { - "source": "../../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/browser/dist/compose/compose-scalar.js", - "self_ms": 0.26 - }, - { - "source": "assets/dist-BZ4LQB0H.js", - "self_ms": 0.25 - }, - { - "source": "../../../node_modules/.pnpm/@sentry+core@10.47.0/node_modules/@sentry/core/build/esm/utils/misc.js", - "self_ms": 0.25 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+start-server-core@1.169.39/node_modules/@tanstack/start-server-core/dist/esm/request-response.js", - "self_ms": 0.25 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+react-router@1.170.41_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@tanstack/react-router/dist/esm/headContentUtils.js", - "self_ms": 0.25 - }, - { - "source": "../../../src/components/Footer.tsx", - "self_ms": 0.25 - }, - { - "source": "../../../node_modules/.pnpm/parse5@7.3.0/node_modules/parse5/dist/common/unicode.js", - "self_ms": 0.22 - }, - { - "source": "../../../node_modules/.pnpm/sonner@2.0.7_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/sonner/dist/index.mjs", - "self_ms": 0.21 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+start-server-core@1.169.39/node_modules/@tanstack/start-server-core/dist/esm/early-hints.js", - "self_ms": 0.21 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+redact@0.1.4_vite@8.0.16_@types+node@25.5.0_esbuild@0.27.4_jiti@2.7.0_tsx@4.21.0_yaml@2.9.0_/node_modules/@tanstack/redact/dist/core/resource-hints.js", - "self_ms": 0.2 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+router-core@1.171.34/node_modules/@tanstack/router-core/dist/esm/ssr/hydrationScripts.js", - "self_ms": 0.18 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+react-router@1.170.41_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@tanstack/react-router/dist/esm/Asset.js", - "self_ms": 0.17 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+router-core@1.171.34/node_modules/@tanstack/router-core/dist/esm/utils.js", - "self_ms": 0.17 - }, - { - "source": "../../../src/components/markdown/FrameworkContent.tsx", - "self_ms": 0.16 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+redact@0.1.4_vite@8.0.16_@types+node@25.5.0_esbuild@0.27.4_jiti@2.7.0_tsx@4.21.0_yaml@2.9.0_/node_modules/@tanstack/redact/dist/server/dispatcher.js", - "self_ms": 0.16 - }, - { - "source": "node-internal:internal_inspect", - "self_ms": 0.14 - }, - { - "source": "../../src/utils/docs-html-headers.server.ts", - "self_ms": 0.14 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+markdown@1.0.0_octane@0.1.13_react-dom@19.2.3_react@19.2.3__react@19.2.3_vite_be296f75eff2a49ec73fb9e97ef8d921/node_modules/@tanstack/markdown/dist/extensions/headings.js", - "self_ms": 0.14 - }, - { - "source": "../../../src/utils/env.functions.ts", - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+start-server-core@1.169.39/node_modules/@tanstack/start-server-core/dist/esm/transformAssetUrls.js", - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+react-query@5.102.8_react@19.2.3/node_modules/@tanstack/react-query/build/modern/useBaseQuery.js", - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@radix-ui+react-primitive@2.1.3_@types+react-dom@19.2.3_@types+react@19.2.14__@types+re_412fca877c3e29a339aeb07f39bb1abf/node_modules/@radix-ui/react-primitive/dist/index.mjs", - "self_ms": 0.13 - }, - { - "source": "assets/schemas-DwJQzDBF.js", - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/jszip@3.10.1/node_modules/jszip/lib/stream/GenericWorker.js", - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+router-core@1.171.34/node_modules/@tanstack/router-core/dist/esm/ssr/ssr-server.js", - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@opentelemetry+instrumentation-mysql@0.60.0_@opentelemetry+api@1.9.1/node_modules/@opentelemetry/instrumentation-mysql/build/src/version.js", - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/pako@1.0.11/node_modules/pako/lib/zlib/deflate.js", - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+react-router-ssr-query@1.167.2_@tanstack+query-core@5.102.8_@tanstack+react-q_21713144354376ef39f15289cdf6f1a2/node_modules/@tanstack/react-router-ssr-query/dist/esm/index.js", - "self_ms": 0.13 - }, - { - "source": "../../../src/utils/docs.ts", - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+markdown@1.0.0_octane@0.1.13_react-dom@19.2.3_react@19.2.3__react@19.2.3_vite_be296f75eff2a49ec73fb9e97ef8d921/node_modules/@tanstack/markdown/dist/extensions/comment-components.js", - "self_ms": 0.13 - }, - { - "source": "node-internal:internal_fs_sync", - "self_ms": 0.13 - }, - { - "source": "cloudflare-internal:http", - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@opentelemetry+instrumentation-pg@0.66.0_@opentelemetry+api@1.9.1/node_modules/@opentelemetry/instrumentation-pg/build/src/version.js", - "self_ms": 0.13 - }, - { - "source": "assets/TrafficSign.es-YCoTTu2w.js", - "self_ms": 0.13 - }, - { - "source": "../../../src/routes/index.tsx", - "self_ms": 0.13 - }, - { - "source": "assets/docs-webhook-sources-DGwy3Y6E.js", - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+start-server-core@1.169.39/node_modules/@tanstack/start-server-core/dist/esm/finalManifest.js", - "self_ms": 0.13 - }, - { - "source": "../../../src/libraries/libraries.ts", - "self_ms": 0.13 - }, - { - "source": "../../../src/queries/docsConfig.ts", - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/browser/dist/doc/Document.js", - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+router-core@1.171.34/node_modules/@tanstack/router-core/dist/esm/sieve-cache.js", - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+query-core@5.102.8/node_modules/@tanstack/query-core/build/modern/queryCache.js", - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@opentelemetry+api@1.9.1/node_modules/@opentelemetry/api/build/esm/diag-api.js", - "self_ms": 0.13 - }, - { - "source": "assets/intent.functions-Ct5UaBoC.js", - "self_ms": 0.13 - }, - { - "source": "assets/blog-Bc_YYqxE.js", - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/browser/dist/compose/compose-doc.js", - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/browser/dist/compose/resolve-flow-scalar.js", - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+markdown@1.0.0_octane@0.1.13_react-dom@19.2.3_react@19.2.3__react@19.2.3_vite_be296f75eff2a49ec73fb9e97ef8d921/node_modules/@tanstack/markdown/dist/extensions/callouts.js", - "self_ms": 0.13 - }, - { - "source": "../../../src/utils/seo.ts", - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+query-core@5.102.8/node_modules/@tanstack/query-core/build/modern/hydration.js", - "self_ms": 0.13 - }, - { - "source": "../../src/server.ts", - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@sentry+core@10.47.0/node_modules/@sentry/core/build/esm/utils/handleCallbackErrors.js", - "self_ms": 0.13 - }, - { - "source": "node-internal:internal_net", - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@opentelemetry+instrumentation-express@0.62.0_@opentelemetry+api@1.9.1/node_modules/@opentelemetry/instrumentation-express/build/src/version.js", - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@opentelemetry+instrumentation-redis@0.62.0_@opentelemetry+api@1.9.1/node_modules/@opentelemetry/instrumentation-redis/build/src/version.js", - "self_ms": 0.13 - }, - { - "source": "assets/match-sorter.esm-B_qnfP2X.js", - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+react-router@1.170.41_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@tanstack/react-router/dist/esm/lazyRouteComponent.js", - "self_ms": 0.13 - }, - { - "source": "assets/ArrowsOutLineHorizontal.es-CUEx7LoN.js", - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+query-core@5.102.8/node_modules/@tanstack/query-core/build/modern/query.js", - "self_ms": 0.13 - }, - { - "source": "assets/browser-U4zUUJM6.js", - "self_ms": 0.13 - }, - { - "source": "../../../src/utils/config.ts?tss-serverfn-split", - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/browser/dist/compose/resolve-block-map.js", - "self_ms": 0.13 - }, - { - "source": "../../../src/utils/markdown/live-example.ts", - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+redact@0.1.4_vite@8.0.16_@types+node@25.5.0_esbuild@0.27.4_jiti@2.7.0_tsx@4.21.0_yaml@2.9.0_/node_modules/@tanstack/redact/dist/server/resource-hints.js", - "self_ms": 0.13 - }, - { - "source": "../../../src/contexts/SearchContext.tsx", - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+query-core@5.102.8/node_modules/@tanstack/query-core/build/modern/removable.js", - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+react-router@1.170.41_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@tanstack/react-router/dist/esm/useMatch.js", - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+highlight@1.0.0/node_modules/@tanstack/highlight/dist/internal/code-fence.js", - "self_ms": 0.13 - }, - { - "source": "assets/esm-CmcjpCbh.js", - "self_ms": 0.13 - }, - { - "source": "assets/esm-Ce-Mi024.js", - "self_ms": 0.13 - }, - { - "source": "node-internal:internal_zlib_base", - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@opentelemetry+api@1.9.1/node_modules/@opentelemetry/api/build/esm/internal/global-utils.js", - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/supports-color@5.5.0/node_modules/supports-color/index.js", - "self_ms": 0.13 - }, - { - "source": "assets/dist-CCiojUqn.js", - "self_ms": 0.13 - }, - { - "source": "assets/dist-CJf1wIqo.js", - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/zustand@5.0.12_@types+react@19.2.14_react@19.2.3_use-sync-external-store@1.6.0_react@19.2.3_/node_modules/zustand/esm/vanilla.mjs", - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/browser/dist/compose/composer.js", - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+markdown@1.0.0_octane@0.1.13_react-dom@19.2.3_react@19.2.3__react@19.2.3_vite_be296f75eff2a49ec73fb9e97ef8d921/node_modules/@tanstack/markdown/dist/extensions/docs.js", - "self_ms": 0.13 - }, - { - "source": "../../../src/routes/_library/$libraryId/$version.docs.tsx", - "self_ms": 0.13 - }, - { - "source": "../../../src/utils/docs-embed-headers.ts", - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+router-ssr-query-core@1.169.2_@tanstack+query-core@5.102.8_@tanstack+router-core@1.171.34/node_modules/@tanstack/router-ssr-query-core/dist/esm/index.js", - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+react-start@1.168.60_esbuild@0.27.4_react-dom@19.2.3_react@19.2.3__react@19.2_b22d3cffd4a0ac63d50c71211c37abf6/node_modules/@tanstack/react-start/dist/default-entry/esm/server.js", - "self_ms": 0.13 - }, - { - "source": "node-internal:internal_fs_utils", - "self_ms": 0.13 - }, - { - "source": "node-internal:internal_http_agent", - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@opentelemetry+core@2.6.1_@opentelemetry+api@1.9.1/node_modules/@opentelemetry/core/build/esm/utils/timeout.js", - "self_ms": 0.13 - }, - { - "source": "assets/sdk-DVisKDdM.js", - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@opentelemetry+instrumentation-http@0.214.0_@opentelemetry+api@1.9.1/node_modules/@opentelemetry/instrumentation-http/build/src/internal-types.js", - "self_ms": 0.13 - }, - { - "source": "assets/auth.functions-BstwcUzq.js", - "self_ms": 0.13 - }, - { - "source": "assets/_tanstack-start-manifest_v-BBqkB58P.js", - "self_ms": 0.13 - }, - { - "source": "../../../src/utils/docs-redirects.ts", - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+react-start-server@1.167.46_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@tanstack/react-start-server/dist/esm/defaultStreamHandler.js", - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+router-core@1.171.34/node_modules/@tanstack/router-core/dist/esm/ssr/handlerCallback.js", - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@opentelemetry+instrumentation-mongoose@0.60.0_@opentelemetry+api@1.9.1/node_modules/@opentelemetry/instrumentation-mongoose/build/src/version.js", - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+highlight@1.0.0/node_modules/@tanstack/highlight/dist/theme.js", - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+history@1.162.4/node_modules/@tanstack/history/dist/esm/index.js", - "self_ms": 0.13 - }, - { - "source": "../../../src/components/ToastProvider.tsx", - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+redact@0.1.4_vite@8.0.16_@types+node@25.5.0_esbuild@0.27.4_jiti@2.7.0_tsx@4.21.0_yaml@2.9.0_/node_modules/@tanstack/redact/dist/react/children.js", - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/jszip@3.10.1/node_modules/jszip/lib/zipObject.js", - "self_ms": 0.12 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+redact@0.1.4_vite@8.0.16_@types+node@25.5.0_esbuild@0.27.4_jiti@2.7.0_tsx@4.21.0_yaml@2.9.0_/node_modules/@tanstack/redact/dist/core/attributes.js", - "self_ms": 0.12 - }, - { - "source": "../../../src/components/MegaMenuItem.tsx", - "self_ms": 0.12 - }, - { - "source": "../../../node_modules/.pnpm/@opentelemetry+core@2.6.1_@opentelemetry+api@1.9.1/node_modules/@opentelemetry/core/build/esm/common/global-error-handler.js", - "self_ms": 0.12 - }, - { - "source": "../../../src/ui/Tooltip.tsx", - "self_ms": 0.12 - }, - { - "source": "../../../src/components/Select.tsx", - "self_ms": 0.12 - }, - { - "source": "../../../node_modules/.pnpm/zustand@5.0.12_@types+react@19.2.14_react@19.2.3_use-sync-external-store@1.6.0_react@19.2.3_/node_modules/zustand/esm/react.mjs", - "self_ms": 0.12 - }, - { - "source": "../../../node_modules/.pnpm/lru-cache@11.2.7/node_modules/lru-cache/dist/esm/index.min.js", - "self_ms": 0.12 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+redact@0.1.4_vite@8.0.16_@types+node@25.5.0_esbuild@0.27.4_jiti@2.7.0_tsx@4.21.0_yaml@2.9.0_/node_modules/@tanstack/redact/dist/react/memo.js", - "self_ms": 0.12 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+react-router@1.170.41_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@tanstack/react-router/dist/esm/ssr/renderRouterToStream.js", - "self_ms": 0.12 - }, - { - "source": "../../../src/components/ds/ui/PartnerTierLogo.tsx", - "self_ms": 0.12 - }, - { - "source": "assets/builtin_esm-external-require-events-BxdsvtrH.js", - "self_ms": 0.11 - }, - { - "source": "../../../node_modules/.pnpm/@phosphor-icons+react@2.1.10_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@phosphor-icons/react/dist/lib/IconBase.es.js", - "self_ms": 0.1 - }, - { - "source": "../../../node_modules/.pnpm/@phosphor-icons+react@2.1.10_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@phosphor-icons/react/dist/csr/LinkedinLogo.es.js", - "self_ms": 0.09 - }, - { - "source": "../../../src/components/VersionSelect.tsx", - "self_ms": 0.09 - }, - { - "source": "../../../src/hooks/useCurrentUser.ts", - "self_ms": 0.07 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+redact@0.1.4_vite@8.0.16_@types+node@25.5.0_esbuild@0.27.4_jiti@2.7.0_tsx@4.21.0_yaml@2.9.0_/node_modules/@tanstack/redact/dist/react/jsx-runtime.js", - "self_ms": 0.05 - } - ] - }, - "repeat": { - "activeMs": 25.44, - "idleMs": 28.13, - "functions": [ - { - "source": "runtime", - "name": "(garbage collector)", - "self_ms": 5.71 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+query-core@5.102.8/node_modules/@tanstack/query-core/build/modern/subscribable.js", - "name": "", - "line": 10, - "self_ms": 2.89 - }, - { - "source": "runtime", - "name": "get process", - "self_ms": 1.9 - }, - { - "source": "../../../src/utils/github-content-cache.server.ts", - "name": "Tt", - "line": 324, - "self_ms": 1.43 - }, - { - "source": "../../../node_modules/.pnpm/seroval@1.6.7/node_modules/seroval/dist/index.js", - "name": "ge", - "line": 167, - "self_ms": 1.32 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+redact@0.1.4_vite@8.0.16_@types+node@25.5.0_esbuild@0.27.4_jiti@2.7.0_tsx@4.21.0_yaml@2.9.0_/node_modules/@tanstack/redact/dist/server/walk.js", - "name": "re", - "line": 63, - "self_ms": 0.54 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+redact@0.1.4_vite@8.0.16_@types+node@25.5.0_esbuild@0.27.4_jiti@2.7.0_tsx@4.21.0_yaml@2.9.0_/node_modules/@tanstack/redact/dist/server/walk.js", - "name": "Om", - "line": 160, - "self_ms": 0.47 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+redact@0.1.4_vite@8.0.16_@types+node@25.5.0_esbuild@0.27.4_jiti@2.7.0_tsx@4.21.0_yaml@2.9.0_/node_modules/@tanstack/redact/dist/server/walk.js", - "name": "mn", - "line": 93, - "self_ms": 0.43 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+redact@0.1.4_vite@8.0.16_@types+node@25.5.0_esbuild@0.27.4_jiti@2.7.0_tsx@4.21.0_yaml@2.9.0_/node_modules/@tanstack/redact/dist/server/stream.js", - "name": "p", - "line": 253, - "self_ms": 0.39 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+router-core@1.171.34/node_modules/@tanstack/router-core/dist/esm/ssr/htmlBoundaryScanner.js", - "name": "Gs", - "line": 13, - "self_ms": 0.39 - }, - { - "source": "../../../src/utils/docsNavTabs.ts", - "name": "f", - "line": 31, - "self_ms": 0.37 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+highlight@1.0.0/node_modules/@tanstack/highlight/dist/internal/script.js", - "name": "C", - "line": 43, - "self_ms": 0.34 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+redact@0.1.4_vite@8.0.16_@types+node@25.5.0_esbuild@0.27.4_jiti@2.7.0_tsx@4.21.0_yaml@2.9.0_/node_modules/@tanstack/redact/dist/server/walk.js", - "name": "Mm", - "line": 298, - "self_ms": 0.34 - }, - { - "source": "../../src/server.ts", - "name": "", - "line": 228, - "self_ms": 0.26 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+start-client-core@1.170.34/node_modules/@tanstack/start-client-core/dist/esm/createServerFn.js", - "name": "a", - "line": 156, - "self_ms": 0.26 - }, - { - "source": "../../../src/utils/request-timing.server.ts", - "name": "S", - "line": 90, - "self_ms": 0.26 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+redact@0.1.4_vite@8.0.16_@types+node@25.5.0_esbuild@0.27.4_jiti@2.7.0_tsx@4.21.0_yaml@2.9.0_/node_modules/@tanstack/redact/dist/server/stream.js", - "name": "ac", - "line": 34, - "self_ms": 0.25 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+markdown@1.0.0_octane@0.1.13_react-dom@19.2.3_react@19.2.3__react@19.2.3_vite_be296f75eff2a49ec73fb9e97ef8d921/node_modules/@tanstack/markdown/dist/parser.js", - "name": "c", - "line": 50, - "self_ms": 0.2 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+markdown@1.0.0_octane@0.1.13_react-dom@19.2.3_react@19.2.3__react@19.2.3_vite_be296f75eff2a49ec73fb9e97ef8d921/node_modules/@tanstack/markdown/dist/inline.js", - "name": "P", - "line": 246, - "self_ms": 0.19 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+markdown@1.0.0_octane@0.1.13_react-dom@19.2.3_react@19.2.3__react@19.2.3_vite_be296f75eff2a49ec73fb9e97ef8d921/node_modules/@tanstack/markdown/dist/react.js", - "name": "b", - "line": 176, - "self_ms": 0.18 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+markdown@1.0.0_octane@0.1.13_react-dom@19.2.3_react@19.2.3__react@19.2.3_vite_be296f75eff2a49ec73fb9e97ef8d921/node_modules/@tanstack/markdown/dist/parser.js", - "name": "N", - "line": 443, - "self_ms": 0.17 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+query-core@5.102.8/node_modules/@tanstack/query-core/build/modern/queryObserver.js", - "name": "getOptimisticResult", - "line": 77, - "self_ms": 0.16 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+markdown@1.0.0_octane@0.1.13_react-dom@19.2.3_react@19.2.3__react@19.2.3_vite_be296f75eff2a49ec73fb9e97ef8d921/node_modules/@tanstack/markdown/dist/parser.js", - "name": "xe", - "line": 329, - "self_ms": 0.15 - }, - { - "source": "runtime", - "name": "(program)", - "self_ms": 0.14 - }, - { - "source": "../../../src/utils/repo-path.ts", - "name": "u", - "line": 5, - "self_ms": 0.14 - }, - { - "source": "../../../node_modules/.pnpm/@radix-ui+react-slot@1.2.3_@types+react@19.2.14_react@19.2.3/node_modules/@radix-ui/react-slot/dist/index.mjs", - "name": "React.forwardRef", - "line": 32, - "self_ms": 0.14 - }, - { - "source": "../../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/browser/dist/parse/parser.js", - "name": "scalar", - "line": 428, - "self_ms": 0.14 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+highlight@1.0.0/node_modules/@tanstack/highlight/dist/core.js", - "name": "Y", - "line": 76, - "self_ms": 0.14 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+router-core@1.171.34/node_modules/@tanstack/router-core/dist/esm/router.js", - "name": "update", - "line": 106, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+router-core@1.171.34/node_modules/@tanstack/router-core/dist/esm/path.js", - "name": "ds", - "line": 45, - "self_ms": 0.13 - }, - { - "source": "../../../src/utils/markdown/processor.ts", - "name": "se", - "line": 78, - "self_ms": 0.13 - }, - { - "source": "../../../src/components/library-layout-navigation.ts", - "name": "ye", - "line": 20, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+react-router@1.170.41_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@tanstack/react-router/dist/esm/link.js", - "name": "React$1.forwardRef", - "line": 314, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@phosphor-icons+react@2.1.10_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@phosphor-icons/react/dist/csr/ArrowLeft.es.js", - "name": "o.forwardRef", - "line": 4, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+start-client-core@1.170.34/node_modules/@tanstack/start-client-core/dist/esm/createServerFn.js", - "name": "executeMiddleware", - "line": 89, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/parse5@7.3.0/node_modules/parse5/dist/tokenizer/index.js", - "name": "_emitCodePoint", - "line": 456, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/parse5@7.3.0/node_modules/parse5/dist/parser/index.js", - "name": "getFragmentParser", - "line": 119, - "self_ms": 0.13 - }, - { - "source": "../../../src/routes/_library/$libraryId/$version.docs.$.tsx", - "name": "head", - "line": 80, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+router-core@1.171.34/node_modules/@tanstack/router-core/dist/esm/utils.js", - "name": "ct", - "line": 257, - "self_ms": 0.13 - }, - { - "source": "../../src/utils/prod-diagnostics.server.ts", - "name": "c", - "line": 79, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+markdown@1.0.0_octane@0.1.13_react-dom@19.2.3_react@19.2.3__react@19.2.3_vite_be296f75eff2a49ec73fb9e97ef8d921/node_modules/@tanstack/markdown/dist/parser.js", - "name": "O", - "line": 413, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/parse5@7.3.0/node_modules/parse5/dist/tokenizer/index.js", - "name": "Et", - "line": 115, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/parse5@7.3.0/node_modules/parse5/dist/parser/index.js", - "name": "onEof", - "line": 1062, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/seroval@1.6.7/node_modules/seroval/dist/index.js", - "name": "onParse", - "line": 2798, - "self_ms": 0.13 - }, - { - "source": "../../../src/routes/__root.tsx", - "name": "nu", - "line": 290, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+react-router@1.170.41_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@tanstack/react-router/dist/esm/link.js", - "name": "Ra", - "line": 267, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@radix-ui+react-context@1.1.2_@types+react@19.2.14_react@19.2.3/node_modules/@radix-ui/react-context/dist/index.mjs", - "name": "React.useMemo", - "line": 48, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+redact@0.1.4_vite@8.0.16_@types+node@25.5.0_esbuild@0.27.4_jiti@2.7.0_tsx@4.21.0_yaml@2.9.0_/node_modules/@tanstack/redact/dist/core/attributes.js", - "name": "Ja", - "line": 7, - "self_ms": 0.13 - }, - { - "source": "../../../src/utils/markdown/processor.ts", - "name": "oe", - "line": 37, - "self_ms": 0.13 - }, - { - "source": "../../../src/utils/markdown/processor.ts", - "name": "ce", - "line": 134, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/parse5@7.3.0/node_modules/parse5/dist/index.js", - "name": "Ra", - "line": 33, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/seroval@1.6.7/node_modules/seroval/dist/index.js", - "name": "Tt", - "line": 1893, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+react-router@1.170.41_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@tanstack/react-router/dist/esm/headContentUtils.js", - "name": "", - "line": 90, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+start-client-core@1.170.34/node_modules/@tanstack/start-client-core/dist/esm/createServerFn.js", - "name": "__executeServer", - "line": 62, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+markdown@1.0.0_octane@0.1.13_react-dom@19.2.3_react@19.2.3__react@19.2.3_vite_be296f75eff2a49ec73fb9e97ef8d921/node_modules/@tanstack/markdown/dist/inline.js", - "name": "_", - "line": 2, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/parse5@7.3.0/node_modules/parse5/dist/tokenizer/index.js", - "name": "_appendCharToCurrentCharacterToken", - "line": 442, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+router-ssr-query-core@1.169.2_@tanstack+query-core@5.102.8_@tanstack+router-core@1.171.34/node_modules/@tanstack/router-ssr-query-core/dist/esm/index.js", - "name": "Zm.e.options.dehydrate", - "line": 30, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/parse5@7.3.0/node_modules/parse5/dist/tokenizer/index.js", - "name": "_stateData", - "line": 792, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+router-core@1.171.34/node_modules/@tanstack/router-core/dist/esm/ssr/headers.js", - "name": "Zp", - "line": 3, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+router-core@1.171.34/node_modules/@tanstack/router-core/dist/esm/load-server.js", - "name": "Pu", - "line": 115, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+markdown@1.0.0_octane@0.1.13_react-dom@19.2.3_react@19.2.3__react@19.2.3_vite_be296f75eff2a49ec73fb9e97ef8d921/node_modules/@tanstack/markdown/dist/parser.js", - "name": "A", - "line": 298, - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@radix-ui+react-tooltip@1.2.8_@types+react-dom@19.2.3_@types+react@19.2.14__@types+reac_f164644780a8f95ec4733d733b3b08bc/node_modules/@radix-ui/react-tooltip/dist/index.mjs", - "name": "W", - "line": 71, - "self_ms": 0.13 - }, - { - "source": "../../../src/utils/docs.functions.ts?tss-serverfn-split", - "name": "loadDocumentsServerModule", - "line": 135, - "self_ms": 0.12 - }, - { - "source": "../../../node_modules/.pnpm/parse5@7.3.0/node_modules/parse5/dist/tokenizer/index.js", - "name": "_s", - "line": 141, - "self_ms": 0.12 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+router-core@1.171.34/node_modules/@tanstack/router-core/dist/esm/path.js", - "name": "zc", - "line": 110, - "self_ms": 0.12 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+router-core@1.171.34/node_modules/@tanstack/router-core/dist/esm/router.js", - "name": "pu", - "line": 891, - "self_ms": 0.12 - }, - { - "source": "../../../src/components/Navbar.tsx", - "name": "Ld", - "line": 341, - "self_ms": 0.12 - }, - { - "source": "../../../src/ui/Button.tsx", - "name": "R", - "line": 96, - "self_ms": 0.12 - }, - { - "source": "../../../src/components/ds/ui/index.tsx", - "name": "", - "line": 203, - "self_ms": 0.12 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+markdown@1.0.0_octane@0.1.13_react-dom@19.2.3_react@19.2.3__react@19.2.3_vite_be296f75eff2a49ec73fb9e97ef8d921/node_modules/@tanstack/markdown/dist/parser.js", - "name": "Ae", - "line": 4, - "self_ms": 0.11 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+highlight@1.0.0/node_modules/@tanstack/highlight/dist/internal/patterns.js", - "name": "_", - "line": 4, - "self_ms": 0.11 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+router-core@1.171.34/node_modules/@tanstack/router-core/dist/esm/router.js", - "name": "s", - "line": 251, - "self_ms": 0.11 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+markdown@1.0.0_octane@0.1.13_react-dom@19.2.3_react@19.2.3__react@19.2.3_vite_be296f75eff2a49ec73fb9e97ef8d921/node_modules/@tanstack/markdown/dist/parser.js", - "name": "i", - "line": 85, - "self_ms": 0.08 - }, - { - "source": "../../../src/components/Dropdown.tsx", - "name": "k", - "line": 53, - "self_ms": 0.07 - }, - { - "source": "../../../src/utils/markdown/processor.ts", - "name": "H", - "line": 201, - "self_ms": 0.06 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+redact@0.1.4_vite@8.0.16_@types+node@25.5.0_esbuild@0.27.4_jiti@2.7.0_tsx@4.21.0_yaml@2.9.0_/node_modules/@tanstack/redact/dist/server/walk.js", - "name": "mi", - "line": 57, - "self_ms": 0.06 - }, - { - "source": "../../../src/utils/markdown/live-example.ts", - "name": "g", - "line": 33, - "self_ms": 0.05 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+markdown@1.0.0_octane@0.1.13_react-dom@19.2.3_react@19.2.3__react@19.2.3_vite_be296f75eff2a49ec73fb9e97ef8d921/node_modules/@tanstack/markdown/dist/inline.js", - "name": "g", - "line": 31, - "self_ms": 0.05 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+markdown@1.0.0_octane@0.1.13_react-dom@19.2.3_react@19.2.3__react@19.2.3_vite_be296f75eff2a49ec73fb9e97ef8d921/node_modules/@tanstack/markdown/dist/extensions/docs.js", - "name": "Y", - "line": 18, - "self_ms": 0.05 - }, - { - "source": "../../../src/utils/partner-placement.ts", - "name": "", - "line": 181, - "self_ms": 0.04 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+router-core@1.171.34/node_modules/@tanstack/router-core/dist/esm/new-process-route-tree.js", - "name": "Ht", - "line": 45, - "self_ms": 0.04 - }, - { - "source": "../../../node_modules/.pnpm/seroval@1.6.7/node_modules/seroval/dist/index.js", - "name": "Fr", - "line": 400, - "self_ms": 0.03 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+router-core@1.171.34/node_modules/@tanstack/router-core/dist/esm/utils.js", - "name": "Nc", - "line": 292, - "self_ms": 0.02 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+redact@0.1.4_vite@8.0.16_@types+node@25.5.0_esbuild@0.27.4_jiti@2.7.0_tsx@4.21.0_yaml@2.9.0_/node_modules/@tanstack/redact/dist/server/walk.js", - "name": "a", - "line": 304, - "self_ms": 0.02 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+highlight@1.0.0/node_modules/@tanstack/highlight/dist/core.js", - "name": "E", - "line": 193, - "self_ms": 0.02 - }, - { - "source": "../../../node_modules/.pnpm/seroval@1.6.7/node_modules/seroval/dist/index.js", - "name": "Hn", - "line": 2449, - "self_ms": 0.01 - }, - { - "source": "../../../node_modules/.pnpm/seroval@1.6.7/node_modules/seroval/dist/index.js", - "name": "Wr", - "line": 2478, - "self_ms": 0.01 - } - ], - "sources": [ - { - "source": "runtime", - "self_ms": 7.75 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+query-core@5.102.8/node_modules/@tanstack/query-core/build/modern/subscribable.js", - "self_ms": 2.89 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+redact@0.1.4_vite@8.0.16_@types+node@25.5.0_esbuild@0.27.4_jiti@2.7.0_tsx@4.21.0_yaml@2.9.0_/node_modules/@tanstack/redact/dist/server/walk.js", - "self_ms": 1.86 - }, - { - "source": "../../../node_modules/.pnpm/seroval@1.6.7/node_modules/seroval/dist/index.js", - "self_ms": 1.62 - }, - { - "source": "../../../src/utils/github-content-cache.server.ts", - "self_ms": 1.43 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+markdown@1.0.0_octane@0.1.13_react-dom@19.2.3_react@19.2.3__react@19.2.3_vite_be296f75eff2a49ec73fb9e97ef8d921/node_modules/@tanstack/markdown/dist/parser.js", - "self_ms": 0.96 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+redact@0.1.4_vite@8.0.16_@types+node@25.5.0_esbuild@0.27.4_jiti@2.7.0_tsx@4.21.0_yaml@2.9.0_/node_modules/@tanstack/redact/dist/server/stream.js", - "self_ms": 0.64 - }, - { - "source": "../../../node_modules/.pnpm/parse5@7.3.0/node_modules/parse5/dist/tokenizer/index.js", - "self_ms": 0.64 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+start-client-core@1.170.34/node_modules/@tanstack/start-client-core/dist/esm/createServerFn.js", - "self_ms": 0.51 - }, - { - "source": "../../../src/utils/markdown/processor.ts", - "self_ms": 0.45 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+router-core@1.171.34/node_modules/@tanstack/router-core/dist/esm/ssr/htmlBoundaryScanner.js", - "self_ms": 0.39 - }, - { - "source": "../../../src/utils/docsNavTabs.ts", - "self_ms": 0.37 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+router-core@1.171.34/node_modules/@tanstack/router-core/dist/esm/router.js", - "self_ms": 0.36 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+markdown@1.0.0_octane@0.1.13_react-dom@19.2.3_react@19.2.3__react@19.2.3_vite_be296f75eff2a49ec73fb9e97ef8d921/node_modules/@tanstack/markdown/dist/inline.js", - "self_ms": 0.36 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+highlight@1.0.0/node_modules/@tanstack/highlight/dist/internal/script.js", - "self_ms": 0.34 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+react-router@1.170.41_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@tanstack/react-router/dist/esm/link.js", - "self_ms": 0.26 - }, - { - "source": "../../src/server.ts", - "self_ms": 0.26 - }, - { - "source": "../../../node_modules/.pnpm/parse5@7.3.0/node_modules/parse5/dist/parser/index.js", - "self_ms": 0.26 - }, - { - "source": "../../../src/utils/request-timing.server.ts", - "self_ms": 0.26 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+router-core@1.171.34/node_modules/@tanstack/router-core/dist/esm/path.js", - "self_ms": 0.26 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+markdown@1.0.0_octane@0.1.13_react-dom@19.2.3_react@19.2.3__react@19.2.3_vite_be296f75eff2a49ec73fb9e97ef8d921/node_modules/@tanstack/markdown/dist/react.js", - "self_ms": 0.18 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+query-core@5.102.8/node_modules/@tanstack/query-core/build/modern/queryObserver.js", - "self_ms": 0.16 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+highlight@1.0.0/node_modules/@tanstack/highlight/dist/core.js", - "self_ms": 0.15 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+router-core@1.171.34/node_modules/@tanstack/router-core/dist/esm/utils.js", - "self_ms": 0.15 - }, - { - "source": "../../../src/utils/repo-path.ts", - "self_ms": 0.14 - }, - { - "source": "../../../node_modules/.pnpm/@radix-ui+react-slot@1.2.3_@types+react@19.2.14_react@19.2.3/node_modules/@radix-ui/react-slot/dist/index.mjs", - "self_ms": 0.14 - }, - { - "source": "../../../node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/browser/dist/parse/parser.js", - "self_ms": 0.14 - }, - { - "source": "../../../src/components/library-layout-navigation.ts", - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@phosphor-icons+react@2.1.10_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@phosphor-icons/react/dist/csr/ArrowLeft.es.js", - "self_ms": 0.13 - }, - { - "source": "../../../src/routes/_library/$libraryId/$version.docs.$.tsx", - "self_ms": 0.13 - }, - { - "source": "../../src/utils/prod-diagnostics.server.ts", - "self_ms": 0.13 - }, - { - "source": "../../../src/routes/__root.tsx", - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@radix-ui+react-context@1.1.2_@types+react@19.2.14_react@19.2.3/node_modules/@radix-ui/react-context/dist/index.mjs", - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+redact@0.1.4_vite@8.0.16_@types+node@25.5.0_esbuild@0.27.4_jiti@2.7.0_tsx@4.21.0_yaml@2.9.0_/node_modules/@tanstack/redact/dist/core/attributes.js", - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/parse5@7.3.0/node_modules/parse5/dist/index.js", - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+react-router@1.170.41_react-dom@19.2.3_react@19.2.3__react@19.2.3/node_modules/@tanstack/react-router/dist/esm/headContentUtils.js", - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+router-ssr-query-core@1.169.2_@tanstack+query-core@5.102.8_@tanstack+router-core@1.171.34/node_modules/@tanstack/router-ssr-query-core/dist/esm/index.js", - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+router-core@1.171.34/node_modules/@tanstack/router-core/dist/esm/ssr/headers.js", - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+router-core@1.171.34/node_modules/@tanstack/router-core/dist/esm/load-server.js", - "self_ms": 0.13 - }, - { - "source": "../../../node_modules/.pnpm/@radix-ui+react-tooltip@1.2.8_@types+react-dom@19.2.3_@types+react@19.2.14__@types+reac_f164644780a8f95ec4733d733b3b08bc/node_modules/@radix-ui/react-tooltip/dist/index.mjs", - "self_ms": 0.13 - }, - { - "source": "../../../src/utils/docs.functions.ts?tss-serverfn-split", - "self_ms": 0.12 - }, - { - "source": "../../../src/components/Navbar.tsx", - "self_ms": 0.12 - }, - { - "source": "../../../src/ui/Button.tsx", - "self_ms": 0.12 - }, - { - "source": "../../../src/components/ds/ui/index.tsx", - "self_ms": 0.12 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+highlight@1.0.0/node_modules/@tanstack/highlight/dist/internal/patterns.js", - "self_ms": 0.11 - }, - { - "source": "../../../src/components/Dropdown.tsx", - "self_ms": 0.07 - }, - { - "source": "../../../src/utils/markdown/live-example.ts", - "self_ms": 0.05 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+markdown@1.0.0_octane@0.1.13_react-dom@19.2.3_react@19.2.3__react@19.2.3_vite_be296f75eff2a49ec73fb9e97ef8d921/node_modules/@tanstack/markdown/dist/extensions/docs.js", - "self_ms": 0.05 - }, - { - "source": "../../../src/utils/partner-placement.ts", - "self_ms": 0.04 - }, - { - "source": "../../../node_modules/.pnpm/@tanstack+router-core@1.171.34/node_modules/@tanstack/router-core/dist/esm/new-process-route-tree.js", - "self_ms": 0.04 - } - ] - } - }, - "cleanup": [ - { - "worker": "tanstack-cold-probe-minimal", - "exit_code": 0, - "deleted": true - }, - { - "worker": "tanstack-cold-probe-tiny", - "exit_code": 0, - "deleted": true - }, - { - "worker": "tanstack-cold-probe-full", - "exit_code": 0, - "deleted": true - }, - { - "worker": "tanstack-cold-probe-data", - "exit_code": 0, - "deleted": true - }, - { - "worker": "tanstack-cold-probe-no-wasm", - "exit_code": 0, - "deleted": true - }, - { - "worker": "tanstack-cold-probe-single-js", - "exit_code": 0, - "deleted": true - }, - { - "worker": "tanstack-cold-probe-many-js", - "exit_code": 0, - "deleted": true - }, - { - "worker": "tanstack-cold-probe-monolith", - "exit_code": 0, - "deleted": true - } - ], - "production_version_after_experiment": "3b554871-c23c-4825-9bb4-f9bc27dc5466" -} diff --git a/docs/worker-cold-start-probes/README.md b/docs/worker-cold-start-probes/README.md deleted file mode 100644 index 7ec68c598..000000000 --- a/docs/worker-cold-start-probes/README.md +++ /dev/null @@ -1,20 +0,0 @@ -# Archived diagnostic templates - -These files document the experiment. They are not application code or a proposed deployment. In particular, the empty-WASM control cannot generate OG images, and the rebundle did not solve the cold delay. - -- `probe.js.txt` is the standalone minimal handler. `/noop` performs no I/O. `/cache` performs a Cache API miss, and `/r2` performs a read-only HEAD miss. -- `measure.py.txt` records curl timing, response instance/counter headers, and ray IDs. Its optional arguments select a path and request count. The hostnames in the file refer to temporary Workers that have been deleted. -- `rebundle.mjs.txt` records the esbuild experiment. It expects the original full-probe files/configuration prepared in `dist/server`; it is not a standalone project build command. - -The complete Worker upload was tested by placing the minimal handler beside the site's built `index.js` and `assets` modules, with the same ESModule/CompiledWasm discovery rules. Merely sharing that upload was enough to reproduce the delay, without importing the application. The full-app variant added a static import of built `index.js` and forwarded `/docs` to the actual docs URL. - -The synthetic variants used the same minimal handler and binding configuration: - -1. Data: concatenate built `index.js` and the server asset JavaScript into one file, uploaded with a Data rule. -2. Single JS: encode the same text as `export default ` in one extra ESModule. -3. Many JS: split that text into 1,000 slices, each exported as a JSON string in an ESModule. -4. Empty WASM: retain the site's JavaScript modules, replace its original compiled WASM with the eight-byte empty WASM module, and only exercise `/noop`. - -Each config used the same account, compatibility date/flags, and read-only diagnostic paths. Only `GITHUB_CONTENT_CACHE` was bound, with no database, application secrets, Durable Object namespaces, or scheduled tasks. Full-app and rebundled probes also retained the production static assets binding. All probes enabled native tracing and logs. Production routes were never attached. - -Join request records to Wrangler tail output by `cf-ray`. Exclude non-200 responses from latency summaries while retaining them in the raw dataset. Separate first observed instance requests from reused instances. Report connection setup independently, and do not sum application spans that overlap or depend on Worker I/O clocks. diff --git a/docs/worker-cold-start-probes/measure.py.txt b/docs/worker-cold-start-probes/measure.py.txt deleted file mode 100644 index 787524803..000000000 --- a/docs/worker-cold-start-probes/measure.py.txt +++ /dev/null @@ -1,16 +0,0 @@ -import subprocess,json,sys,time -from pathlib import Path -name=sys.argv[1];run=sys.argv[2] if len(sys.argv)>2 else 'initial' -rows=[] -paths=['/noop']*8+['/cache']*3+['/r2']*3 -if name not in ['tiny','minimal']:paths+=['/docs']*5+['/noop']*2 -if len(sys.argv)>3: paths=[sys.argv[3]]*int(sys.argv[4]) -for i,path in enumerate(paths): - out=Path(f'/tmp/docs-cold-{name}-{run}-{i}.headers') - p=subprocess.run(['curl','-sS','--max-time','30','-H','Accept: text/html','-D',str(out),'-o',f'/tmp/docs-cold-{name}-{run}-{i}.body','-w','%{json}',f'https://tanstack-cold-probe-{name}.thetanstack.workers.dev{path}'],capture_output=True,text=True) - if p.returncode:print('curl error',p.stderr,flush=True);continue - m=json.loads(p.stdout);h={} - for line in out.read_text().splitlines(): - if ':' in line:k,v=line.split(':',1);h[k.lower()]=v.strip() - row={'worker':name,'run':run,'path':path,'status':m['http_code'],'ttfb_ms':round(m['time_starttransfer']*1000,1),'total_ms':round(m['time_total']*1000,1),'tls_ms':round(m['time_appconnect']*1000,1),'after_connection_ms':round((m['time_starttransfer']-m['time_pretransfer'])*1000,1),'ray':h.get('cf-ray'),'instance':h.get('x-probe-instance'),'instance_request':h.get('x-probe-request'),'phase_ms':h.get('x-probe-phase-ms'),'server_timing':h.get('server-timing')} - rows.append(row);print(json.dumps(row),flush=True);Path(f'/tmp/docs-cold-{name}-{run}-measurements.json').write_text(json.dumps(rows,indent=2)+'\n');time.sleep(.5) diff --git a/docs/worker-cold-start-probes/probe.js.txt b/docs/worker-cold-start-probes/probe.js.txt deleted file mode 100644 index 22587630d..000000000 --- a/docs/worker-cold-start-probes/probe.js.txt +++ /dev/null @@ -1,34 +0,0 @@ -let instance -let requests = 0 -export default { - async fetch(request, env, ctx) { - instance ??= crypto.randomUUID() - const count = ++requests - const started = performance.now() - const path = new URL(request.url).pathname - let response - let phaseMs = 0 - if (path === '/cache') { - const t = performance.now() - await caches.default.match('https://blob-storage-cache.tanstack.internal/diagnostic-missing-key') - phaseMs = performance.now() - t - response = new Response('cache read complete') - } else if (path === '/r2') { - const t = performance.now() - await env.GITHUB_CONTENT_CACHE.head('diagnostic-missing-key') - phaseMs = performance.now() - t - response = new Response('r2 read complete') - } else if (path === '/docs') { - response = new Response('not supported', {status:404}) - } else { - response = new Response('ok') - } - const headers = new Headers(response.headers) - headers.set('Cache-Control', 'private, no-store') - headers.set('X-Probe-Instance', instance) - headers.set('X-Probe-Request', String(count)) - headers.set('X-Probe-Phase-Ms', String(phaseMs)) - console.log(JSON.stringify({logType:'docs_cold_probe',instance,count,path,ray:request.headers.get('cf-ray'),phaseMs,headersMs:performance.now()-started})) - return new Response(response.body, {status:response.status,headers}) - } -} diff --git a/docs/worker-cold-start-probes/rebundle.mjs.txt b/docs/worker-cold-start-probes/rebundle.mjs.txt deleted file mode 100644 index f0fbe265e..000000000 --- a/docs/worker-cold-start-probes/rebundle.mjs.txt +++ /dev/null @@ -1,11 +0,0 @@ -import { createRequire } from 'node:module' -import {mkdir,readFile,writeFile,copyFile} from 'node:fs/promises' -import path from 'node:path' -const require=createRequire(process.cwd()+'/package.json') -const {build}=require('esbuild') -const out='/tmp/docs-cold-monolith' -await mkdir(out,{recursive:true}) -const result=await build({entryPoints:[path.resolve('dist/server/index.js')],outfile:out+'/app.js',bundle:true,format:'esm',platform:'node',ignoreAnnotations:true,treeShaking:false,logLevel:'silent',target:'es2022',minify:true,metafile:true,external:['cloudflare:workers','node:*'],plugins:[{name:'preserve-cloudflare-wasm',setup(build){build.onResolve({filter:/\.wasm$/},async args=>{const source=path.resolve(args.resolveDir,args.path);const basename=path.basename(source);await copyFile(source,out+'/'+basename);return {path:'./'+basename,external:true}})}}]}) -await writeFile(out+'/metafile.json',JSON.stringify(result.metafile)) -let probe=await readFile('dist/server/cold-probe-full.js','utf8');probe=probe.replace("import app from './index.js'","import app from './app.js'");await writeFile(out+'/index.js',probe) -const cfg=JSON.parse(await readFile('dist/server/cold-probe-full.wrangler.json','utf8'));cfg.name='tanstack-cold-probe-monolith';cfg.main='index.js';cfg.find_additional_modules=true;cfg.assets.directory=path.resolve('dist/client');await writeFile(out+'/wrangler.json',JSON.stringify(cfg));console.log(JSON.stringify({outputs:Object.entries(result.metafile.outputs).map(([name,value])=>({name,bytes:value.bytes})),inputModules:Object.keys(result.metafile.inputs).length})) diff --git a/docs/worker-deployment-boundaries.md b/docs/worker-deployment-boundaries.md deleted file mode 100644 index 7abeac91e..000000000 --- a/docs/worker-deployment-boundaries.md +++ /dev/null @@ -1,84 +0,0 @@ -# Worker deployment boundaries - -The browser still uses one TanStack Start app and its existing route tree. One -Vite build produces four independent Cloudflare Worker uploads: - -| Output | Worker | Owns | -| -------------- | ------------------ | ------------------------------------------------------------------------------------- | -| `dist/server` | `tanstack-com` | Pages, docs, assets, auth, Start server functions, site cron tasks | -| `dist/og` | `tanstack-og` | OG and README image generation, including Takumi WASM | -| `dist/chat` | `tanstack-chat` | Chat HTTP handlers, model execution, Durable Objects, chat workflow and sync recovery | -| `dist/starter` | `tanstack-starter` | Project generation, embedded templates, starter API and GitHub deployment | - -Public URLs stay the same. The Start API routes forward the original Request -through service bindings, preserving cookies, origin, query parameters, bodies -and streamed responses. Each backend retains its existing authentication, -authorization, same-origin and rate-limit checks. Auxiliary Workers have no -public routes or workers.dev endpoints. - -Implementation files stay with their features. Thin backend HTTP adapters live -under `src/chat/server/http` and `src/application-starter/api/http`. Their route -tables put specific paths before parameters and splats. `worker-boundaries.test.ts` -checks that their paths and methods match the public Start API routes. - -The chat app, shared project workbenches, charts builder and icon browser use -Start's `createClientOnlyFn` around their lazy component imports. `ClientOnly` -alone does not remove a dependency from the server upload. - -The production build checks both eager chat imports and every uploaded site -module, including lazy chunks. It fails if the extracted heavy implementations -return to the site upload. Six small provider templates remain with the site's -existing example deployment API. - -## Development - -`pnpm dev:cloudflare` starts the app and its auxiliary Workers together, using -local service bindings. The existing root `.env.local` is loaded by `with-env`. -The child configs declare their required secrets so Wrangler also reads them -from the inherited process environment. Hyperdrive is disabled in development, -as in the existing site config, and the local database URL is inherited from -`with-env`. - -For a production build preview with local credentials, use: - -```sh -pnpm build:cloudflare -pnpm with-env vite preview -``` - -## Deployment - -```sh -pnpm build:cloudflare -pnpm deploy:cloudflare:workers -``` - -The deployment command publishes OG, starter, chat, then the site. It preserves -existing remote variables and secrets. It does not run database migrations or -purge the CDN. The existing broader deployment commands still perform their -existing database preparation and cache purge steps. - -Provision the child Workers' declared secrets before routing production -requests to them. Never put secret values in Wrangler configs or Git. - -The first rollout prepares the chat Worker's three SQLite namespaces with -`expecting-transfer` declarations and bindings to the existing source namespaces. -The site then commits the transfers with `transferred` declarations. The chat -Worker activates its own bindings and takes ownership of the existing workflow. -Finally, the site removes the completed transfer declarations. The deployment -script detects this first rollout through the existing workflow's owner and -performs the stages in order. It checks required child secrets before starting. - -Subsequent deployments publish the chat Worker before the site. The chat config -uses explicit SQLite exports, so local development also gets SQLite storage. -Never use `new_sqlite_classes` or create fresh production namespaces for the -existing conversations. - -The chat Worker owns workspace-sync recovery; the site keeps its other cron -work. The site no longer exports chat classes or owns Cloudflare workflow -bindings. A disposable Cloudflare test verifies namespace and workflow -continuity through this same rollout, including requests between stages. - -A rollback after transferring namespaces must retain the new namespace owner -and cross-script bindings, or explicitly transfer those namespaces back. Simply -deploying the old monolithic config is not a complete rollback plan. diff --git a/docs/worker-split-measurements.json b/docs/worker-split-measurements.json deleted file mode 100644 index 0ee4c8244..000000000 --- a/docs/worker-split-measurements.json +++ /dev/null @@ -1,1714 +0,0 @@ -{ - "measured_at_utc": "2026-10-15", - "method": "Interleaved requests, separate curl connection per request, alternating order, 250ms gap. Identical minimal handler with original versus reduced site modules uploaded but never imported. No credentials, database, storage or service bindings. First observed instance is identified by X-Probe-Request: 1, it does not prove every Cloudflare platform cache was cold. After-connection time subtracts time_pretransfer from time_starttransfer and still includes network round-trip time. These measurements isolate Worker payload preparation, they are not production documentation TTFB measurements.", - "summary": { - "before": { - "requests": 40, - "successes": 40, - "first_observed_instance_requests": 12, - "first_observed_instance_median_after_connection_ms": 1048.05, - "reused_instance_requests": 28, - "reused_instance_median_after_connection_ms": 67.65 - }, - "after": { - "requests": 40, - "successes": 40, - "first_observed_instance_requests": 13, - "first_observed_instance_median_after_connection_ms": 471.6, - "reused_instance_requests": 27, - "reused_instance_median_after_connection_ms": 65.2 - } - }, - "probes": { - "before": { - "worker": "tanstack-split-payload-before", - "version": "e0ac12ea-a3a0-49db-9d71-d7aa59319892", - "upload_kib": 26260.77, - "gzip_kib": 8459.71 - }, - "after": { - "worker": "tanstack-split-payload-after", - "version": "65404bd3-081c-46ef-b0e6-195d8ef8f2f1", - "upload_kib": 10935.11, - "gzip_kib": 3158.83 - } - }, - "measurements": [ - { - "variant": "before", - "index": 0, - "status": 200, - "ttfb_ms": 1419.0, - "after_connection_ms": 1293.6, - "instance": "8f5ee7bc-c49e-4605-b581-f82a061261f7", - "instance_request": "1", - "ray": "a4b27b2038604b91-DFW" - }, - { - "variant": "after", - "index": 0, - "status": 200, - "ttfb_ms": 977.1, - "after_connection_ms": 849.1, - "instance": "d57c1d58-33e2-41de-a518-556e5fae8243", - "instance_request": "1", - "ray": "a4b27b2ab96b143d-DFW" - }, - { - "variant": "after", - "index": 1, - "status": 200, - "ttfb_ms": 461.8, - "after_connection_ms": 382.1, - "instance": "8718ccd8-496d-45a1-99e4-8eac1cdb135a", - "instance_request": "1", - "ray": "a4b27b32386f4918-DFW" - }, - { - "variant": "before", - "index": 1, - "status": 200, - "ttfb_ms": 1001.5, - "after_connection_ms": 923.7, - "instance": "05101b85-77bf-4c50-b689-ac993edd792d", - "instance_request": "1", - "ray": "a4b27b36bd742c1e-DFW" - }, - { - "variant": "before", - "index": 2, - "status": 200, - "ttfb_ms": 829.6, - "after_connection_ms": 750.3, - "instance": "32d16e77-1d91-44cb-97c5-5df22e6e9578", - "instance_request": "1", - "ray": "a4b27b3eacc269dc-DFW" - }, - { - "variant": "after", - "index": 2, - "status": 200, - "ttfb_ms": 812.6, - "after_connection_ms": 727.4, - "instance": "5f4301a6-1e2b-4020-894b-cf66c982f69c", - "instance_request": "1", - "ray": "a4b27b459ee947a5-DFW" - }, - { - "variant": "after", - "index": 3, - "status": 200, - "ttfb_ms": 484.8, - "after_connection_ms": 403.9, - "instance": "943b718d-2f8c-43b4-9c16-1235c0f2d4c1", - "instance_request": "1", - "ray": "a4b27b4c5ec611de-DFW" - }, - { - "variant": "before", - "index": 3, - "status": 200, - "ttfb_ms": 2800.6, - "after_connection_ms": 2714.3, - "instance": "9c5ded07-e4d6-4de2-b8b7-e65b114f30cc", - "instance_request": "1", - "ray": "a4b27b511fbceac9-DFW" - }, - { - "variant": "before", - "index": 4, - "status": 200, - "ttfb_ms": 139.1, - "after_connection_ms": 58.7, - "instance": "05101b85-77bf-4c50-b689-ac993edd792d", - "instance_request": "2", - "ray": "a4b27b643a89159f-DFW" - }, - { - "variant": "after", - "index": 4, - "status": 200, - "ttfb_ms": 549.5, - "after_connection_ms": 471.6, - "instance": "49eeb249-7c5f-48e9-9530-d99a10bbfff9", - "instance_request": "1", - "ray": "a4b27b66c9c993ac-DFW" - }, - { - "variant": "after", - "index": 5, - "status": 200, - "ttfb_ms": 514.4, - "after_connection_ms": 436.8, - "instance": "124075ac-8a23-4729-af2f-1e0263b93caf", - "instance_request": "1", - "ray": "a4b27b6bd8056781-DFW" - }, - { - "variant": "before", - "index": 5, - "status": 200, - "ttfb_ms": 150.9, - "after_connection_ms": 71.3, - "instance": "32d16e77-1d91-44cb-97c5-5df22e6e9578", - "instance_request": "2", - "ray": "a4b27b70bf7666ef-DFW" - }, - { - "variant": "before", - "index": 6, - "status": 200, - "ttfb_ms": 139.8, - "after_connection_ms": 61.1, - "instance": "8f5ee7bc-c49e-4605-b581-f82a061261f7", - "instance_request": "2", - "ray": "a4b27b7349044aa7-DFW" - }, - { - "variant": "after", - "index": 6, - "status": 200, - "ttfb_ms": 136.9, - "after_connection_ms": 60.4, - "instance": "8718ccd8-496d-45a1-99e4-8eac1cdb135a", - "instance_request": "2", - "ray": "a4b27b75cf5aebf6-DFW" - }, - { - "variant": "after", - "index": 7, - "status": 200, - "ttfb_ms": 140.6, - "after_connection_ms": 62.0, - "instance": "49eeb249-7c5f-48e9-9530-d99a10bbfff9", - "instance_request": "2", - "ray": "a4b27b784f69a915-DFW" - }, - { - "variant": "before", - "index": 7, - "status": 200, - "ttfb_ms": 152.1, - "after_connection_ms": 67.6, - "instance": "05101b85-77bf-4c50-b689-ac993edd792d", - "instance_request": "3", - "ray": "a4b27b7ade53b1ee-DFW" - }, - { - "variant": "before", - "index": 8, - "status": 200, - "ttfb_ms": 1356.4, - "after_connection_ms": 1274.9, - "instance": "e44ed419-558d-408a-910a-50715e5fd4f7", - "instance_request": "1", - "ray": "a4b27b7d6c7a6b22-DFW" - }, - { - "variant": "after", - "index": 8, - "status": 200, - "ttfb_ms": 191.5, - "after_connection_ms": 97.9, - "instance": "943b718d-2f8c-43b4-9c16-1235c0f2d4c1", - "instance_request": "2", - "ray": "a4b27b87aea1e76e-DFW" - }, - { - "variant": "after", - "index": 9, - "status": 200, - "ttfb_ms": 836.2, - "after_connection_ms": 701.5, - "instance": "b5ea49ab-6728-4bae-93e7-2812be869350", - "instance_request": "1", - "ray": "a4b27b8abbb16bb9-DFW" - }, - { - "variant": "before", - "index": 9, - "status": 200, - "ttfb_ms": 786.7, - "after_connection_ms": 708.6, - "instance": "79fb3f8f-7b0c-48ed-b62c-f36e1a851526", - "instance_request": "1", - "ray": "a4b27b913bdda619-DFW" - }, - { - "variant": "before", - "index": 10, - "status": 200, - "ttfb_ms": 157.8, - "after_connection_ms": 76.1, - "instance": "79fb3f8f-7b0c-48ed-b62c-f36e1a851526", - "instance_request": "2", - "ray": "a4b27b97d8bc5618-DFW" - }, - { - "variant": "after", - "index": 10, - "status": 200, - "ttfb_ms": 514.2, - "after_connection_ms": 430.9, - "instance": "0379d764-7ec6-4e2e-bc20-f6e9ab8f8a55", - "instance_request": "1", - "ray": "a4b27b9a7d2de5de-DFW" - }, - { - "variant": "after", - "index": 11, - "status": 200, - "ttfb_ms": 124.9, - "after_connection_ms": 45.1, - "instance": "49eeb249-7c5f-48e9-9530-d99a10bbfff9", - "instance_request": "3", - "ray": "a4b27b9f4b32a922-DFW" - }, - { - "variant": "before", - "index": 11, - "status": 200, - "ttfb_ms": 1517.3, - "after_connection_ms": 1435.4, - "instance": "4109a8f4-0e7d-4c83-bc70-3793a8d00162", - "instance_request": "1", - "ray": "a4b27ba1c9f946e6-DFW" - }, - { - "variant": "before", - "index": 12, - "status": 200, - "ttfb_ms": 916.2, - "after_connection_ms": 833.4, - "instance": "d38c1d5d-db05-4e65-9ce7-4101daa5a52f", - "instance_request": "1", - "ray": "a4b27baceee7f05e-DFW" - }, - { - "variant": "after", - "index": 12, - "status": 200, - "ttfb_ms": 139.6, - "after_connection_ms": 60.2, - "instance": "8718ccd8-496d-45a1-99e4-8eac1cdb135a", - "instance_request": "3", - "ray": "a4b27bb439655549-DFW" - }, - { - "variant": "after", - "index": 13, - "status": 200, - "ttfb_ms": 143.4, - "after_connection_ms": 65.0, - "instance": "49eeb249-7c5f-48e9-9530-d99a10bbfff9", - "instance_request": "4", - "ray": "a4b27bb6cfea3797-DFW" - }, - { - "variant": "before", - "index": 13, - "status": 200, - "ttfb_ms": 146.1, - "after_connection_ms": 64.1, - "instance": "8f5ee7bc-c49e-4605-b581-f82a061261f7", - "instance_request": "3", - "ray": "a4b27bb95824e912-DFW" - }, - { - "variant": "before", - "index": 14, - "status": 200, - "ttfb_ms": 123.5, - "after_connection_ms": 46.4, - "instance": "32d16e77-1d91-44cb-97c5-5df22e6e9578", - "instance_request": "3", - "ray": "a4b27bbbf90066f5-DFW" - }, - { - "variant": "after", - "index": 14, - "status": 200, - "ttfb_ms": 143.5, - "after_connection_ms": 64.1, - "instance": "124075ac-8a23-4729-af2f-1e0263b93caf", - "instance_request": "2", - "ray": "a4b27bbe7f816a03-DFW" - }, - { - "variant": "after", - "index": 15, - "status": 200, - "ttfb_ms": 559.5, - "after_connection_ms": 483.0, - "instance": "55b75676-4c05-4329-af21-947c76bccaf4", - "instance_request": "1", - "ray": "a4b27bc0ff751021-DFW" - }, - { - "variant": "before", - "index": 15, - "status": 200, - "ttfb_ms": 159.2, - "after_connection_ms": 81.0, - "instance": "4109a8f4-0e7d-4c83-bc70-3793a8d00162", - "instance_request": "2", - "ray": "a4b27bc61c9a4671-DFW" - }, - { - "variant": "before", - "index": 16, - "status": 200, - "ttfb_ms": 1176.1, - "after_connection_ms": 1097.0, - "instance": "ea854113-4e85-42d2-b99b-9ad3fa2d683a", - "instance_request": "1", - "ray": "a4b27bc8cdea638a-DFW" - }, - { - "variant": "after", - "index": 16, - "status": 200, - "ttfb_ms": 455.1, - "after_connection_ms": 374.0, - "instance": "e7f9fddf-501e-4a61-b5b4-62154dc89a56", - "instance_request": "1", - "ray": "a4b27bd1c99a1db5-DFW" - }, - { - "variant": "after", - "index": 17, - "status": 200, - "ttfb_ms": 151.0, - "after_connection_ms": 68.2, - "instance": "124075ac-8a23-4729-af2f-1e0263b93caf", - "instance_request": "3", - "ray": "a4b27bd64fc769bf-DFW" - }, - { - "variant": "before", - "index": 17, - "status": 200, - "ttfb_ms": 1474.1, - "after_connection_ms": 1394.6, - "instance": "4e815e29-0e99-438c-9b56-33f345941695", - "instance_request": "1", - "ray": "a4b27bd8d99c72ff-DFW" - }, - { - "variant": "before", - "index": 18, - "status": 200, - "ttfb_ms": 143.1, - "after_connection_ms": 60.7, - "instance": "d38c1d5d-db05-4e65-9ce7-4101daa5a52f", - "instance_request": "2", - "ray": "a4b27be3c947f0b2-DFW" - }, - { - "variant": "after", - "index": 18, - "status": 200, - "ttfb_ms": 240.3, - "after_connection_ms": 62.0, - "instance": "e7f9fddf-501e-4a61-b5b4-62154dc89a56", - "instance_request": "2", - "ray": "a4b27be6e9f309ac-DFW" - }, - { - "variant": "after", - "index": 19, - "status": 200, - "ttfb_ms": 180.3, - "after_connection_ms": 95.0, - "instance": "e7f9fddf-501e-4a61-b5b4-62154dc89a56", - "instance_request": "3", - "ray": "a4b27be97c365607-DFW" - }, - { - "variant": "before", - "index": 19, - "status": 200, - "ttfb_ms": 205.5, - "after_connection_ms": 67.5, - "instance": "ea854113-4e85-42d2-b99b-9ad3fa2d683a", - "instance_request": "2", - "ray": "a4b27bec8cbe2562-DFW" - }, - { - "variant": "before", - "index": 20, - "status": 200, - "ttfb_ms": 161.7, - "after_connection_ms": 62.6, - "instance": "8f5ee7bc-c49e-4605-b581-f82a061261f7", - "instance_request": "4", - "ray": "a4b27bef5d0c168b-DFW" - }, - { - "variant": "after", - "index": 20, - "status": 200, - "ttfb_ms": 170.6, - "after_connection_ms": 87.6, - "instance": "5f4301a6-1e2b-4020-894b-cf66c982f69c", - "instance_request": "2", - "ray": "a4b27bf1ec524684-DFW" - }, - { - "variant": "after", - "index": 21, - "status": 200, - "ttfb_ms": 263.5, - "after_connection_ms": 153.3, - "instance": "5f4301a6-1e2b-4020-894b-cf66c982f69c", - "instance_request": "3", - "ray": "a4b27bf4cb794781-DFW" - }, - { - "variant": "before", - "index": 21, - "status": 200, - "ttfb_ms": 1133.5, - "after_connection_ms": 999.1, - "instance": "3ea78bbe-dc80-47f2-bbc5-35b748baa476", - "instance_request": "1", - "ray": "a4b27bf849f607b7-DFW" - }, - { - "variant": "before", - "index": 22, - "status": 200, - "ttfb_ms": 215.8, - "after_connection_ms": 78.9, - "instance": "4109a8f4-0e7d-4c83-bc70-3793a8d00162", - "instance_request": "3", - "ray": "a4b27c00fa9e4683-DFW" - }, - { - "variant": "after", - "index": 22, - "status": 200, - "ttfb_ms": 133.8, - "after_connection_ms": 55.9, - "instance": "e7f9fddf-501e-4a61-b5b4-62154dc89a56", - "instance_request": "4", - "ray": "a4b27c03aed0686c-DFW" - }, - { - "variant": "after", - "index": 23, - "status": 200, - "ttfb_ms": 966.2, - "after_connection_ms": 886.4, - "instance": "f4964a6c-7496-47e4-94ee-330ade7a557c", - "instance_request": "1", - "ray": "a4b27c062f5a3594-DFW" - }, - { - "variant": "before", - "index": 23, - "status": 200, - "ttfb_ms": 151.4, - "after_connection_ms": 71.1, - "instance": "3ea78bbe-dc80-47f2-bbc5-35b748baa476", - "instance_request": "2", - "ray": "a4b27c0ddf164fb7-DFW" - }, - { - "variant": "before", - "index": 24, - "status": 200, - "ttfb_ms": 177.4, - "after_connection_ms": 93.1, - "instance": "9c5ded07-e4d6-4de2-b8b7-e65b114f30cc", - "instance_request": "2", - "ray": "a4b27c107fcceac5-DFW" - }, - { - "variant": "after", - "index": 24, - "status": 200, - "ttfb_ms": 181.3, - "after_connection_ms": 93.3, - "instance": "b5ea49ab-6728-4bae-93e7-2812be869350", - "instance_request": "2", - "ray": "a4b27c134bf46b4b-DFW" - }, - { - "variant": "after", - "index": 25, - "status": 200, - "ttfb_ms": 125.1, - "after_connection_ms": 45.5, - "instance": "124075ac-8a23-4729-af2f-1e0263b93caf", - "instance_request": "4", - "ray": "a4b27c15f95f6fa8-DFW" - }, - { - "variant": "before", - "index": 25, - "status": 200, - "ttfb_ms": 142.7, - "after_connection_ms": 64.6, - "instance": "d38c1d5d-db05-4e65-9ce7-4101daa5a52f", - "instance_request": "3", - "ray": "a4b27c186820f05c-DFW" - }, - { - "variant": "before", - "index": 26, - "status": 200, - "ttfb_ms": 142.2, - "after_connection_ms": 62.9, - "instance": "4e815e29-0e99-438c-9b56-33f345941695", - "instance_request": "2", - "ray": "a4b27c1afb752d45-DFW" - }, - { - "variant": "after", - "index": 26, - "status": 200, - "ttfb_ms": 149.3, - "after_connection_ms": 68.9, - "instance": "55b75676-4c05-4329-af21-947c76bccaf4", - "instance_request": "2", - "ray": "a4b27c1d8a896e71-DFW" - }, - { - "variant": "after", - "index": 27, - "status": 200, - "ttfb_ms": 177.3, - "after_connection_ms": 93.3, - "instance": "b5ea49ab-6728-4bae-93e7-2812be869350", - "instance_request": "3", - "ray": "a4b27c201a936c5b-DFW" - }, - { - "variant": "before", - "index": 27, - "status": 200, - "ttfb_ms": 147.5, - "after_connection_ms": 68.6, - "instance": "4e815e29-0e99-438c-9b56-33f345941695", - "instance_request": "3", - "ray": "a4b27c22dd3687f4-DFW" - }, - { - "variant": "before", - "index": 28, - "status": 200, - "ttfb_ms": 150.1, - "after_connection_ms": 70.9, - "instance": "8f5ee7bc-c49e-4605-b581-f82a061261f7", - "instance_request": "5", - "ray": "a4b27c256ae44854-DFW" - }, - { - "variant": "after", - "index": 28, - "status": 200, - "ttfb_ms": 158.7, - "after_connection_ms": 81.0, - "instance": "49eeb249-7c5f-48e9-9530-d99a10bbfff9", - "instance_request": "5", - "ray": "a4b27c27fa1e5870-DFW" - }, - { - "variant": "after", - "index": 29, - "status": 200, - "ttfb_ms": 169.4, - "after_connection_ms": 91.7, - "instance": "5f4301a6-1e2b-4020-894b-cf66c982f69c", - "instance_request": "4", - "ray": "a4b27c2a9a17485b-DFW" - }, - { - "variant": "before", - "index": 29, - "status": 200, - "ttfb_ms": 147.1, - "after_connection_ms": 65.5, - "instance": "d38c1d5d-db05-4e65-9ce7-4101daa5a52f", - "instance_request": "4", - "ray": "a4b27c2d5d17f048-DFW" - }, - { - "variant": "before", - "index": 30, - "status": 200, - "ttfb_ms": 158.0, - "after_connection_ms": 73.6, - "instance": "8f5ee7bc-c49e-4605-b581-f82a061261f7", - "instance_request": "6", - "ray": "a4b27c2fe9c4e772-DFW" - }, - { - "variant": "after", - "index": 30, - "status": 200, - "ttfb_ms": 618.3, - "after_connection_ms": 536.5, - "instance": "d378afa9-b704-4745-a325-1442624b8f1f", - "instance_request": "1", - "ray": "a4b27c328a8cf044-DFW" - }, - { - "variant": "after", - "index": 31, - "status": 200, - "ttfb_ms": 495.9, - "after_connection_ms": 419.2, - "instance": "cebc9ba5-d1cd-4c85-b2cf-464b686ddeb3", - "instance_request": "1", - "ray": "a4b27c380dc3124f-DFW" - }, - { - "variant": "before", - "index": 31, - "status": 200, - "ttfb_ms": 153.2, - "after_connection_ms": 69.4, - "instance": "05101b85-77bf-4c50-b689-ac993edd792d", - "instance_request": "4", - "ray": "a4b27c3cec865eca-DFW" - }, - { - "variant": "before", - "index": 32, - "status": 200, - "ttfb_ms": 843.0, - "after_connection_ms": 762.5, - "instance": "3a017cfa-4662-4678-9e11-63b112069b9a", - "instance_request": "1", - "ray": "a4b27c3f79db686c-DFW" - }, - { - "variant": "after", - "index": 32, - "status": 200, - "ttfb_ms": 151.2, - "after_connection_ms": 65.2, - "instance": "d378afa9-b704-4745-a325-1442624b8f1f", - "instance_request": "2", - "ray": "a4b27c46896df065-DFW" - }, - { - "variant": "after", - "index": 33, - "status": 200, - "ttfb_ms": 146.7, - "after_connection_ms": 65.4, - "instance": "d378afa9-b704-4745-a325-1442624b8f1f", - "instance_request": "3", - "ray": "a4b27c493da1f0b4-DFW" - }, - { - "variant": "before", - "index": 33, - "status": 200, - "ttfb_ms": 146.9, - "after_connection_ms": 66.9, - "instance": "ea854113-4e85-42d2-b99b-9ad3fa2d683a", - "instance_request": "3", - "ray": "a4b27c4bcde155cb-DFW" - }, - { - "variant": "before", - "index": 34, - "status": 200, - "ttfb_ms": 171.6, - "after_connection_ms": 92.4, - "instance": "e44ed419-558d-408a-910a-50715e5fd4f7", - "instance_request": "2", - "ray": "a4b27c4e6f286b4b-DFW" - }, - { - "variant": "after", - "index": 34, - "status": 200, - "ttfb_ms": 138.9, - "after_connection_ms": 60.7, - "instance": "943b718d-2f8c-43b4-9c16-1235c0f2d4c1", - "instance_request": "3", - "ray": "a4b27c512c0d379d-DFW" - }, - { - "variant": "after", - "index": 35, - "status": 200, - "ttfb_ms": 156.1, - "after_connection_ms": 76.7, - "instance": "5f4301a6-1e2b-4020-894b-cf66c982f69c", - "instance_request": "5", - "ray": "a4b27c53abb246dd-DFW" - }, - { - "variant": "before", - "index": 35, - "status": 200, - "ttfb_ms": 203.8, - "after_connection_ms": 59.4, - "instance": "ea854113-4e85-42d2-b99b-9ad3fa2d683a", - "instance_request": "4", - "ray": "a4b27c56ce819d60-DFW" - }, - { - "variant": "before", - "index": 36, - "status": 200, - "ttfb_ms": 142.2, - "after_connection_ms": 61.0, - "instance": "4e815e29-0e99-438c-9b56-33f345941695", - "instance_request": "4", - "ray": "a4b27c595d1428e5-DFW" - }, - { - "variant": "after", - "index": 36, - "status": 200, - "ttfb_ms": 140.3, - "after_connection_ms": 64.3, - "instance": "8718ccd8-496d-45a1-99e4-8eac1cdb135a", - "instance_request": "4", - "ray": "a4b27c5befa2c669-DFW" - }, - { - "variant": "after", - "index": 37, - "status": 200, - "ttfb_ms": 129.8, - "after_connection_ms": 45.0, - "instance": "124075ac-8a23-4729-af2f-1e0263b93caf", - "instance_request": "5", - "ray": "a4b27c5e8eb663bc-DFW" - }, - { - "variant": "before", - "index": 37, - "status": 200, - "ttfb_ms": 161.4, - "after_connection_ms": 82.4, - "instance": "e44ed419-558d-408a-910a-50715e5fd4f7", - "instance_request": "3", - "ray": "a4b27c60fbc16b57-DFW" - }, - { - "variant": "before", - "index": 38, - "status": 200, - "ttfb_ms": 145.7, - "after_connection_ms": 67.7, - "instance": "d38c1d5d-db05-4e65-9ce7-4101daa5a52f", - "instance_request": "5", - "ray": "a4b27c63aa66f081-DFW" - }, - { - "variant": "after", - "index": 38, - "status": 200, - "ttfb_ms": 159.6, - "after_connection_ms": 78.1, - "instance": "943b718d-2f8c-43b4-9c16-1235c0f2d4c1", - "instance_request": "4", - "ray": "a4b27c664aa6d47c-DFW" - }, - { - "variant": "after", - "index": 39, - "status": 200, - "ttfb_ms": 143.3, - "after_connection_ms": 61.0, - "instance": "943b718d-2f8c-43b4-9c16-1235c0f2d4c1", - "instance_request": "5", - "ray": "a4b27c690df22ca9-DFW" - }, - { - "variant": "before", - "index": 39, - "status": 200, - "ttfb_ms": 157.3, - "after_connection_ms": 77.4, - "instance": "4e815e29-0e99-438c-9b56-33f345941695", - "instance_request": "5", - "ray": "a4b27c6b999646a5-DFW" - } - ], - "transfer_validation": { - "stored_marker": "preserved", - "workflow_created_between_transfer_stages": { - "id": "during-transfer", - "status": { - "status": "complete", - "error": null, - "output": { - "marker": "preserved" - }, - "rollback": null - } - }, - "final_marker": { - "marker": "preserved" - }, - "source_cleanup_deployment_succeeded": true - }, - "cleanup": { - "workers": { - "tanstack-split-payload-before": true, - "tanstack-split-payload-after": true, - "tanstack-split-check-source": true, - "tanstack-split-check-target": true - }, - "synthetic_workflow_deleted": true - }, - "production_split_deployed": true, - "validation": { - "production_build": "passed", - "typescript": "passed", - "lint": "passed", - "unit": { - "passed": 568, - "skipped": 4 - }, - "chat": { - "files_passed": 235, - "tests_passed": 2270 - }, - "desktop": { - "passed": 20, - "skipped": 1 - }, - "browser_page_errors": 0, - "local_sqlite_namespaces": 3 - }, - "production": { - "before_version": "c59a8959-bb8f-46a7-953a-a7c600b1e350", - "after_version": "57c7a11c-699b-4116-9cfa-2d3a9ceb9736", - "workers": { - "site": "57c7a11c-699b-4116-9cfa-2d3a9ceb9736", - "chat": "0da0e4c9-bafc-4bfd-848d-b9cf13fdd64d", - "og": "4e3550be-77f7-4357-b688-8f298e7f0495", - "starter": "6c373cf8-d6b5-49f4-9434-77e71a32af51" - }, - "namespace_ids_preserved": true, - "workflow_id_preserved": true, - "state_before": { - "namespaces": [ - { - "id": "4747da39bdcb4fd291816ecfdfb6e553", - "name": "tanstack-com_WorkspaceSync", - "script": "tanstack-com", - "class": "WorkspaceSync", - "use_sqlite": true - }, - { - "id": "e2306989d3e1432c84f6497e83c368c9", - "name": "tanstack-com_StreamObject", - "script": "tanstack-com", - "class": "StreamObject", - "use_sqlite": true - }, - { - "id": "05995a182725440cbcf3343d11ba39fa", - "name": "tanstack-com_Conversation", - "script": "tanstack-com", - "class": "Conversation", - "use_sqlite": true - } - ], - "workflow": { - "id": "5b66083d-acab-4b3d-9543-72bd1ed99db3", - "name": "tanstack-chat-workflows", - "script_name": "tanstack-com", - "class_name": "TanChatWorkflow" - } - }, - "state_after": { - "namespaces": [ - { - "id": "4747da39bdcb4fd291816ecfdfb6e553", - "name": "tanstack-chat_WorkspaceSync", - "script": "tanstack-chat", - "class": "WorkspaceSync", - "use_sqlite": true - }, - { - "id": "05995a182725440cbcf3343d11ba39fa", - "name": "tanstack-chat_Conversation", - "script": "tanstack-chat", - "class": "Conversation", - "use_sqlite": true - }, - { - "id": "e2306989d3e1432c84f6497e83c368c9", - "name": "tanstack-chat_StreamObject", - "script": "tanstack-chat", - "class": "StreamObject", - "use_sqlite": true - } - ], - "workflow": { - "id": "5b66083d-acab-4b3d-9543-72bd1ed99db3", - "name": "tanstack-chat-workflows", - "script_name": "tanstack-chat", - "class_name": "TanChatWorkflow" - } - }, - "summary": { - "before": { - "requests": 24, - "successes": 24, - "median_ttfb_ms": 245.9, - "p95_ttfb_ms_nearest_rank": 1120.2, - "maximum_ttfb_ms": 1969.7, - "median_after_connection_ms": 163.0, - "median_cf_worker_ms": 91.0, - "responses_over_1s": 2 - }, - "after": { - "requests": 24, - "successes": 24, - "median_ttfb_ms": 305.5, - "p95_ttfb_ms_nearest_rank": 1293.4, - "maximum_ttfb_ms": 1511.8, - "median_after_connection_ms": 185.85, - "median_cf_worker_ms": 100.0, - "responses_over_1s": 5 - }, - "settled": { - "requests": 24, - "successes": 24, - "median_ttfb_ms": 248.5, - "p95_ttfb_ms_nearest_rank": 1352.0, - "maximum_ttfb_ms": 1354.3, - "median_after_connection_ms": 168.2, - "median_cf_worker_ms": 84.0, - "responses_over_1s": 2 - } - }, - "measurements": { - "before": [ - { - "index": 0, - "status": 200, - "ttfb_ms": 1120.2, - "after_connection_ms": 1038.8, - "server_timing": "cfEdge;dur=51,cfOrigin;dur=0,cfWorker;dur=940", - "ray": "a4b28f301fb56b25-DFW", - "cache_control": "public, max-age=0, must-revalidate" - }, - { - "index": 1, - "status": 200, - "ttfb_ms": 273.4, - "after_connection_ms": 187.5, - "server_timing": "cfEdge;dur=50,cfOrigin;dur=0,cfWorker;dur=92", - "ray": "a4b28f39af8d6b27-DFW", - "cache_control": "public, max-age=0, must-revalidate" - }, - { - "index": 2, - "status": 200, - "ttfb_ms": 290.9, - "after_connection_ms": 211.2, - "server_timing": "cfEdge;dur=41,cfOrigin;dur=0,cfWorker;dur=125", - "ray": "a4b28f3dcfea6b7f-DFW", - "cache_control": "public, max-age=0, must-revalidate" - }, - { - "index": 3, - "status": 200, - "ttfb_ms": 1969.7, - "after_connection_ms": 1887.8, - "server_timing": "cfEdge;dur=1287,cfOrigin;dur=0,cfWorker;dur=558", - "ray": "a4b28f422acc5062-DFW", - "cache_control": "public, max-age=0, must-revalidate" - }, - { - "index": 4, - "status": 200, - "ttfb_ms": 339.2, - "after_connection_ms": 186.8, - "server_timing": "cfEdge;dur=39,cfOrigin;dur=0,cfWorker;dur=102", - "ray": "a4b28f516bbf90ae-DFW", - "cache_control": "public, max-age=0, must-revalidate" - }, - { - "index": 5, - "status": 200, - "ttfb_ms": 228.8, - "after_connection_ms": 130.8, - "server_timing": "cfEdge;dur=28,cfOrigin;dur=0,cfWorker;dur=61", - "ray": "a4b28f55e98886ee-DFW", - "cache_control": "public, max-age=0, must-revalidate" - }, - { - "index": 6, - "status": 200, - "ttfb_ms": 201.6, - "after_connection_ms": 114.4, - "server_timing": "cfEdge;dur=12,cfOrigin;dur=0,cfWorker;dur=59", - "ray": "a4b28f59df7fee0c-DFW", - "cache_control": "public, max-age=0, must-revalidate" - }, - { - "index": 7, - "status": 200, - "ttfb_ms": 304.6, - "after_connection_ms": 224.0, - "server_timing": "cfEdge;dur=28,cfOrigin;dur=0,cfWorker;dur=154", - "ray": "a4b28f5d88aaceb7-DFW", - "cache_control": "public, max-age=0, must-revalidate" - }, - { - "index": 8, - "status": 200, - "ttfb_ms": 273.4, - "after_connection_ms": 192.3, - "server_timing": "cfEdge;dur=47,cfOrigin;dur=0,cfWorker;dur=101", - "ray": "a4b28f620b706ba1-DFW", - "cache_control": "public, max-age=0, must-revalidate" - }, - { - "index": 9, - "status": 200, - "ttfb_ms": 224.3, - "after_connection_ms": 143.3, - "server_timing": "cfEdge;dur=21,cfOrigin;dur=0,cfWorker;dur=77", - "ray": "a4b28f664949286c-DFW", - "cache_control": "public, max-age=0, must-revalidate" - }, - { - "index": 10, - "status": 200, - "ttfb_ms": 238.6, - "after_connection_ms": 160.0, - "server_timing": "cfEdge;dur=28,cfOrigin;dur=0,cfWorker;dur=90", - "ray": "a4b28f6a3b4d259a-DFW", - "cache_control": "public, max-age=0, must-revalidate" - }, - { - "index": 11, - "status": 200, - "ttfb_ms": 241.5, - "after_connection_ms": 156.8, - "server_timing": "cfEdge;dur=31,cfOrigin;dur=0,cfWorker;dur=82", - "ray": "a4b28f6e3febf1be-DFW", - "cache_control": "public, max-age=0, must-revalidate" - }, - { - "index": 12, - "status": 200, - "ttfb_ms": 269.3, - "after_connection_ms": 187.8, - "server_timing": "cfEdge;dur=34,cfOrigin;dur=0,cfWorker;dur=109", - "ray": "a4b28f722e976c33-DFW", - "cache_control": "public, max-age=0, must-revalidate" - }, - { - "index": 13, - "status": 200, - "ttfb_ms": 301.6, - "after_connection_ms": 196.3, - "server_timing": "cfEdge;dur=29,cfOrigin;dur=0,cfWorker;dur=82", - "ray": "a4b28f7678210af8-DFW", - "cache_control": "public, max-age=0, must-revalidate" - }, - { - "index": 14, - "status": 200, - "ttfb_ms": 247.8, - "after_connection_ms": 162.5, - "server_timing": "cfEdge;dur=24,cfOrigin;dur=0,cfWorker;dur=92", - "ray": "a4b28f7ac8ea52a8-DFW", - "cache_control": "public, max-age=0, must-revalidate" - }, - { - "index": 15, - "status": 200, - "ttfb_ms": 239.0, - "after_connection_ms": 156.0, - "server_timing": "cfEdge;dur=27,cfOrigin;dur=0,cfWorker;dur=87", - "ray": "a4b28f7eda970ce7-DFW", - "cache_control": "public, max-age=0, must-revalidate" - }, - { - "index": 16, - "status": 200, - "ttfb_ms": 213.9, - "after_connection_ms": 130.9, - "server_timing": "cfEdge;dur=24,cfOrigin;dur=0,cfWorker;dur=64", - "ray": "a4b28f82de7c0c5e-DFW", - "cache_control": "public, max-age=0, must-revalidate" - }, - { - "index": 17, - "status": 200, - "ttfb_ms": 306.3, - "after_connection_ms": 226.8, - "server_timing": "cfEdge;dur=14,cfOrigin;dur=0,cfWorker;dur=170", - "ray": "a4b28f86acf2f0a1-DFW", - "cache_control": "public, max-age=0, must-revalidate" - }, - { - "index": 18, - "status": 200, - "ttfb_ms": 316.2, - "after_connection_ms": 234.9, - "server_timing": "cfEdge;dur=27,cfOrigin;dur=0,cfWorker;dur=166", - "ray": "a4b28f8b3832525d-DFW", - "cache_control": "public, max-age=0, must-revalidate" - }, - { - "index": 19, - "status": 200, - "ttfb_ms": 226.1, - "after_connection_ms": 145.6, - "server_timing": "cfEdge;dur=25,cfOrigin;dur=0,cfWorker;dur=78", - "ray": "a4b28f8fafb6d132-DFW", - "cache_control": "public, max-age=0, must-revalidate" - }, - { - "index": 20, - "status": 200, - "ttfb_ms": 202.7, - "after_connection_ms": 121.2, - "server_timing": "cfEdge;dur=19,cfOrigin;dur=0,cfWorker;dur=56", - "ray": "a4b28f93adbbf2f6-DFW", - "cache_control": "public, max-age=0, must-revalidate" - }, - { - "index": 21, - "status": 200, - "ttfb_ms": 244.0, - "after_connection_ms": 163.5, - "server_timing": "cfEdge;dur=26,cfOrigin;dur=0,cfWorker;dur=96", - "ray": "a4b28f976d65cb75-DFW", - "cache_control": "public, max-age=0, must-revalidate" - }, - { - "index": 22, - "status": 200, - "ttfb_ms": 239.0, - "after_connection_ms": 156.3, - "server_timing": "cfEdge;dur=39,cfOrigin;dur=0,cfWorker;dur=76", - "ray": "a4b28f9b8acfc0fe-DFW", - "cache_control": "public, max-age=0, must-revalidate" - }, - { - "index": 23, - "status": 200, - "ttfb_ms": 221.3, - "after_connection_ms": 143.7, - "server_timing": "cfEdge;dur=35,cfOrigin;dur=0,cfWorker;dur=67", - "ray": "a4b28f9f8b5df0a1-DFW", - "cache_control": "public, max-age=0, must-revalidate" - } - ], - "after": [ - { - "index": 0, - "status": 200, - "ttfb_ms": 1293.4, - "after_connection_ms": 1213.9, - "server_timing": "cfEdge;dur=722,cfOrigin;dur=0,cfWorker;dur=447", - "ray": "a4b29199cb838788-DFW", - "cache_control": "private, no-store" - }, - { - "index": 1, - "status": 200, - "ttfb_ms": 330.3, - "after_connection_ms": 247.5, - "server_timing": "cfEdge;dur=49,cfOrigin;dur=0,cfWorker;dur=156", - "ray": "a4b291a46d98b81a-DFW", - "cache_control": "private, no-store" - }, - { - "index": 2, - "status": 200, - "ttfb_ms": 904.8, - "after_connection_ms": 824.1, - "server_timing": "cfEdge;dur=432,cfOrigin;dur=0,cfWorker;dur=351", - "ray": "a4b291a90ce36a7e-DFW", - "cache_control": "private, no-store" - }, - { - "index": 3, - "status": 200, - "ttfb_ms": 836.6, - "after_connection_ms": 753.6, - "server_timing": "cfEdge;dur=445,cfOrigin;dur=0,cfWorker;dur=267", - "ray": "a4b291b14f2931a6-DFW", - "cache_control": "private, no-store" - }, - { - "index": 4, - "status": 200, - "ttfb_ms": 882.3, - "after_connection_ms": 803.4, - "server_timing": "cfEdge;dur=443,cfOrigin;dur=0,cfWorker;dur=319", - "ray": "a4b291b90cf9c86f-DFW", - "cache_control": "private, no-store" - }, - { - "index": 5, - "status": 200, - "ttfb_ms": 266.2, - "after_connection_ms": 184.2, - "server_timing": "cfEdge;dur=35,cfOrigin;dur=0,cfWorker;dur=100", - "ray": "a4b291c0f8f06bc6-DFW", - "cache_control": "private, no-store" - }, - { - "index": 6, - "status": 200, - "ttfb_ms": 234.0, - "after_connection_ms": 150.9, - "server_timing": "cfEdge;dur=47,cfOrigin;dur=0,cfWorker;dur=61", - "ray": "a4b291c539180af8-DFW", - "cache_control": "private, no-store" - }, - { - "index": 7, - "status": 200, - "ttfb_ms": 195.2, - "after_connection_ms": 117.8, - "server_timing": "cfEdge;dur=16,cfOrigin;dur=0,cfWorker;dur=58", - "ray": "a4b291c92987f432-DFW", - "cache_control": "private, no-store" - }, - { - "index": 8, - "status": 200, - "ttfb_ms": 196.9, - "after_connection_ms": 119.2, - "server_timing": "cfEdge;dur=26,cfOrigin;dur=0,cfWorker;dur=48", - "ray": "a4b291cceaca6e88-DFW", - "cache_control": "private, no-store" - }, - { - "index": 9, - "status": 200, - "ttfb_ms": 1038.2, - "after_connection_ms": 955.7, - "server_timing": "cfEdge;dur=506,cfOrigin;dur=0,cfWorker;dur=406", - "ray": "a4b291d0aab41924-DFW", - "cache_control": "private, no-store" - }, - { - "index": 10, - "status": 200, - "ttfb_ms": 245.6, - "after_connection_ms": 147.8, - "server_timing": "cfEdge;dur=25,cfOrigin;dur=0,cfWorker;dur=69", - "ray": "a4b291da8f325870-DFW", - "cache_control": "private, no-store" - }, - { - "index": 11, - "status": 200, - "ttfb_ms": 1067.7, - "after_connection_ms": 979.1, - "server_timing": "cfEdge;dur=626,cfOrigin;dur=0,cfWorker;dur=310", - "ray": "a4b291de7c14c0e5-DFW", - "cache_control": "private, no-store" - }, - { - "index": 12, - "status": 200, - "ttfb_ms": 1511.8, - "after_connection_ms": 1428.3, - "server_timing": "cfEdge;dur=881,cfOrigin;dur=0,cfWorker;dur=502", - "ray": "a4b291e79e777d5b-DFW", - "cache_control": "private, no-store" - }, - { - "index": 13, - "status": 200, - "ttfb_ms": 199.5, - "after_connection_ms": 116.9, - "server_timing": "cfEdge;dur=23,cfOrigin;dur=0,cfWorker;dur=51", - "ray": "a4b291f3992a14ef-DFW", - "cache_control": "private, no-store" - }, - { - "index": 14, - "status": 200, - "ttfb_ms": 934.8, - "after_connection_ms": 851.3, - "server_timing": "cfEdge;dur=484,cfOrigin;dur=0,cfWorker;dur=325", - "ray": "a4b291f75af87ca9-DFW", - "cache_control": "private, no-store" - }, - { - "index": 15, - "status": 200, - "ttfb_ms": 246.0, - "after_connection_ms": 162.7, - "server_timing": "cfEdge;dur=27,cfOrigin;dur=0,cfWorker;dur=94", - "ray": "a4b291ffcac58c20-DFW", - "cache_control": "private, no-store" - }, - { - "index": 16, - "status": 200, - "ttfb_ms": 1290.9, - "after_connection_ms": 1208.5, - "server_timing": "cfEdge;dur=730,cfOrigin;dur=0,cfWorker;dur=437", - "ray": "a4b29203dbdbf0a6-DFW", - "cache_control": "private, no-store" - }, - { - "index": 17, - "status": 200, - "ttfb_ms": 449.5, - "after_connection_ms": 187.5, - "server_timing": "cfEdge;dur=21,cfOrigin;dur=0,cfWorker;dur=65", - "ray": "a4b2920fa9db5950-DFW", - "cache_control": "private, no-store" - }, - { - "index": 18, - "status": 200, - "ttfb_ms": 280.7, - "after_connection_ms": 165.7, - "server_timing": "cfEdge;dur=25,cfOrigin;dur=0,cfWorker;dur=97", - "ray": "a4b292145b9a2d33-DFW", - "cache_control": "private, no-store" - }, - { - "index": 19, - "status": 200, - "ttfb_ms": 205.0, - "after_connection_ms": 124.1, - "server_timing": "cfEdge;dur=38,cfOrigin;dur=0,cfWorker;dur=39", - "ray": "a4b292186c692d2f-DFW", - "cache_control": "private, no-store" - }, - { - "index": 20, - "status": 200, - "ttfb_ms": 254.8, - "after_connection_ms": 175.0, - "server_timing": "cfEdge;dur=35,cfOrigin;dur=0,cfWorker;dur=100", - "ray": "a4b2921c3bd446a5-DFW", - "cache_control": "private, no-store" - }, - { - "index": 21, - "status": 200, - "ttfb_ms": 409.4, - "after_connection_ms": 330.8, - "server_timing": "cfEdge;dur=39,cfOrigin;dur=0,cfWorker;dur=145", - "ray": "a4b292204e056c26-DFW", - "cache_control": "private, no-store" - }, - { - "index": 22, - "status": 200, - "ttfb_ms": 212.8, - "after_connection_ms": 134.2, - "server_timing": "cfEdge;dur=30,cfOrigin;dur=0,cfWorker;dur=61", - "ray": "a4b29225ae053da4-DFW", - "cache_control": "private, no-store" - }, - { - "index": 23, - "status": 200, - "ttfb_ms": 178.4, - "after_connection_ms": 98.3, - "server_timing": "cfEdge;dur=12,cfOrigin;dur=0,cfWorker;dur=46", - "ray": "a4b292298a79d57a-DFW", - "cache_control": "private, no-store" - } - ], - "settled": [ - { - "index": 0, - "status": 200, - "ttfb_ms": 339.1, - "after_connection_ms": 251.2, - "server_timing": "cfEdge;dur=47,cfOrigin;dur=0,cfWorker;dur=159", - "ray": "a4b2930b1d3f4773-DFW", - "cache_control": "private, no-store" - }, - { - "index": 1, - "status": 200, - "ttfb_ms": 190.2, - "after_connection_ms": 110.8, - "server_timing": "cfEdge;dur=24,cfOrigin;dur=0,cfWorker;dur=44", - "ray": "a4b2930fad79a922-DFW", - "cache_control": "private, no-store" - }, - { - "index": 2, - "status": 200, - "ttfb_ms": 279.5, - "after_connection_ms": 199.8, - "server_timing": "cfEdge;dur=42,cfOrigin;dur=0,cfWorker;dur=111", - "ray": "a4b293136f3b47a8-DFW", - "cache_control": "private, no-store" - }, - { - "index": 3, - "status": 200, - "ttfb_ms": 201.0, - "after_connection_ms": 119.6, - "server_timing": "cfEdge;dur=25,cfOrigin;dur=0,cfWorker;dur=53", - "ray": "a4b29317ae8f28f0-DFW", - "cache_control": "private, no-store" - }, - { - "index": 4, - "status": 200, - "ttfb_ms": 217.2, - "after_connection_ms": 136.5, - "server_timing": "cfEdge;dur=40,cfOrigin;dur=0,cfWorker;dur=53", - "ray": "a4b2931b6dfc33ce-DFW", - "cache_control": "private, no-store" - }, - { - "index": 5, - "status": 200, - "ttfb_ms": 222.2, - "after_connection_ms": 139.4, - "server_timing": "cfEdge;dur=35,cfOrigin;dur=0,cfWorker;dur=60", - "ray": "a4b2931f595a2c97-DFW", - "cache_control": "private, no-store" - }, - { - "index": 6, - "status": 200, - "ttfb_ms": 171.8, - "after_connection_ms": 94.2, - "server_timing": "cfEdge;dur=9,cfOrigin;dur=0,cfWorker;dur=42", - "ray": "a4b293233fb8aad5-DFW", - "cache_control": "private, no-store" - }, - { - "index": 7, - "status": 200, - "ttfb_ms": 403.5, - "after_connection_ms": 319.1, - "server_timing": "cfEdge;dur=20,cfOrigin;dur=0,cfWorker;dur=256", - "ray": "a4b29326db8d74d7-DFW", - "cache_control": "private, no-store" - }, - { - "index": 8, - "status": 200, - "ttfb_ms": 522.5, - "after_connection_ms": 440.8, - "server_timing": "cfEdge;dur=29,cfOrigin;dur=0,cfWorker;dur=368", - "ray": "a4b2932beb1de922-DFW", - "cache_control": "private, no-store" - }, - { - "index": 9, - "status": 200, - "ttfb_ms": 223.7, - "after_connection_ms": 143.2, - "server_timing": "cfEdge;dur=17,cfOrigin;dur=0,cfWorker;dur=83", - "ray": "a4b29331bc9ccd08-DFW", - "cache_control": "private, no-store" - }, - { - "index": 10, - "status": 200, - "ttfb_ms": 297.9, - "after_connection_ms": 211.1, - "server_timing": "cfEdge;dur=41,cfOrigin;dur=0,cfWorker;dur=123", - "ray": "a4b29335bea36c53-DFW", - "cache_control": "private, no-store" - }, - { - "index": 11, - "status": 200, - "ttfb_ms": 333.3, - "after_connection_ms": 209.9, - "server_timing": "cfEdge;dur=19,cfOrigin;dur=0,cfWorker;dur=146", - "ray": "a4b2933a698bf065-DFW", - "cache_control": "private, no-store" - }, - { - "index": 12, - "status": 200, - "ttfb_ms": 196.1, - "after_connection_ms": 116.5, - "server_timing": "cfEdge;dur=32,cfOrigin;dur=0,cfWorker;dur=42", - "ray": "a4b2933ebfb392e6-DFW", - "cache_control": "private, no-store" - }, - { - "index": 13, - "status": 200, - "ttfb_ms": 219.4, - "after_connection_ms": 139.6, - "server_timing": "cfEdge;dur=46,cfOrigin;dur=0,cfWorker;dur=50", - "ray": "a4b293427c46a91e-DFW", - "cache_control": "private, no-store" - }, - { - "index": 14, - "status": 200, - "ttfb_ms": 238.3, - "after_connection_ms": 158.8, - "server_timing": "cfEdge;dur=34,cfOrigin;dur=0,cfWorker;dur=85", - "ray": "a4b29346499bf082-DFW", - "cache_control": "private, no-store" - }, - { - "index": 15, - "status": 200, - "ttfb_ms": 227.7, - "after_connection_ms": 146.2, - "server_timing": "cfEdge;dur=45,cfOrigin;dur=0,cfWorker;dur=59", - "ray": "a4b2934a4b4014ef-DFW", - "cache_control": "private, no-store" - }, - { - "index": 16, - "status": 200, - "ttfb_ms": 309.1, - "after_connection_ms": 227.7, - "server_timing": "cfEdge;dur=33,cfOrigin;dur=0,cfWorker;dur=150", - "ray": "a4b29351597c2c85-DFW", - "cache_control": "private, no-store" - }, - { - "index": 17, - "status": 200, - "ttfb_ms": 1354.3, - "after_connection_ms": 1272.2, - "server_timing": "cfEdge;dur=731,cfOrigin;dur=0,cfWorker;dur=497", - "ray": "a4b29355c93866e9-DFW", - "cache_control": "private, no-store" - }, - { - "index": 18, - "status": 200, - "ttfb_ms": 292.0, - "after_connection_ms": 212.4, - "server_timing": "cfEdge;dur=27,cfOrigin;dur=0,cfWorker;dur=143", - "ray": "a4b29360c8c069f8-DFW", - "cache_control": "private, no-store" - }, - { - "index": 19, - "status": 200, - "ttfb_ms": 226.7, - "after_connection_ms": 143.5, - "server_timing": "cfEdge;dur=25,cfOrigin;dur=0,cfWorker;dur=76", - "ray": "a4b293653b47b901-DFW", - "cache_control": "private, no-store" - }, - { - "index": 20, - "status": 200, - "ttfb_ms": 311.0, - "after_connection_ms": 225.3, - "server_timing": "cfEdge;dur=51,cfOrigin;dur=0,cfWorker;dur=120", - "ray": "a4b293692d306bc2-DFW", - "cache_control": "private, no-store" - }, - { - "index": 21, - "status": 200, - "ttfb_ms": 211.4, - "after_connection_ms": 130.1, - "server_timing": "cfEdge;dur=16,cfOrigin;dur=0,cfWorker;dur=67", - "ray": "a4b2936dcd02ca89-DFW", - "cache_control": "private, no-store" - }, - { - "index": 22, - "status": 200, - "ttfb_ms": 1352.0, - "after_connection_ms": 1263.3, - "server_timing": "cfEdge;dur=740,cfOrigin;dur=0,cfWorker;dur=477", - "ray": "a4b29371bf51eb2b-DFW", - "cache_control": "private, no-store" - }, - { - "index": 23, - "status": 200, - "ttfb_ms": 258.7, - "after_connection_ms": 177.6, - "server_timing": "cfEdge;dur=29,cfOrigin;dur=0,cfWorker;dur=65", - "ray": "a4b2937cacd28b23-DFW", - "cache_control": "private, no-store" - } - ] - }, - "smoke_checks": [ - { - "path": "/api/chat/bootstrap", - "status": 401, - "contentType": "application/json", - "bytes": 32 - }, - { - "path": "/auth/mcp/client-metadata", - "status": 200, - "contentType": "application/json", - "bytes": 320 - }, - { - "path": "/api/og/query.png", - "status": 200, - "contentType": "image/png", - "bytes": 25500, - "png": true - }, - { - "path": "/api/readme/query.png?framework=react", - "status": 200, - "contentType": "image/png", - "bytes": 29752, - "png": true - }, - { - "path": "/api/application-starter/features?framework=react", - "status": 200, - "contentType": "application/json", - "bytes": 10980 - }, - { - "path": "/api/application-starter/deploy/check-name?name=worker-split-check", - "status": 401, - "contentType": "application/json", - "bytes": 47 - }, - { - "path": "/api/application-starter/compile", - "status": 200, - "fileCount": 16, - "hasPackageJson": true - } - ], - "browser": { - "status": 200, - "url": "https://tanstack.com/query/latest/docs/framework/react/installation", - "title": "Overview | TanStack Query React Docs", - "errors": [], - "chatRequests": [], - "documentNavigations": 1 - }, - "authentication": { - "before": { - "status": 401, - "bodyHash": "f49c9ec553f5bfed31a628d9cff7ea7475ce2b74969eaae86127e0fbd9575688" - }, - "after": { - "status": 401, - "bodyHash": "f49c9ec553f5bfed31a628d9cff7ea7475ce2b74969eaae86127e0fbd9575688" - }, - "saved_session_expired": true, - "successful_signed_in_check": "pending fresh login" - }, - "interpretation": "The settled production median is effectively unchanged. Fresh deployments and real production traffic produce a changing cold/warm mixture. These small sequential samples do not establish a production cold-TTFB percentile improvement. The separate controlled payload comparison demonstrates a reduction in preparation latency, not a 55% end-to-end docs speedup. Long responses remain." - } -} diff --git a/docs/worker-split-validation.md b/docs/worker-split-validation.md deleted file mode 100644 index abf48228c..000000000 --- a/docs/worker-split-validation.md +++ /dev/null @@ -1,105 +0,0 @@ -# Worker split validation - -The site Worker now excludes OG image generation, the chat HTTP backend and -Durable Objects, project starter templates, the chat app UI and the icon catalog. -One Start app and browser route tree remain. - -## Cold payload comparison - -Eighty interleaved requests compared the original and reduced site uploads with -an identical minimal handler. Neither handler imported the uploaded app modules, -used credentials, or accessed storage. Every request returned 200 from DFW. - -| | Original payload | Reduced payload | -| ------------------------------------------------ | ---------------: | --------------: | -| Upload | 26,260.77 KiB | 10,935.11 KiB | -| Gzip upload | 8,459.71 KiB | 3,158.83 KiB | -| First observed instance samples | 12 | 13 | -| Median first-instance response after connection | 1,048.05 ms | 471.6 ms | -| Median reused-instance response after connection | 67.65 ms | 65.2 ms | - -The upload shrank about 58%. Median first-instance latency fell about 55%, while -reused-instance latency stayed similar. This supports removing uploaded bytes -as a fix for the cold preparation delay found in the earlier investigation. - -These are payload preparation measurements, not full documentation page TTFB. -The handler's first observed request does not establish that every Cloudflare -platform cache was cold. The measurements still include network round-trip -time. Raw records and cleanup results are in `worker-split-measurements.json`. - -## Runtime and state checks - -The actual built app ran locally with all four Workers and native service -bindings, a synthetic session secret, and an unused local database address. - -- OG image generation returned a valid 1200 × 630 PNG. -- README image generation returned a valid 1800 × 450 PNG. -- Unknown libraries returned 404 and invalid README themes returned 400. -- Unauthenticated chat bootstrap returned 401, and MCP metadata returned 200. -- The icon browser rendered, filtered icons, and had no browser errors. -- Visiting chat without a session redirected to `/chat-access` without browser errors. -- All three chat Durable Object namespaces reported SQLite storage locally. -- Starter HTTP routing reached its existing database-backed rate limiter. Its - database-dependent checks could not complete with the synthetic local address. - -Disposable Cloudflare Workers exercised the same staged transfer as the -production deployment script: prepare the target, commit at the source, activate -the target's local bindings and existing workflow, then remove source tombstones. -The stored marker survived. A workflow created between transfer stages retained -its ID and completed successfully after reassignment. Four disposable Workers -and their test workflow were deleted afterward. - -The production build and full `pnpm test` suite pass: all TypeScript configurations, -lint, 568 unit tests, 2,270 chat tests and 20 desktop tests. Five existing tests -are skipped. - -The tests cover API path and method parity, route precedence, decoded parameters, -trailing slashes, HEAD requests, cookies, request bodies, streamed responses, -first-rollout ordering, ordinary deployments and preflight failure behavior. - -## Production rollout and response measurements - -Deployed to production on October 15, 2026. Initial split deployment version: -`57c7a11c-699b-4116-9cfa-2d3a9ceb9736`. - -The three Durable Object namespace IDs and the existing workflow ID match the -pre-deployment snapshot exactly. Their owner is now `tanstack-chat`. - -Production smoke checks passed for OG and README rendering, MCP metadata, -unauthenticated chat protection, starter feature discovery and in-memory project -generation. The generated project had 16 files including `package.json`, and no -repository or saved project was created. Docs rendered without browser errors -and navigated through the client router without another document request. No -chat APIs or chat app bundles loaded while visiting docs. - -Three sequential samples of the same public Query overview page, each with 24 -fresh curl connections from DFW, all returned 200: - -| Sample | Median TTFB | p95 TTFB, nearest rank | Maximum | Median cfWorker | -| ---------------------------- | ----------: | ---------------------: | ---------: | --------------: | -| Before deployment | 245.9 ms | 1,120.2 ms | 1,969.7 ms | 91 ms | -| Immediately after deployment | 305.5 ms | 1,293.4 ms | 1,511.8 ms | 100 ms | -| Follow-up after deployment | 248.5 ms | 1,352.0 ms | 1,354.3 ms | 84 ms | - -The settled median is effectively unchanged. These small samples have different -cold/warm mixtures and do not establish an improvement in production cold-TTFB -percentiles. Long responses remain. The controlled payload result above is not -a 55% end-to-end docs speedup. - -Documentation responses now explicitly use `private, no-store`. The prior -production version returned `public, max-age=0, must-revalidate`. No full-page -cache was enabled, and this rollout did not purge the CDN or run database schema -migrations. - -The user approved credential provisioning and the authenticated check. The -saved session was already expired before deployment and returned the same 401 -response afterward. A successful signed-in check still needs a fresh session -from `pnpm auth:login` in the primary repository. - -Automatic approval review rejected the earlier temporary public documentation -probes with a binding to the live cache. Those probes were not deployed; the -measurements above were made against the actual production site. - -The branch was subsequently rebased onto `b416acbc` to retain six newer main -commits, including the header branding and Hotkeys page updates. The response -samples above describe the initial split deployment. diff --git a/harness-tests/core/catalog-detail-http.test.ts b/harness-tests/core/catalog-detail-http.test.ts index 2bfbef06a..69a6ec338 100644 --- a/harness-tests/core/catalog-detail-http.test.ts +++ b/harness-tests/core/catalog-detail-http.test.ts @@ -29,8 +29,8 @@ vi.mock('~/chat/server/kody-environment.server', () => ({ })) vi.mock('~/chat/server/plugin-api', () => ({ pluginApi: m.plugins })) vi.mock('~/chat/server/skill-api', () => ({ skillApi: m.skills })) -import { handlePlugins } from '../../src/chat/server/routes/plugins' -import { handleSkills } from '../../src/chat/server/routes/skills' +import { handlePlugins } from '../../src/routes/api/chat/plugins' +import { handleSkills } from '../../src/routes/api/chat/skills' beforeEach(() => { vi.resetAllMocks() m.user.mockResolvedValue({ userId: 'owner', capabilities: ['builder'] }) diff --git a/harness-tests/core/chat-entrypoints.test.js b/harness-tests/core/chat-entrypoints.test.js deleted file mode 100644 index bfe587ffe..000000000 --- a/harness-tests/core/chat-entrypoints.test.js +++ /dev/null @@ -1,120 +0,0 @@ -import { expect, it, vi } from 'vitest' - -const state = vi.hoisted(() => ({ loaded: [], calls: [], initialized: [] })) -vi.mock('cloudflare:workers', () => ({ - DurableObject: class { - constructor(ctx, env) { - this.ctx = ctx - this.env = env - } - }, - WorkflowEntrypoint: class { - constructor(ctx, env) { - this.ctx = ctx - this.env = env - } - }, -})) -vi.mock('~/chat/server/conversation', () => { - state.loaded.push('conversation') - return { - Conversation: class { - constructor(ctx, env) { - state.initialized.push([ctx, env]) - ctx.blockConcurrencyWhile(async () => { - state.initialized.push('storage ready') - }) - } - begin(...args) { - state.calls.push(args) - return 'started' - } - alarm() { - return 'alarm complete' - } - }, - } -}) -vi.mock('~/chat/server/workspace-sync-object', () => { - state.loaded.push('workspace') - return { - WorkspaceSync: class { - snapshot(...args) { - state.calls.push(args) - return 'snapshot' - } - }, - } -}) -vi.mock('@durable-streams/server-cloudflare', () => { - state.loaded.push('streams') - return { - StreamObject: class { - fetch(request) { - return new Response(request.url) - } - forkAcquire(...args) { - state.calls.push(args) - return { ok: true } - } - }, - } -}) -vi.mock('~/chat/server/workflow-driver', () => { - state.loaded.push('workflow') - return { - TanChatWorkflow: class { - constructor(ctx, env) { - state.initialized.push([ctx, env]) - } - run(...args) { - state.calls.push(args) - return 'completed' - } - }, - } -}) - -it('loads implementations on object creation and preserves arguments, results, and initialization', async () => { - const entries = await import('~/chat/server/entries') - expect(state.loaded).toEqual([]) - const pending = [] - const ctx = { - blockConcurrencyWhile: (work) => { - const task = work() - pending.push(task) - return task - }, - } - const env = { marker: 'same environment' } - const conversation = new entries.Conversation(ctx, env) - await Promise.all(pending) - expect(state.loaded).toEqual(['conversation']) - expect(state.initialized).toEqual([[ctx, env], 'storage ready']) - const input = { messageId: 'message' } - expect(await conversation.begin(input)).toBe('started') - expect(state.calls.at(-1)).toEqual([input]) - expect(await conversation.alarm()).toBe('alarm complete') - - const workspace = new entries.WorkspaceSync(ctx, env) - await Promise.all(pending) - expect(await workspace.snapshot('workspace', 'user')).toBe('snapshot') - expect(state.calls.at(-1)).toEqual(['workspace', 'user']) - const stream = new entries.StreamObject(ctx, env) - await Promise.all(pending) - const request = new Request('https://example.com/stream') - expect(await (await stream.fetch(request)).text()).toBe(request.url) - expect(await stream.forkAcquire({ edgeId: 'edge' })).toEqual({ ok: true }) - const workflow = new entries.TanChatWorkflow(ctx, env) - expect(state.loaded).toEqual(['conversation', 'workspace', 'streams']) - const event = { payload: {} }, - step = {} - expect(await workflow.run(event, step)).toBe('completed') - expect(state.calls.at(-1)).toEqual([event, step]) - expect(state.loaded).toEqual([ - 'conversation', - 'workspace', - 'streams', - 'workflow', - ]) -}) diff --git a/harness-tests/core/chat-file-route.test.ts b/harness-tests/core/chat-file-route.test.ts index e39b51f64..a11f83afa 100644 --- a/harness-tests/core/chat-file-route.test.ts +++ b/harness-tests/core/chat-file-route.test.ts @@ -17,7 +17,7 @@ vi.mock('~/chat/server/file-api', () => ({ fileApi: dependencies.files })) vi.mock('~/chat/server/file-environment.server', () => ({ getFileEnvironment: dependencies.environment, })) -import { handleFileRequest } from '../../src/chat/server/routes/files' +import { handleFileRequest } from '../../src/routes/api/chat/files' import { SavedFileError } from '../../src/chat/server/saved-file-contract' const request = ( query = 'workspaceId=personal&botId=assistant', diff --git a/harness-tests/core/chat-mcp-route.test.ts b/harness-tests/core/chat-mcp-route.test.ts index 080d7199c..ed64e4d8a 100644 --- a/harness-tests/core/chat-mcp-route.test.ts +++ b/harness-tests/core/chat-mcp-route.test.ts @@ -23,7 +23,7 @@ vi.mock('~/chat/server/mcp-environment.server', async (original) => ({ getMcpEnvironment: dep.env, })) vi.mock('~/chat/server/mcp-account-api', () => ({ mcpAccountApi: dep.api })) -import { handleMcp } from '../../src/chat/server/routes/mcp/$' +import { handleMcp } from '../../src/routes/api/chat/mcp/$' import { WorkspacePolicyError } from '../../src/chat/workspace-policy.server' beforeEach(() => { vi.clearAllMocks() diff --git a/harness-tests/core/chat-model-route.test.ts b/harness-tests/core/chat-model-route.test.ts index 119812fba..4b5f7f71e 100644 --- a/harness-tests/core/chat-model-route.test.ts +++ b/harness-tests/core/chat-model-route.test.ts @@ -25,7 +25,7 @@ vi.mock('~/chat/server/run-models', async (importOriginal) => ({ ...(await importOriginal()), getRunModelCatalog: dependencies.catalog, })) -import { handleModelCatalog } from '../../src/chat/server/routes/models' +import { handleModelCatalog } from '../../src/routes/api/chat/models' import { WorkspacePolicyError } from '../../src/chat/workspace-policy.server' import { RunModelError } from '../../src/chat/server/run-models' import { defaultPolicy } from '../../src/chat/core/types' diff --git a/harness-tests/core/chat-plugin-route.test.ts b/harness-tests/core/chat-plugin-route.test.ts index fe54150fc..32f804ad0 100644 --- a/harness-tests/core/chat-plugin-route.test.ts +++ b/harness-tests/core/chat-plugin-route.test.ts @@ -23,7 +23,7 @@ vi.mock('~/chat/server/kody-environment.server', async (original) => ({ getKodyEnvironment: dep.env, })) vi.mock('~/chat/server/plugin-api', () => ({ pluginApi: dep.api })) -import { handlePlugins } from '../../src/chat/server/routes/plugins' +import { handlePlugins } from '../../src/routes/api/chat/plugins' import { WorkspacePolicyError } from '../../src/chat/workspace-policy.server' beforeEach(() => { vi.clearAllMocks() diff --git a/harness-tests/core/chat-runtime-headers.test.ts b/harness-tests/core/chat-runtime-headers.test.ts index ebdbae256..8c5fb0293 100644 --- a/harness-tests/core/chat-runtime-headers.test.ts +++ b/harness-tests/core/chat-runtime-headers.test.ts @@ -9,8 +9,8 @@ const captured = vi.hoisted(() => { }) => Promise)[] = [] return { headers, beforeLoads } }) -vi.mock('../../src/chat/components/ChatShellRoute', () => ({ - ChatShellRoute: () => null, +vi.mock('../../src/chat/components/ChatShell', () => ({ + ChatShell: () => null, })) vi.mock('@tanstack/react-start', () => ({ createServerFn: () => ({ handler: () => () => null }), diff --git a/harness-tests/core/chat-skill-route.test.ts b/harness-tests/core/chat-skill-route.test.ts index 5fce60ad2..76749be36 100644 --- a/harness-tests/core/chat-skill-route.test.ts +++ b/harness-tests/core/chat-skill-route.test.ts @@ -23,7 +23,7 @@ vi.mock('~/chat/server/kody-environment.server', async (original) => ({ getKodyEnvironment: dep.env, })) vi.mock('~/chat/server/skill-api', () => ({ skillApi: dep.api })) -import { handleSkills } from '../../src/chat/server/routes/skills' +import { handleSkills } from '../../src/routes/api/chat/skills' import { WorkspacePolicyError } from '../../src/chat/workspace-policy.server' beforeEach(() => { vi.clearAllMocks() diff --git a/package.json b/package.json index f03a78391..2c157137b 100644 --- a/package.json +++ b/package.json @@ -18,8 +18,8 @@ "preview": "vite preview", "preview:cloudflare": "pnpm run preview", "eval:builder-ai": "tsx scripts/builder-ai-eval/run.ts", - "deploy:cloudflare": "pnpm run db:migrate && pnpm run db:verify-builder && pnpm run db:verify-chat && pnpm run build:cloudflare && pnpm run deploy:cloudflare:workers && pnpm run purge:cloudflare", - "deploy:cloudflare:ci": "pnpm run db:prepare-builder && pnpm run deploy:cloudflare:workers", + "deploy:cloudflare": "pnpm run db:migrate && pnpm run db:verify-builder && pnpm run db:verify-chat && pnpm run build:cloudflare && wrangler deploy --name tanstack-com && pnpm run purge:cloudflare", + "deploy:cloudflare:ci": "pnpm run db:prepare-builder && wrangler deploy --name tanstack-com", "purge:cloudflare": "pnpm run with-env -- node scripts/purge-cloudflare-cache.mjs", "cf:typegen": "wrangler types", "content:build": "node scripts/build-content-collections.mjs", @@ -56,8 +56,7 @@ "finalize:desktop-release": "node scripts/desktop-release.mjs", "publish:desktop-release": "pnpm verify:desktop-release && node scripts/desktop-publish.mjs", "benchmark:chat-copy": "tsx scripts/chat/benchmark-conversation-copy.ts", - "benchmark:chat-protocol": "tsx scripts/chat/benchmark-conversation-protocol.ts", - "deploy:cloudflare:workers": "node scripts/deploy-cloudflare.mjs" + "benchmark:chat-protocol": "tsx scripts/chat/benchmark-conversation-protocol.ts" }, "dependencies": { "@codemirror/lang-css": "^6.3.1", diff --git a/scripts/chat-isolation-vite.ts b/scripts/chat-isolation-vite.ts deleted file mode 100644 index f186d09df..000000000 --- a/scripts/chat-isolation-vite.ts +++ /dev/null @@ -1,58 +0,0 @@ -import type { PluginOption } from 'vite' - -// Route matching needs synchronous search validation. Cloudflare also requires -// its exported classes at startup. Neither may import the chat implementation. -const eagerChatModules = new Set([ - 'core/navigation.ts', - 'core/workspace-panels.ts', - 'server/entries.ts', -]) - -export function chatIsolation(): PluginOption { - return { - name: 'tanstack-chat-isolation', - apply: 'build', - applyToEnvironment: (environment) => - ['client', 'ssr'].includes(environment.name), - generateBundle(_options, bundle) { - const chunks = Object.values(bundle).filter( - (item) => item.type === 'chunk', - ) - const byName = new Map(chunks.map((chunk) => [chunk.fileName, chunk])) - const pending = chunks - .filter( - (chunk) => - chunk.isEntry || - Object.keys(chunk.modules).some((id) => - id.endsWith('/src/router.tsx'), - ), - ) - .map((chunk) => chunk.fileName) - const visited = new Set() - const violations = new Set() - while (pending.length) { - const name = pending.pop()! - if (visited.has(name)) continue - visited.add(name) - const chunk = byName.get(name) - if (!chunk) continue - pending.push(...chunk.imports) - for (const [id, module] of Object.entries(chunk.modules)) { - const chatPath = id.split('/src/chat/')[1] - if ( - module.renderedLength && - chatPath && - !eagerChatModules.has(chatPath) - ) { - violations.add(chatPath) - } - } - } - if (violations.size) { - this.error( - `TanChat must load on demand. Eager modules:\n${[...violations].sort().join('\n')}`, - ) - } - }, - } -} diff --git a/scripts/deploy-cloudflare.mjs b/scripts/deploy-cloudflare.mjs deleted file mode 100644 index 157e87ba3..000000000 --- a/scripts/deploy-cloudflare.mjs +++ /dev/null @@ -1,117 +0,0 @@ -import { spawnSync } from 'node:child_process' -import { readFileSync, writeFileSync, rmSync } from 'node:fs' - -function wrangler(args, capture = false) { - const result = spawnSync('pnpm', ['exec', 'wrangler', ...args], { - stdio: capture ? ['inherit', 'pipe', 'inherit'] : 'inherit', - encoding: 'utf8', - }) - if (result.error) throw result.error - if (result.status !== 0) - throw new Error( - `wrangler ${args[0]} failed with exit code ${result.status ?? 1}`, - ) - return result.stdout -} - -const sitePath = 'dist/server/wrangler.json' -const chatPath = 'dist/chat/wrangler.json' -const site = JSON.parse(readFileSync(sitePath, 'utf8')) -const chat = JSON.parse(readFileSync(chatPath, 'utf8')) -const workflow = chat.workflows[0] -const deploy = (config) => - wrangler(['deploy', '--config', config, '--keep-vars']) - -// Fail before any namespace changes if a child is missing its credentials. -for (const worker of ['chat', 'starter']) { - const configPath = `dist/${worker}/wrangler.json` - const config = JSON.parse(readFileSync(configPath, 'utf8')) - const secrets = JSON.parse( - wrangler(['secret', 'list', '--config', configPath], true), - ) - const missing = (config.secrets?.required ?? []).filter( - (name) => !secrets.some((secret) => secret.name === name), - ) - if (missing.length) - throw new Error( - `Provision ${config.name} secrets before deployment: ${missing.join(', ')}`, - ) -} - -let currentWorkflow -for (let page = 1; !currentWorkflow; page++) { - const workflows = JSON.parse( - wrangler( - [ - 'workflows', - 'list', - '--json', - '--per-page', - '100', - '--page', - String(page), - '--config', - sitePath, - ], - true, - ), - ) - currentWorkflow = workflows.find((item) => item.name === workflow.name) - if (workflows.length < 100) break -} -if ( - !currentWorkflow || - ![site.name, chat.name].includes(currentWorkflow.script_name) -) { - throw new Error( - `Expected ${workflow.name} to belong to ${site.name} or ${chat.name}. Check the existing deployment before continuing.`, - ) -} - -for (const worker of ['og', 'starter']) deploy(`dist/${worker}/wrangler.json`) - -if (currentWorkflow.script_name === site.name) { - // First rollout: prepare transfers while the old site still owns the state. - // Cross-script bindings resolve to the existing namespace IDs and continue - // working after those namespaces move. Do not create replacement namespaces. - const preparing = structuredClone(chat) - for (const entry of Object.values(preparing.exports)) { - if (entry.type !== 'durable-object') continue - entry.state = 'expecting-transfer' - entry.transfer_from = site.name - } - for (const binding of preparing.durable_objects.bindings) - binding.script_name = site.name - for (const binding of preparing.workflows) binding.script_name = site.name - preparing.triggers = { crons: [] } - - const committing = structuredClone(site) - committing.exports = Object.fromEntries( - chat.durable_objects.bindings.map((binding) => [ - binding.class_name, - { - type: 'durable-object', - state: 'transferred', - transferred_to: chat.name, - }, - ]), - ) - - const preparingPath = 'dist/chat/wrangler.prepare-transfer.json' - const committingPath = 'dist/server/wrangler.commit-transfer.json' - try { - writeFileSync(preparingPath, JSON.stringify(preparing)) - writeFileSync(committingPath, JSON.stringify(committing)) - deploy(preparingPath) - deploy(committingPath) - deploy(chatPath) - // Remove the completed source tombstones. The site owns no namespaces. - deploy(sitePath) - } finally { - rmSync(preparingPath, { force: true }) - rmSync(committingPath, { force: true }) - } -} else { - deploy(chatPath) - deploy(sitePath) -} diff --git a/scripts/worker-isolation-vite.ts b/scripts/worker-isolation-vite.ts deleted file mode 100644 index 16d9b9ee7..000000000 --- a/scripts/worker-isolation-vite.ts +++ /dev/null @@ -1,48 +0,0 @@ -import type { PluginOption } from 'vite' - -// Check every uploaded module, including lazy chunks. Lazy loading alone does -// not remove a dependency from a Cloudflare Worker deployment. -const excludedSiteModules = [ - '/src/server/og/generate.server.ts', - '/src/chat/server/conversation.ts', - '/src/chat/server/run-models.ts', - '/src/chat/server/workflow-driver.ts', - '/src/chat/server/workspace-sync-object.ts', - '/src/chat/components/App.tsx', - '/src/components/ds/phosphor-icons.generated.ts', - '/src/application-starter/api/create-worker.ts', - '/src/chat/server/http/', - '/src/application-starter/api/http/', - '/node_modules/@tanstack/create/', -] - -export function workerIsolation(): PluginOption { - return { - name: 'tanstack-worker-isolation', - apply: 'build', - applyToEnvironment: (environment) => environment.name === 'ssr', - generateBundle(_options, bundle) { - const violations = new Set() - for (const item of Object.values(bundle)) { - if (item.type !== 'chunk') continue - for (const [id, module] of Object.entries(item.modules)) { - // The site's existing example deployment API uses these six small provider templates. - const providerTemplate = - /\/generated\/worker\/frameworks\/(react|solid)\/add-ons\/(cloudflare|netlify|railway)\.js$/.test( - id, - ) - if ( - module.renderedLength && - !providerTemplate && - excludedSiteModules.some((path) => id.includes(path)) - ) - violations.add(id) - } - } - if (violations.size) - this.error( - `Heavy features must stay out of the site Worker:\n${[...violations].sort().join('\n')}`, - ) - }, - } -} diff --git a/src/application-starter/api/http/compile-attributed.ts b/src/application-starter/api/http/compile-attributed.ts deleted file mode 100644 index c0a559182..000000000 --- a/src/application-starter/api/http/compile-attributed.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' -import { - applicationStarterErrorResponse, - applicationStarterInternalErrorResponse, - applicationStarterJsonResponse, - readApplicationStarterJsonRequest, -} from '~/application-starter/api/request-boundary.server' -import { - applicationStarterValidateBodySchema, - parseApplicationStarterRequest, -} from '~/application-starter/api/request-schema.server' - -export default defineHttpRoute( - '/api/application-starter/compile-attributed', - z.object({}), - { - POST: async ({ request }: { request: Request }) => { - try { - const requestBody = await readApplicationStarterJsonRequest(request) - if ('response' in requestBody) { - return requestBody.response - } - - let body - try { - body = parseApplicationStarterRequest( - applicationStarterValidateBodySchema, - requestBody.body, - ) - } catch { - return applicationStarterErrorResponse( - 'Invalid request body', - 400, - requestBody.rateLimit, - ) - } - - const { compileWithAttributionHandler } = - await import('~/application-starter/api/compile') - const response = await compileWithAttributionHandler(body.definition) - - return applicationStarterJsonResponse(response, requestBody.rateLimit) - } catch (error) { - console.error('Error compiling project with attribution:', error) - return applicationStarterInternalErrorResponse( - 'Failed to compile project', - ) - } - }, - }, -) diff --git a/src/application-starter/api/http/compile.ts b/src/application-starter/api/http/compile.ts deleted file mode 100644 index 123bb4643..000000000 --- a/src/application-starter/api/http/compile.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' -import { - applicationStarterErrorResponse, - applicationStarterInternalErrorResponse, - applicationStarterJsonResponse, - readApplicationStarterJsonRequest, -} from '~/application-starter/api/request-boundary.server' -import { - applicationStarterCompileBodySchema, - parseApplicationStarterRequest, -} from '~/application-starter/api/request-schema.server' - -export default defineHttpRoute( - '/api/application-starter/compile', - z.object({}), - { - POST: async ({ request }: { request: Request }) => { - try { - const requestBody = await readApplicationStarterJsonRequest(request) - if ('response' in requestBody) { - return requestBody.response - } - - let body - try { - body = parseApplicationStarterRequest( - applicationStarterCompileBodySchema, - requestBody.body, - ) - } catch { - return applicationStarterErrorResponse( - 'Invalid request body', - 400, - requestBody.rateLimit, - ) - } - - const { compileHandler } = - await import('~/application-starter/api/compile') - const response = await compileHandler(body.definition, { - format: body.format, - }) - return applicationStarterJsonResponse(response, requestBody.rateLimit) - } catch (error) { - console.error('Error compiling project:', error) - return applicationStarterInternalErrorResponse( - 'Failed to compile project', - ) - } - }, - }, -) diff --git a/src/application-starter/api/http/deploy/check-name.ts b/src/application-starter/api/http/deploy/check-name.ts deleted file mode 100644 index 5dbac3348..000000000 --- a/src/application-starter/api/http/deploy/check-name.ts +++ /dev/null @@ -1,85 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' -import { validateApplicationStarterGetRequest } from '~/application-starter/api/request-boundary.server' -import { jsonResponse } from '~/utils/api-boundary.server' -import { RATE_LIMITS } from '~/utils/rateLimit.server' - -export default defineHttpRoute( - '/api/application-starter/deploy/check-name', - z.object({}), - { - GET: async ({ request }: { request: Request }) => { - const requestGuard = await validateApplicationStarterGetRequest(request, { - rateLimit: RATE_LIMITS.deploy, - }) - if ('response' in requestGuard) { - return requestGuard.response - } - - const [ - { getAuthService }, - { getGitHubAuthState }, - { checkRepoNameAvailable, validateRepoName }, - ] = await Promise.all([ - import('~/auth/index.server'), - import('~/auth/github.server'), - import('~/utils/github-repo.server'), - ]) - const url = new URL(request.url) - const name = url.searchParams.get('name') - - if (!name) { - return jsonResponse( - { available: false, error: 'Name required' }, - { status: 400, headers: requestGuard.rateLimit.headers }, - ) - } - - const validation = validateRepoName(name) - if (!validation.valid) { - return jsonResponse( - { - available: false, - error: validation.error ?? 'Invalid repository name', - }, - { status: 400, headers: requestGuard.rateLimit.headers }, - ) - } - - const authService = getAuthService() - const user = await authService.getCurrentUser(request) - - if (!user) { - return jsonResponse( - { available: false, error: 'Not authenticated' }, - { status: 401, headers: requestGuard.rateLimit.headers }, - ) - } - - const authState = await getGitHubAuthState(user.userId) - - if (!authState.hasRepoScope || !authState.accessToken) { - return jsonResponse( - { available: false, error: 'Missing scope' }, - { status: 403, headers: requestGuard.rateLimit.headers }, - ) - } - - try { - const available = await checkRepoNameAvailable( - authState.accessToken, - name, - ) - return jsonResponse( - { available }, - { headers: requestGuard.rateLimit.headers }, - ) - } catch { - return jsonResponse( - { available: false, error: 'Could not check repository name' }, - { status: 502, headers: requestGuard.rateLimit.headers }, - ) - } - }, - }, -) diff --git a/src/application-starter/api/http/deploy/github.ts b/src/application-starter/api/http/deploy/github.ts deleted file mode 100644 index 5eb692916..000000000 --- a/src/application-starter/api/http/deploy/github.ts +++ /dev/null @@ -1,341 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' -import { - jsonResponse, - readJsonBody, - validateJsonRequest, -} from '~/utils/api-boundary.server' -import { - applicationStarterDeployBodySchema, - parseApplicationStarterRequest, -} from '~/application-starter/api/request-schema.server' -import { - checkIpRateLimit, - rateLimitedResponse, - RATE_LIMITS, -} from '~/utils/rateLimit.server' - -interface DeployResponse { - success: true - repoUrl: string - owner: string - repoName: string -} - -interface DeployError { - success: false - error: string - code: - | 'NOT_AUTHENTICATED' - | 'NO_GITHUB_ACCOUNT' - | 'MISSING_REPO_SCOPE' - | 'INVALID_REPO_NAME' - | 'REPO_NAME_TAKEN' - | 'REPO_CREATION_FAILED' - | 'PUSH_FAILED' - | 'COMPILE_FAILED' - | 'INVALID_REQUEST' -} - -function deployErrorResponse( - error: DeployError, - status: number, - headers?: Headers, -) { - return jsonResponse(error, { status, headers }) -} - -export default defineHttpRoute( - '/api/application-starter/deploy/github', - z.object({}), - { - /** - * GET: Check GitHub auth state for current user - */ - GET: async ({ request }: { request: Request }) => { - const [{ getAuthService }, { getGitHubAuthState }] = await Promise.all([ - import('~/auth/index.server'), - import('~/auth/github.server'), - ]) - const authService = getAuthService() - const user = await authService.getCurrentUser(request) - - if (!user) { - return jsonResponse({ - authenticated: false, - hasGitHubAccount: false, - hasRepoScope: false, - }) - } - - const authState = await getGitHubAuthState(user.userId) - - return jsonResponse({ - authenticated: true, - ...authState, - }) - }, - - /** - * POST: Create GitHub repo and push project files - */ - POST: async ({ request }: { request: Request }) => { - const [authIndex, authGithub, githubRepo] = await Promise.all([ - import('~/auth/index.server'), - import('~/auth/github.server'), - import('~/utils/github-repo.server'), - ]) - const { getAuthService } = authIndex - const { getGitHubAuthState } = authGithub - const { - createRepository, - pushFiles, - validateRepoName, - validateGitHubFiles, - generateRepoDescription, - } = githubRepo - // Rate limiting (10 requests/minute per IP) - const rateLimit = await checkIpRateLimit(request, RATE_LIMITS.deploy) - if (!rateLimit.allowed) { - return rateLimitedResponse(rateLimit) - } - - const guardError = validateJsonRequest(request, { - maxContentLength: 1024 * 1024, - }) - if (guardError) { - return deployErrorResponse( - { - success: false, - error: guardError.message, - code: 'INVALID_REQUEST', - }, - guardError.status, - rateLimit.headers, - ) - } - - const authService = getAuthService() - const user = await authService.getCurrentUser(request) - - if (!user) { - return deployErrorResponse( - { - success: false, - error: 'You must be logged in to deploy', - code: 'NOT_AUTHENTICATED', - }, - 401, - rateLimit.headers, - ) - } - - const authState = await getGitHubAuthState(user.userId) - - if (!authState.hasGitHubAccount) { - return deployErrorResponse( - { - success: false, - error: 'No GitHub account linked', - code: 'NO_GITHUB_ACCOUNT', - }, - 403, - rateLimit.headers, - ) - } - - if (!authState.hasRepoScope || !authState.accessToken) { - console.log('[Deploy] Auth state check failed:', { - hasRepoScope: authState.hasRepoScope, - hasToken: !!authState.accessToken, - }) - return deployErrorResponse( - { - success: false, - error: - 'Missing public_repo scope. Please re-authenticate with GitHub.', - code: 'MISSING_REPO_SCOPE', - }, - 403, - rateLimit.headers, - ) - } - console.log( - '[Deploy] Auth state OK, hasRepoScope:', - authState.hasRepoScope, - ) - - let body - try { - const bodyResult = await readJsonBody(request, { - maxContentLength: 1024 * 1024, - }) - if (!bodyResult.success) { - throw new Error(bodyResult.error.message) - } - body = parseApplicationStarterRequest( - applicationStarterDeployBodySchema, - bodyResult.body, - ) - } catch { - return deployErrorResponse( - { - success: false, - error: 'Invalid request body', - code: 'INVALID_REQUEST', - }, - 400, - rateLimit.headers, - ) - } - - const { - repoName, - isPrivate, - projectName, - framework, - packageManager, - features, - featureOptions, - tailwind, - files, - } = body - const safeFeatureOptions = featureOptions ?? {} - - // Validate repo name - const validation = validateRepoName(repoName) - if (!validation.valid) { - return deployErrorResponse( - { - success: false, - error: validation.error ?? 'Invalid repository name', - code: 'INVALID_REPO_NAME', - }, - 400, - rateLimit.headers, - ) - } - - // Compile the project, or use files generated by the client-only applicationStarter. - let compiledFiles: Record - if (files) { - const fileValidation = validateGitHubFiles(files) - if (!fileValidation.valid) { - return deployErrorResponse( - { - success: false, - error: fileValidation.error, - code: 'INVALID_REQUEST', - }, - 400, - rateLimit.headers, - ) - } - compiledFiles = files - } else { - try { - const { compileHandler } = - await import('~/application-starter/api/compile') - const result = await compileHandler({ - name: projectName, - framework, - packageManager, - tailwind, - features, - featureOptions: safeFeatureOptions, - }) - compiledFiles = result.files - } catch (error) { - console.error('[Deploy] Compile failed:', error) - return deployErrorResponse( - { - success: false, - error: 'Failed to compile project', - code: 'COMPILE_FAILED', - }, - 500, - rateLimit.headers, - ) - } - } - - const compiledFileValidation = validateGitHubFiles(compiledFiles) - if (!compiledFileValidation.valid) { - return deployErrorResponse( - { - success: false, - error: compiledFileValidation.error, - code: 'INVALID_REQUEST', - }, - 400, - rateLimit.headers, - ) - } - - // Create the repository - const description = generateRepoDescription(features) - console.log('[Deploy] Creating repository:', { - repoName, - isPrivate, - description, - }) - const createResult = await createRepository(authState.accessToken, { - name: repoName, - description, - isPrivate, - }) - - if (!createResult.success) { - console.error('[Deploy] Repository creation failed:', { - error: createResult.error, - code: createResult.code, - }) - const code = - createResult.code === 'NAME_TAKEN' - ? 'REPO_NAME_TAKEN' - : 'REPO_CREATION_FAILED' - return deployErrorResponse( - { - success: false, - error: createResult.error, - code, - }, - code === 'REPO_NAME_TAKEN' ? 409 : 500, - rateLimit.headers, - ) - } - console.log('[Deploy] Repository created:', createResult.repoUrl) - - // Push files to the repository - const pushResult = await pushFiles(authState.accessToken, { - owner: createResult.owner, - repo: createResult.name, - files: compiledFiles, - message: 'Initial commit from TanStack Application Starter', - }) - - if (!pushResult.success) { - console.error('[Deploy] Push failed:', pushResult.error) - return deployErrorResponse( - { - success: false, - error: `Repository created but failed to push files: ${pushResult.error}`, - code: 'PUSH_FAILED', - }, - 500, - rateLimit.headers, - ) - } - - return jsonResponse( - { - success: true, - repoUrl: createResult.repoUrl, - owner: createResult.owner, - repoName: createResult.name, - } satisfies DeployResponse, - { headers: rateLimit.headers }, - ) - }, - }, -) diff --git a/src/application-starter/api/http/download.ts b/src/application-starter/api/http/download.ts deleted file mode 100644 index 7b65df10f..000000000 --- a/src/application-starter/api/http/download.ts +++ /dev/null @@ -1,144 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' -import JSZip from 'jszip' -import { - getContentDispositionHeader, - sanitizeResponseFilename, -} from '~/utils/http-response' -import { - applicationStarterErrorResponse, - applicationStarterInternalErrorResponse, - validateApplicationStarterGetRequest, -} from '~/application-starter/api/request-boundary.server' - -const BASE64_PREFIX = 'base64::' -const MAX_BUILDER_DOWNLOAD_FEATURES = 80 -const MAX_BUILDER_DOWNLOAD_OPTIONS = 200 -const BUILDER_ID_PATTERN = /^[a-z0-9._-]{1,120}$/i -const BUILDER_PROJECT_NAME_PATTERN = /^[a-z0-9][a-z0-9_-]{0,119}$/ - -function decodeBase64File(content: string): Uint8Array | null { - if (content.startsWith(BASE64_PREFIX)) { - const decoded = atob(content.slice(BASE64_PREFIX.length)) - - return Uint8Array.from(decoded, (char) => char.charCodeAt(0)) - } - - return null -} - -export default defineHttpRoute( - '/api/application-starter/download', - z.object({}), - { - GET: async ({ request }: { request: Request }) => { - try { - const requestGuard = await validateApplicationStarterGetRequest(request) - if ('response' in requestGuard) { - return requestGuard.response - } - - const url = new URL(request.url) - const name = url.searchParams.get('name') || 'my-tanstack-app' - const featuresParam = url.searchParams.get('features') || '' - const framework = url.searchParams.get('framework') || 'react' - const packageManager = url.searchParams.get('pm') || 'pnpm' - const tailwind = url.searchParams.get('tailwind') !== 'false' - - const features = featuresParam - .split(',') - .map((f) => f.trim()) - .filter(Boolean) - - if ( - !BUILDER_PROJECT_NAME_PATTERN.test(name) || - features.length > MAX_BUILDER_DOWNLOAD_FEATURES || - features.some((feature) => !BUILDER_ID_PATTERN.test(feature)) - ) { - return applicationStarterErrorResponse( - 'Invalid applicationStarter download request', - 400, - requestGuard.rateLimit, - ) - } - - // Parse feature options (keys like "drizzle.database=postgres") - const featureOptions: Record> = {} - let optionCount = 0 - for (const [key, value] of url.searchParams.entries()) { - if (key.includes('.') && value) { - const [featureId, optionKey] = key.split('.') - optionCount++ - if ( - optionCount > MAX_BUILDER_DOWNLOAD_OPTIONS || - !BUILDER_ID_PATTERN.test(featureId) || - !BUILDER_ID_PATTERN.test(optionKey) || - value.length > 500 - ) { - return applicationStarterErrorResponse( - 'Invalid applicationStarter download options', - 400, - requestGuard.rateLimit, - ) - } - if (!featureOptions[featureId]) { - featureOptions[featureId] = {} - } - featureOptions[featureId][optionKey] = value - } - } - - const { compileHandler } = - await import('~/application-starter/api/compile') - const result = await compileHandler({ - name, - framework: framework === 'solid' ? 'solid' : 'react', - packageManager: - packageManager === 'bun' || - packageManager === 'npm' || - packageManager === 'yarn' - ? packageManager - : 'pnpm', - tailwind, - features, - featureOptions, - }) - - const zip = new JSZip() - const zipFilename = sanitizeResponseFilename(`${name}.zip`, 'app.zip') - const rootFolderName = sanitizeResponseFilename(name, 'app') - const rootFolder = zip.folder(rootFolderName) - if (!rootFolder) { - throw new Error('Failed to create ZIP folder') - } - - for (const [filePath, content] of Object.entries(result.files)) { - // Handle base64-encoded binary files (SVGs, images, etc.) - const binaryContent = decodeBase64File(content) - if (binaryContent) { - rootFolder.file(filePath, binaryContent, { binary: true }) - } else { - rootFolder.file(filePath, content) - } - } - - const blob = await zip.generateAsync({ type: 'arraybuffer' }) - - return new Response(blob, { - headers: { - 'Content-Type': 'application/zip', - 'Content-Disposition': getContentDispositionHeader( - 'attachment', - zipFilename, - 'app.zip', - ), - 'Cache-Control': 'no-store', - }, - }) - } catch (error) { - console.error('Error generating ZIP:', error) - return applicationStarterInternalErrorResponse('Failed to generate ZIP') - } - }, - }, -) diff --git a/src/application-starter/api/http/feature-artifacts.ts b/src/application-starter/api/http/feature-artifacts.ts deleted file mode 100644 index 466ffcfae..000000000 --- a/src/application-starter/api/http/feature-artifacts.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' -import { normalizeFrameworkId } from '~/application-starter/frameworks' -import { - applicationStarterErrorResponse, - applicationStarterInternalErrorResponse, - applicationStarterJsonResponse, - readApplicationStarterJsonRequest, -} from '~/application-starter/api/request-boundary.server' -import { - applicationStarterFeatureArtifactsBodySchema, - parseApplicationStarterRequest, -} from '~/application-starter/api/request-schema.server' - -export default defineHttpRoute( - '/api/application-starter/feature-artifacts', - z.object({}), - { - POST: async ({ request }: { request: Request }) => { - try { - const requestBody = await readApplicationStarterJsonRequest(request) - if ('response' in requestBody) { - return requestBody.response - } - - let body - try { - body = parseApplicationStarterRequest( - applicationStarterFeatureArtifactsBodySchema, - requestBody.body, - ) - } catch { - return applicationStarterErrorResponse( - 'Invalid request body', - 400, - requestBody.rateLimit, - ) - } - - const { featureArtifactsHandler } = - await import('~/application-starter/api/feature-artifacts') - const response = await featureArtifactsHandler({ - features: body.features, - projectName: body.projectName, - framework: normalizeFrameworkId(body.framework), - featureOptions: body.featureOptions, - tailwind: body.tailwind, - }) - - return applicationStarterJsonResponse(response, requestBody.rateLimit) - } catch (error) { - console.error('Error fetching feature artifacts:', error) - return applicationStarterInternalErrorResponse( - 'Failed to fetch feature artifacts', - ) - } - }, - }, -) diff --git a/src/application-starter/api/http/features.ts b/src/application-starter/api/http/features.ts deleted file mode 100644 index 217741cbd..000000000 --- a/src/application-starter/api/http/features.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' -import { normalizeFrameworkId } from '~/application-starter/frameworks' - -export default defineHttpRoute( - '/api/application-starter/features', - z.object({}), - { - GET: async ({ request }: { request: Request }) => { - try { - const url = new URL(request.url) - const framework = normalizeFrameworkId( - url.searchParams.get('framework') ?? 'react', - ) - const { getFeaturesHandler } = - await import('~/application-starter/api/features') - const response = await getFeaturesHandler(framework) - return new Response(JSON.stringify(response), { - headers: { 'Content-Type': 'application/json' }, - }) - } catch (error) { - console.error('Error fetching features:', error) - return new Response( - JSON.stringify({ error: 'Failed to fetch features' }), - { - status: 500, - headers: { 'Content-Type': 'application/json' }, - }, - ) - } - }, - }, -) diff --git a/src/application-starter/api/http/load-remote-addon.ts b/src/application-starter/api/http/load-remote-addon.ts deleted file mode 100644 index 1ce8d88d6..000000000 --- a/src/application-starter/api/http/load-remote-addon.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' -import { - applicationStarterErrorResponse, - applicationStarterJsonResponse, - validateApplicationStarterGetRequest, -} from '~/application-starter/api/request-boundary.server' -import { RATE_LIMITS } from '~/utils/rateLimit.server' - -export default defineHttpRoute( - '/api/application-starter/load-remote-addon', - z.object({}), - { - GET: async ({ request }: { request: Request }) => { - const requestGuard = await validateApplicationStarterGetRequest(request, { - rateLimit: RATE_LIMITS.applicationStarterRemote, - }) - if ('response' in requestGuard) { - return requestGuard.response - } - - const url = new URL(request.url) - const integrationUrl = url.searchParams.get('url') - - if (!integrationUrl) { - return applicationStarterErrorResponse( - 'URL is required', - 400, - requestGuard.rateLimit, - ) - } - - const { loadRemoteIntegrationHandler } = - await import('~/application-starter/api/remote') - const response = await loadRemoteIntegrationHandler(integrationUrl) - return applicationStarterJsonResponse(response, requestGuard.rateLimit) - }, - }, -) diff --git a/src/application-starter/api/http/load-remote-template.ts b/src/application-starter/api/http/load-remote-template.ts deleted file mode 100644 index a0ee60998..000000000 --- a/src/application-starter/api/http/load-remote-template.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' -import { - applicationStarterErrorResponse, - applicationStarterJsonResponse, - validateApplicationStarterGetRequest, -} from '~/application-starter/api/request-boundary.server' -import { RATE_LIMITS } from '~/utils/rateLimit.server' - -export default defineHttpRoute( - '/api/application-starter/load-remote-template', - z.object({}), - { - GET: async ({ request }: { request: Request }) => { - const requestGuard = await validateApplicationStarterGetRequest(request, { - rateLimit: RATE_LIMITS.applicationStarterRemote, - }) - if ('response' in requestGuard) { - return requestGuard.response - } - - const url = new URL(request.url) - const templateUrl = url.searchParams.get('url') - - if (!templateUrl) { - return applicationStarterErrorResponse( - 'URL is required', - 400, - requestGuard.rateLimit, - ) - } - - const { loadRemoteTemplateHandler } = - await import('~/application-starter/api/remote') - const response = await loadRemoteTemplateHandler(templateUrl) - return applicationStarterJsonResponse(response, requestGuard.rateLimit) - }, - }, -) diff --git a/src/application-starter/api/http/load-template.ts b/src/application-starter/api/http/load-template.ts deleted file mode 100644 index 75c8c92d8..000000000 --- a/src/application-starter/api/http/load-template.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' -import { - applicationStarterErrorResponse, - applicationStarterJsonResponse, - readApplicationStarterJsonRequest, -} from '~/application-starter/api/request-boundary.server' -import { - applicationStarterRemoteLoadBodySchema, - parseApplicationStarterRequest, -} from '~/application-starter/api/request-schema.server' -import { RATE_LIMITS } from '~/utils/rateLimit.server' - -export default defineHttpRoute( - '/api/application-starter/load-template', - z.object({}), - { - POST: async ({ request }: { request: Request }) => { - try { - const requestBody = await readApplicationStarterJsonRequest(request, { - rateLimit: RATE_LIMITS.applicationStarterRemote, - }) - if ('response' in requestBody) { - return requestBody.response - } - - let body - try { - body = parseApplicationStarterRequest( - applicationStarterRemoteLoadBodySchema, - requestBody.body, - ) - } catch { - return applicationStarterErrorResponse( - 'Invalid request body', - 400, - requestBody.rateLimit, - ) - } - - const { loadRemoteTemplateHandler } = - await import('~/application-starter/api/remote') - const response = await loadRemoteTemplateHandler(body.url) - return applicationStarterJsonResponse(response, requestBody.rateLimit) - } catch (error) { - console.error('Error loading remote template:', error) - return applicationStarterErrorResponse( - 'Failed to load remote template', - 500, - ) - } - }, - }, -) diff --git a/src/application-starter/api/http/resolve.ts b/src/application-starter/api/http/resolve.ts deleted file mode 100644 index fec5771b5..000000000 --- a/src/application-starter/api/http/resolve.ts +++ /dev/null @@ -1,207 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' -import { - checkIpWindowRateLimit, - checkIpRateLimit, - getIpWindowRateLimitStatus, - RATE_LIMITS, - rateLimitedResponse, -} from '~/utils/rateLimit.server' -import { envFunctions } from '~/utils/env.functions' -import { - isRecord, - readJsonBody, - validateJsonRequest, -} from '~/utils/api-boundary.server' - -const MAX_APPLICATION_STARTER_BODY_BYTES = 16 * 1024 - -export default defineHttpRoute( - '/api/application-starter/resolve', - z.object({}), - { - GET: async ({ request }: { request: Request }) => { - try { - if (!envFunctions.DATABASE_URL) { - return new Response( - JSON.stringify({ - authenticated: false, - anonymousGenerationQuota: { - limit: RATE_LIMITS.applicationStarterAnonymousDaily.limit, - remaining: RATE_LIMITS.applicationStarterAnonymousDaily.limit, - resetAt: new Date( - Date.now() + - RATE_LIMITS.applicationStarterAnonymousDaily.windowMs, - ).toISOString(), - }, - }), - { - headers: { - 'Cache-Control': 'no-store', - 'Content-Type': 'application/json', - }, - }, - ) - } - - const [{ getAuthService }, anonymousQuota] = await Promise.all([ - import('~/auth/index.server'), - getIpWindowRateLimitStatus( - request, - RATE_LIMITS.applicationStarterAnonymousDaily, - ), - ]) - - const authService = getAuthService() - const user = await authService.getCurrentUser(request) - - return new Response( - JSON.stringify({ - authenticated: !!user, - anonymousGenerationQuota: user - ? null - : { - limit: anonymousQuota.limit, - remaining: anonymousQuota.remaining, - resetAt: anonymousQuota.resetAt.toISOString(), - }, - }), - { - headers: { - 'Cache-Control': 'no-store', - 'Content-Type': 'application/json', - }, - }, - ) - } catch (error) { - console.error('Error loading application starter status:', error) - - return new Response( - JSON.stringify({ - error: 'Failed to load application starter status', - }), - { - status: 500, - headers: { - 'Cache-Control': 'no-store', - 'Content-Type': 'application/json', - }, - }, - ) - } - }, - POST: async ({ request }: { request: Request }) => { - try { - const [{ getAuthService }, starterServer] = await Promise.all([ - import('~/auth/index.server'), - import('~/utils/application-starter.server'), - ]) - - const rateLimit = await checkIpRateLimit( - request, - RATE_LIMITS.applicationStarter, - ) - - if (!rateLimit.allowed) { - return rateLimitedResponse(rateLimit) - } - - const requestGuardError = validateJsonRequest(request, { - maxContentLength: MAX_APPLICATION_STARTER_BODY_BYTES, - }) - if (requestGuardError) { - return new Response( - JSON.stringify({ error: requestGuardError.message }), - { - status: requestGuardError.status, - headers: { - 'Content-Type': 'application/json', - ...Object.fromEntries(rateLimit.headers.entries()), - }, - }, - ) - } - - const bodyResult = await readJsonBody(request, { - maxContentLength: MAX_APPLICATION_STARTER_BODY_BYTES, - }) - if (!bodyResult.success) { - return new Response( - JSON.stringify({ error: bodyResult.error.message }), - { - status: bodyResult.error.status, - headers: { - 'Content-Type': 'application/json', - ...Object.fromEntries(rateLimit.headers.entries()), - }, - }, - ) - } - - const rawBody = bodyResult.body - const isAnalyzeRequest = isRecord(rawBody) && rawBody.mode === 'analyze' - const body = - starterServer.applicationStarterRequestSchema.parse(rawBody) - - const authService = getAuthService() - const user = await authService.getCurrentUser(request) - - if (!user && !isAnalyzeRequest) { - const anonymousQuota = await checkIpWindowRateLimit( - request, - RATE_LIMITS.applicationStarterAnonymousDaily, - ) - - if (!anonymousQuota.allowed) { - return new Response( - JSON.stringify({ - code: 'LOGIN_REQUIRED_FOR_MORE_GENERATIONS', - error: 'Anonymous generation limit reached', - limit: RATE_LIMITS.applicationStarterAnonymousDaily.limit, - loginRequired: true, - retryAfter: Math.ceil( - (anonymousQuota.resetAt.getTime() - Date.now()) / 1000, - ), - }), - { - status: 429, - headers: { - 'Content-Type': 'application/json', - ...Object.fromEntries(rateLimit.headers.entries()), - ...Object.fromEntries(anonymousQuota.headers.entries()), - }, - }, - ) - } - } - - const response = isAnalyzeRequest - ? await starterServer.analyzeApplicationStarterServer({ - data: body, - }) - : await starterServer.resolveApplicationStarterServer({ - data: body, - }) - - return new Response(JSON.stringify(response), { - headers: { - 'Cache-Control': 'no-store', - 'Content-Type': 'application/json', - ...Object.fromEntries(rateLimit.headers.entries()), - }, - }) - } catch (error) { - console.error('Error resolving application starter:', error) - return new Response( - JSON.stringify({ - error: 'Failed to resolve application starter', - }), - { - status: 500, - headers: { 'Content-Type': 'application/json' }, - }, - ) - } - }, - }, -) diff --git a/src/application-starter/api/http/routes.ts b/src/application-starter/api/http/routes.ts deleted file mode 100644 index ab1b98624..000000000 --- a/src/application-starter/api/http/routes.ts +++ /dev/null @@ -1,29 +0,0 @@ -import route0 from '~/application-starter/api/http/compile-attributed' -import route1 from '~/application-starter/api/http/compile' -import route2 from '~/application-starter/api/http/deploy/check-name' -import route3 from '~/application-starter/api/http/deploy/github' -import route4 from '~/application-starter/api/http/download' -import route5 from '~/application-starter/api/http/feature-artifacts' -import route6 from '~/application-starter/api/http/features' -import route7 from '~/application-starter/api/http/load-remote-addon' -import route8 from '~/application-starter/api/http/load-remote-template' -import route9 from '~/application-starter/api/http/load-template' -import route10 from '~/application-starter/api/http/resolve' -import route11 from '~/application-starter/api/http/suggest' -import route12 from '~/application-starter/api/http/validate' - -export const starterHttpRoutes = [ - route0, - route1, - route2, - route3, - route4, - route5, - route6, - route7, - route8, - route9, - route10, - route11, - route12, -] diff --git a/src/application-starter/api/http/suggest.ts b/src/application-starter/api/http/suggest.ts deleted file mode 100644 index 94e79cbd4..000000000 --- a/src/application-starter/api/http/suggest.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' -import { - applicationStarterErrorResponse, - applicationStarterInternalErrorResponse, - applicationStarterJsonResponse, - readApplicationStarterJsonRequest, -} from '~/application-starter/api/request-boundary.server' -import { - applicationStarterSuggestBodySchema, - parseApplicationStarterRequest, -} from '~/application-starter/api/request-schema.server' - -export default defineHttpRoute( - '/api/application-starter/suggest', - z.object({}), - { - POST: async ({ request }: { request: Request }) => { - try { - const requestBody = await readApplicationStarterJsonRequest(request) - if ('response' in requestBody) { - return requestBody.response - } - - let body - try { - body = parseApplicationStarterRequest( - applicationStarterSuggestBodySchema, - requestBody.body, - ) - } catch { - return applicationStarterErrorResponse( - 'Invalid request body', - 400, - requestBody.rateLimit, - ) - } - - const { suggestHandler } = - await import('~/application-starter/api/suggest') - const response = await suggestHandler(body) - return applicationStarterJsonResponse(response, requestBody.rateLimit) - } catch (error) { - console.error('Error suggesting features:', error) - return applicationStarterInternalErrorResponse( - 'Failed to generate suggestions', - ) - } - }, - }, -) diff --git a/src/application-starter/api/http/validate.ts b/src/application-starter/api/http/validate.ts deleted file mode 100644 index 835d5bdae..000000000 --- a/src/application-starter/api/http/validate.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' -import { - applicationStarterErrorResponse, - applicationStarterInternalErrorResponse, - applicationStarterJsonResponse, - readApplicationStarterJsonRequest, -} from '~/application-starter/api/request-boundary.server' -import { - applicationStarterValidateBodySchema, - parseApplicationStarterRequest, -} from '~/application-starter/api/request-schema.server' - -export default defineHttpRoute( - '/api/application-starter/validate', - z.object({}), - { - POST: async ({ request }: { request: Request }) => { - try { - const requestBody = await readApplicationStarterJsonRequest(request) - if ('response' in requestBody) { - return requestBody.response - } - - let body - try { - body = parseApplicationStarterRequest( - applicationStarterValidateBodySchema, - requestBody.body, - ) - } catch { - return applicationStarterErrorResponse( - 'Invalid request body', - 400, - requestBody.rateLimit, - ) - } - - const { validateHandler } = - await import('~/application-starter/api/validate') - const response = await validateHandler(body.definition) - return applicationStarterJsonResponse(response, requestBody.rateLimit) - } catch (error) { - console.error('Error validating project:', error) - return applicationStarterInternalErrorResponse( - 'Failed to validate project', - ) - } - }, - }, -) diff --git a/src/application-starter/api/request-boundary.server.ts b/src/application-starter/api/request-boundary.server.ts index 05581a3b3..bd297b2ec 100644 --- a/src/application-starter/api/request-boundary.server.ts +++ b/src/application-starter/api/request-boundary.server.ts @@ -59,7 +59,7 @@ export async function readApplicationStarterJsonRequest( export async function validateApplicationStarterGetRequest( request: Request, options: { rateLimit?: RateLimitOptions } = {}, -): Promise<{ response: Response } | { rateLimit: RateLimitResult }> { +) { const rateLimit = await checkIpRateLimit( request, options.rateLimit ?? RATE_LIMITS.applicationStarterCompile, diff --git a/src/chat/components/AppRoute.tsx b/src/chat/components/AppRoute.tsx deleted file mode 100644 index 1bd9183ee..000000000 --- a/src/chat/components/AppRoute.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import * as React from 'react' -import { createClientOnlyFn } from '@tanstack/react-start' -import { ClientOnly } from '@tanstack/react-router' -import { WorkspaceSkeleton } from './WorkspaceSkeleton' - -const LazyApp = React.lazy( - createClientOnlyFn(() => - import('./App').then((module) => ({ default: module.App })), - ), -) - -export function AppRoute() { - return ( - }> - }> - - - - ) -} diff --git a/src/chat/components/ChatShellRoute.tsx b/src/chat/components/ChatShellRoute.tsx deleted file mode 100644 index 2b6597016..000000000 --- a/src/chat/components/ChatShellRoute.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import * as React from 'react' -import { createClientOnlyFn } from '@tanstack/react-start' -import { ClientOnly } from '@tanstack/react-router' -import { WorkspaceSkeleton } from './WorkspaceSkeleton' - -const LazyChatShell = React.lazy( - createClientOnlyFn(() => - import('./ChatShell').then((module) => ({ default: module.ChatShell })), - ), -) - -export function ChatShellRoute() { - return ( - }> - }> - - - - ) -} diff --git a/src/chat/components/projects/Loading.tsx b/src/chat/components/projects/Loading.tsx index 0e292ff31..599fb6c18 100644 --- a/src/chat/components/projects/Loading.tsx +++ b/src/chat/components/projects/Loading.tsx @@ -426,16 +426,3 @@ function SkeletonBlock({ className }: { className: string }) { /> ) } - -export function BuilderRouteContent({ - children, - pathname, -}: BuilderRouteFrameProps) { - return ( - - }> - {children} - - - ) -} diff --git a/src/chat/server/entries.ts b/src/chat/server/entries.ts deleted file mode 100644 index 9275c9460..000000000 --- a/src/chat/server/entries.ts +++ /dev/null @@ -1,487 +0,0 @@ -import { DurableObject, WorkflowEntrypoint } from 'cloudflare:workers' -import type { WorkflowEvent, WorkflowStep } from 'cloudflare:workers' -import type { - WorkflowDriverEnvironment, - WorkflowDriverParams, -} from './workflow-driver' -import type { Conversation as ConversationImplementation } from './conversation' -import type { WorkspaceSync as WorkspaceSyncImplementation } from './workspace-sync-object' -import type { StreamObject as StreamObjectImplementation } from '@durable-streams/server-cloudflare' - -// Keep the deployed class names and storage namespaces, but initialize chat only -// when Cloudflare creates one of its objects. RPC methods stay on the prototype. -export class Conversation extends DurableObject< - ConstructorParameters[1] -> { - private implementation!: ConversationImplementation - constructor( - ctx: ConstructorParameters[0], - env: ConstructorParameters[1], - ) { - super(ctx, env) - ctx.blockConcurrencyWhile(async () => { - const { Conversation } = await import('./conversation') - this.implementation = new Conversation(ctx, env) - }) - } - async alarm(...args: Parameters) { - return this.implementation.alarm(...args) - } - async copyBoundary( - ...args: Parameters - ) { - return this.implementation.copyBoundary(...args) - } - async captureThreadSource( - ...args: Parameters - ) { - return this.implementation.captureThreadSource(...args) - } - async captureRetrySourceJson( - ...args: Parameters - ) { - return this.implementation.captureRetrySourceJson(...args) - } - async captureRetrySource( - ...args: Parameters - ) { - return this.implementation.captureRetrySource(...args) - } - async actionEvidenceJson( - ...args: Parameters - ) { - return this.implementation.actionEvidenceJson(...args) - } - async retryPreparationSnapshot( - ...args: Parameters - ) { - return this.implementation.retryPreparationSnapshot(...args) - } - async startCopyExport( - ...args: Parameters - ) { - return this.implementation.startCopyExport(...args) - } - async readCopyPage( - ...args: Parameters - ) { - return this.implementation.readCopyPage(...args) - } - async readCopyPages( - ...args: Parameters - ) { - return this.implementation.readCopyPages(...args) - } - async importCopyPage( - ...args: Parameters - ) { - return this.implementation.importCopyPage(...args) - } - async importCopyPages( - ...args: Parameters - ) { - return this.implementation.importCopyPages(...args) - } - async finishCopyImport( - ...args: Parameters - ) { - return this.implementation.finishCopyImport(...args) - } - async activateCopy( - ...args: Parameters - ) { - return this.implementation.activateCopy(...args) - } - async discardCopyImport( - ...args: Parameters - ) { - return this.implementation.discardCopyImport(...args) - } - async releaseCopyExport( - ...args: Parameters - ) { - return this.implementation.releaseCopyExport(...args) - } - async wakeCopies( - ...args: Parameters - ) { - return this.implementation.wakeCopies(...args) - } - async bindIdentity( - ...args: Parameters - ) { - return this.implementation.bindIdentity(...args) - } - async lifecycleState( - ...args: Parameters - ) { - return this.implementation.lifecycleState(...args) - } - async reserveEmptyThread( - ...args: Parameters - ) { - return this.implementation.reserveEmptyThread(...args) - } - async reserveDeletion( - ...args: Parameters - ) { - return this.implementation.reserveDeletion(...args) - } - async releaseDeletion( - ...args: Parameters - ) { - return this.implementation.releaseDeletion(...args) - } - async streamSnapshot( - ...args: Parameters - ) { - return this.implementation.streamSnapshot(...args) - } - async referenceContext( - ...args: Parameters - ) { - return this.implementation.referenceContext(...args) - } - async archivedMessage( - ...args: Parameters - ) { - return this.implementation.archivedMessage(...args) - } - async archivedHistory( - ...args: Parameters - ) { - return this.implementation.archivedHistory(...args) - } - async transcriptNavigation( - ...args: Parameters - ) { - return this.implementation.transcriptNavigation(...args) - } - async readStream( - ...args: Parameters - ) { - return this.implementation.readStream(...args) - } - async snapshot(...args: Parameters) { - return this.implementation.snapshot(...args) - } - async executionSnapshot( - ...args: Parameters - ) { - return this.implementation.executionSnapshot(...args) - } - async executionHistory( - ...args: Parameters - ) { - return this.implementation.executionHistory(...args) - } - async executionEvents( - ...args: Parameters - ) { - return this.implementation.executionEvents(...args) - } - async changeExecution( - ...args: Parameters - ) { - return this.implementation.changeExecution(...args) - } - async executionProjectSnapshot( - ...args: Parameters - ) { - return this.implementation.executionProjectSnapshot(...args) - } - async reserveExecutionSnapshot( - ...args: Parameters - ) { - return this.implementation.reserveExecutionSnapshot(...args) - } - async publishExecutionSnapshot( - ...args: Parameters - ) { - return this.implementation.publishExecutionSnapshot(...args) - } - async prepareDelegation( - ...args: Parameters - ) { - return this.implementation.prepareDelegation(...args) - } - async listWorkflowRuns( - ...args: Parameters - ) { - return this.implementation.listWorkflowRuns(...args) - } - async readWorkflowAnswer( - ...args: Parameters - ) { - return this.implementation.readWorkflowAnswer(...args) - } - async readWorkflowOutputFile( - ...args: Parameters - ) { - return this.implementation.readWorkflowOutputFile(...args) - } - async readWorkflowFiles( - ...args: Parameters - ) { - return this.implementation.readWorkflowFiles(...args) - } - async inspectWorkflowRun( - ...args: Parameters - ) { - return this.implementation.inspectWorkflowRun(...args) - } - async launchWorkflowRun( - ...args: Parameters - ) { - return this.implementation.launchWorkflowRun(...args) - } - async withdrawWorkflowStart( - ...args: Parameters - ) { - return this.implementation.withdrawWorkflowStart(...args) - } - async startWorkflowRun( - ...args: Parameters - ) { - return this.implementation.startWorkflowRun(...args) - } - async advanceWorkflowRun( - ...args: Parameters - ) { - return this.implementation.advanceWorkflowRun(...args) - } - async cancelWorkflowRun( - ...args: Parameters - ) { - return this.implementation.cancelWorkflowRun(...args) - } - async settleWorkflowStep( - ...args: Parameters - ) { - return this.implementation.settleWorkflowStep(...args) - } - async workflowGrant( - ...args: Parameters - ) { - return this.implementation.workflowGrant(...args) - } - async workflowInputs( - ...args: Parameters - ) { - return this.implementation.workflowInputs(...args) - } - async workflowFileInput( - ...args: Parameters - ) { - return this.implementation.workflowFileInput(...args) - } - async reserveWorkflowOperation( - ...args: Parameters - ) { - return this.implementation.reserveWorkflowOperation(...args) - } - async delegationGrant( - ...args: Parameters - ) { - return this.implementation.delegationGrant(...args) - } - async reserveDelegationOperation( - ...args: Parameters< - ConversationImplementation['reserveDelegationOperation'] - > - ) { - return this.implementation.reserveDelegationOperation(...args) - } - async admitWorkflowRun( - ...args: Parameters - ) { - return this.implementation.admitWorkflowRun(...args) - } - async admitDelegatedRun( - ...args: Parameters - ) { - return this.implementation.admitDelegatedRun(...args) - } - async revokeDelegatedRun( - ...args: Parameters - ) { - return this.implementation.revokeDelegatedRun(...args) - } - async delegatedRunReport( - ...args: Parameters - ) { - return this.implementation.delegatedRunReport(...args) - } - async revokeWorkflowRun( - ...args: Parameters - ) { - return this.implementation.revokeWorkflowRun(...args) - } - async workflowStepUsage( - ...args: Parameters - ) { - return this.implementation.workflowStepUsage(...args) - } - async workflowRunResult( - ...args: Parameters - ) { - return this.implementation.workflowRunResult(...args) - } - async delegationSnapshot( - ...args: Parameters - ) { - return this.implementation.delegationSnapshot(...args) - } - async delegationHistory( - ...args: Parameters - ) { - return this.implementation.delegationHistory(...args) - } - async taskDelegations( - ...args: Parameters - ) { - return this.implementation.taskDelegations(...args) - } - async taskUsage( - ...args: Parameters - ) { - return this.implementation.taskUsage(...args) - } - async historicalTaskUsage( - ...args: Parameters - ) { - return this.implementation.historicalTaskUsage(...args) - } - async cancelDelegatedTask( - ...args: Parameters - ) { - return this.implementation.cancelDelegatedTask(...args) - } - async waitForDelegatedTasks( - ...args: Parameters - ) { - return this.implementation.waitForDelegatedTasks(...args) - } - async scheduleSnapshot( - ...args: Parameters - ) { - return this.implementation.scheduleSnapshot(...args) - } - async changeSchedule( - ...args: Parameters - ) { - return this.implementation.changeSchedule(...args) - } - async runHistory( - ...args: Parameters - ) { - return this.implementation.runHistory(...args) - } - async stop(...args: Parameters) { - return this.implementation.stop(...args) - } - async dismissPendingTask( - ...args: Parameters - ) { - return this.implementation.dismissPendingTask(...args) - } - async reset(...args: Parameters) { - return this.implementation.reset(...args) - } - async begin(...args: Parameters) { - return this.implementation.begin(...args) - } - async sendReceipt( - ...args: Parameters - ) { - return this.implementation.sendReceipt(...args) - } - async updateQueue( - ...args: Parameters - ) { - return this.implementation.updateQueue(...args) - } - async decideApproval( - ...args: Parameters - ) { - return this.implementation.decideApproval(...args) - } - async continueTask( - ...args: Parameters - ) { - return this.implementation.continueTask(...args) - } -} -export class WorkspaceSync extends DurableObject< - ConstructorParameters[1] -> { - private implementation!: WorkspaceSyncImplementation - constructor( - ctx: ConstructorParameters[0], - env: ConstructorParameters[1], - ) { - super(ctx, env) - ctx.blockConcurrencyWhile(async () => { - const { WorkspaceSync } = await import('./workspace-sync-object') - this.implementation = new WorkspaceSync(ctx, env) - }) - } - async snapshot(...args: Parameters) { - return this.implementation.snapshot(...args) - } - async publish(...args: Parameters) { - return this.implementation.publish(...args) - } - async read(...args: Parameters) { - return this.implementation.read(...args) - } - async alarm(...args: Parameters) { - return this.implementation.alarm(...args) - } -} -export class StreamObject extends DurableObject< - ConstructorParameters[1] -> { - private implementation!: StreamObjectImplementation - constructor( - ctx: ConstructorParameters[0], - env: ConstructorParameters[1], - ) { - super(ctx, env) - ctx.blockConcurrencyWhile(async () => { - const { StreamObject } = - await import('@durable-streams/server-cloudflare') - this.implementation = new StreamObject(ctx, env) - }) - } - async fetch(...args: Parameters) { - return this.implementation.fetch(...args) - } - async alarm(...args: Parameters) { - return this.implementation.alarm(...args) - } - async forkAcquire( - ...args: Parameters - ) { - return this.implementation.forkAcquire(...args) - } - async forkRelease( - ...args: Parameters - ) { - return this.implementation.forkRelease(...args) - } - async readRange( - ...args: Parameters - ) { - return this.implementation.readRange(...args) - } -} -export class TanChatWorkflow extends WorkflowEntrypoint< - WorkflowDriverEnvironment, - WorkflowDriverParams -> { - async run(event: WorkflowEvent, step: WorkflowStep) { - const { TanChatWorkflow } = await import('./workflow-driver') - return new TanChatWorkflow(this.ctx, this.env).run(event, step) - } -} diff --git a/src/chat/server/http/api/chat/account/composer-drafts/$accountId.$scope.ts b/src/chat/server/http/api/chat/account/composer-drafts/$accountId.$scope.ts deleted file mode 100644 index d392a0ccd..000000000 --- a/src/chat/server/http/api/chat/account/composer-drafts/$accountId.$scope.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute( - '/api/chat/account/composer-drafts/$accountId/$scope', - z.object({ accountId: z.string(), scope: z.string() }), - { - GET: async ({ request, params }) => { - const { handleComposerDraft } = - await import('~/chat/server/composer-draft-http.server') - return handleComposerDraft(request, params.accountId, params.scope) - }, - POST: async ({ request, params }) => { - const { handleComposerDraft } = - await import('~/chat/server/composer-draft-http.server') - return handleComposerDraft(request, params.accountId, params.scope) - }, - }, -) diff --git a/src/chat/server/http/api/chat/account/devices.ts b/src/chat/server/http/api/chat/account/devices.ts deleted file mode 100644 index dad4f864d..000000000 --- a/src/chat/server/http/api/chat/account/devices.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute('/api/chat/account/devices', z.object({}), { - GET: async ({ request }) => { - const { handleDeviceAccount } = - await import('~/chat/server/device-http.server') - return handleDeviceAccount(request) - }, - POST: async ({ request }) => { - const { handleDeviceAccount } = - await import('~/chat/server/device-http.server') - return handleDeviceAccount(request) - }, -}) diff --git a/src/chat/server/http/api/chat/account/onboarding.ts b/src/chat/server/http/api/chat/account/onboarding.ts deleted file mode 100644 index ef3604ec4..000000000 --- a/src/chat/server/http/api/chat/account/onboarding.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute('/api/chat/account/onboarding', z.object({}), { - GET: async ({ request }) => { - const { handleOnboarding } = - await import('~/chat/server/onboarding-http.server') - return handleOnboarding(request) - }, - POST: async ({ request }) => { - const { handleOnboarding } = - await import('~/chat/server/onboarding-http.server') - return handleOnboarding(request) - }, -}) diff --git a/src/chat/server/http/api/chat/account/preferences.ts b/src/chat/server/http/api/chat/account/preferences.ts deleted file mode 100644 index 1b7093bd4..000000000 --- a/src/chat/server/http/api/chat/account/preferences.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute('/api/chat/account/preferences', z.object({}), { - GET: async ({ request }) => { - const { handleAccountPreferences } = - await import('~/chat/server/account-preferences-http.server') - return handleAccountPreferences(request) - }, - POST: async ({ request }) => { - const { handleAccountPreferences } = - await import('~/chat/server/account-preferences-http.server') - return handleAccountPreferences(request) - }, -}) diff --git a/src/chat/server/http/api/chat/activity.ts b/src/chat/server/http/api/chat/activity.ts deleted file mode 100644 index 1bc1e0a09..000000000 --- a/src/chat/server/http/api/chat/activity.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute('/api/chat/activity', z.object({}), { - GET: async ({ request }) => { - const { handleWorkspaceActivity } = - await import('~/chat/server/workspace-activity-http.server') - return handleWorkspaceActivity(request) - }, -}) diff --git a/src/chat/server/http/api/chat/app-version.ts b/src/chat/server/http/api/chat/app-version.ts deleted file mode 100644 index 1e48e9172..000000000 --- a/src/chat/server/http/api/chat/app-version.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute('/api/chat/app-version', z.object({}), { - GET: async () => { - const { appBuildId } = await import('~/chat/core/app-version') - return Response.json( - { build: appBuildId }, - { headers: { 'Cache-Control': 'no-store' } }, - ) - }, -}) diff --git a/src/chat/server/http/api/chat/bootstrap.ts b/src/chat/server/http/api/chat/bootstrap.ts deleted file mode 100644 index e48450633..000000000 --- a/src/chat/server/http/api/chat/bootstrap.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute('/api/chat/bootstrap', z.object({}), { - GET: async ({ request }) => { - const { handleBootstrap } = - await import('~/chat/server/bootstrap-http.server') - return handleBootstrap(request) - }, -}) diff --git a/src/chat/server/http/api/chat/bot-drafts/$id.files.$fileId.content.ts b/src/chat/server/http/api/chat/bot-drafts/$id.files.$fileId.content.ts deleted file mode 100644 index 5cfe1fc9d..000000000 --- a/src/chat/server/http/api/chat/bot-drafts/$id.files.$fileId.content.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute( - '/api/chat/bot-drafts/$id/files/$fileId/content', - z.object({ id: z.string(), fileId: z.string() }), - { - GET: async ({ request, params }) => { - const { handleFiles } = await import('~/chat/server/file-http.server') - return handleFiles(request, 'bot-drafts', params.id, params.fileId, true) - }, - }, -) diff --git a/src/chat/server/http/api/chat/bot-drafts/$id.files.$fileId.ts b/src/chat/server/http/api/chat/bot-drafts/$id.files.$fileId.ts deleted file mode 100644 index 50371b16b..000000000 --- a/src/chat/server/http/api/chat/bot-drafts/$id.files.$fileId.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute( - '/api/chat/bot-drafts/$id/files/$fileId', - z.object({ id: z.string(), fileId: z.string() }), - { - GET: async ({ request, params }) => { - const { handleFiles } = await import('~/chat/server/file-http.server') - return handleFiles(request, 'bot-drafts', params.id, params.fileId) - }, - POST: async ({ request, params }) => { - const { handleFiles } = await import('~/chat/server/file-http.server') - return handleFiles(request, 'bot-drafts', params.id, params.fileId) - }, - PUT: async ({ request, params }) => { - const { handleFiles } = await import('~/chat/server/file-http.server') - return handleFiles(request, 'bot-drafts', params.id, params.fileId) - }, - DELETE: async ({ request, params }) => { - const { handleFiles } = await import('~/chat/server/file-http.server') - return handleFiles(request, 'bot-drafts', params.id, params.fileId) - }, - }, -) diff --git a/src/chat/server/http/api/chat/bot-drafts/$id.files.ts b/src/chat/server/http/api/chat/bot-drafts/$id.files.ts deleted file mode 100644 index 58699363e..000000000 --- a/src/chat/server/http/api/chat/bot-drafts/$id.files.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute( - '/api/chat/bot-drafts/$id/files', - z.object({ id: z.string() }), - { - GET: async ({ request, params }) => { - const { handleFiles } = await import('~/chat/server/file-http.server') - return handleFiles(request, 'bot-drafts', params.id) - }, - POST: async ({ request, params }) => { - const { handleFiles } = await import('~/chat/server/file-http.server') - return handleFiles(request, 'bot-drafts', params.id) - }, - PUT: async ({ request, params }) => { - const { handleFiles } = await import('~/chat/server/file-http.server') - return handleFiles(request, 'bot-drafts', params.id) - }, - DELETE: async ({ request, params }) => { - const { handleFiles } = await import('~/chat/server/file-http.server') - return handleFiles(request, 'bot-drafts', params.id) - }, - }, -) diff --git a/src/chat/server/http/api/chat/bot-drafts/$id.ts b/src/chat/server/http/api/chat/bot-drafts/$id.ts deleted file mode 100644 index 6a0a79793..000000000 --- a/src/chat/server/http/api/chat/bot-drafts/$id.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute( - '/api/chat/bot-drafts/$id', - z.object({ id: z.string() }), - { - GET: async ({ request, params }) => { - const { handleBotDraft } = - await import('~/chat/server/bot-draft-http.server') - return handleBotDraft(request, params.id) - }, - POST: async ({ request, params }) => { - const { handleBotDraft } = - await import('~/chat/server/bot-draft-http.server') - return handleBotDraft(request, params.id) - }, - }, -) diff --git a/src/chat/server/http/api/chat/bots.ts b/src/chat/server/http/api/chat/bots.ts deleted file mode 100644 index 1a55c9ccf..000000000 --- a/src/chat/server/http/api/chat/bots.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute('/api/chat/bots', z.object({}), { - POST: async ({ request }) => { - const { handleBotMutation } = - await import('~/chat/server/bot-mutation-http.server') - return handleBotMutation(request) - }, -}) diff --git a/src/chat/server/http/api/chat/bots/$id.$operation.ts b/src/chat/server/http/api/chat/bots/$id.$operation.ts deleted file mode 100644 index 6c93adc69..000000000 --- a/src/chat/server/http/api/chat/bots/$id.$operation.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute( - '/api/chat/bots/$id/$operation', - z.object({ id: z.string(), operation: z.string() }), - { - POST: async ({ request, params }) => { - const { handleConversationCopy } = - await import('~/chat/server/conversation-copy-http.server') - const { handleConversationRead, handleConversationSend } = - await import('~/chat/server/conversation-http.server') - const { handleBotMutation } = - await import('~/chat/server/bot-mutation-http.server') - return params.operation === 'copies' - ? handleConversationCopy(request, params.id, 'bot') - : ['move', 'delete', 'restore'].includes(params.operation) - ? handleBotMutation(request, params.id, params.operation) - : handleConversationSend(request, params.id, params.operation, 'bot') - }, - PATCH: async ({ request, params }) => { - const { handleBotMutation } = - await import('~/chat/server/bot-mutation-http.server') - return handleBotMutation(request, params.id, params.operation) - }, - GET: async ({ request, params }) => { - const { handleConversationCopy } = - await import('~/chat/server/conversation-copy-http.server') - const { handleConversationRead, handleConversationSend } = - await import('~/chat/server/conversation-http.server') - return params.operation === 'copy-source' - ? handleConversationCopy(request, params.id, 'bot', true) - : handleConversationRead(request, params.id, params.operation, 'bot') - }, - }, -) diff --git a/src/chat/server/http/api/chat/bots/$id.files.$fileId.content.ts b/src/chat/server/http/api/chat/bots/$id.files.$fileId.content.ts deleted file mode 100644 index 876340572..000000000 --- a/src/chat/server/http/api/chat/bots/$id.files.$fileId.content.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute( - '/api/chat/bots/$id/files/$fileId/content', - z.object({ id: z.string(), fileId: z.string() }), - { - GET: async ({ request, params }) => { - const { handleFiles } = await import('~/chat/server/file-http.server') - return handleFiles(request, 'bots', params.id, params.fileId, true) - }, - }, -) diff --git a/src/chat/server/http/api/chat/bots/$id.files.$fileId.ts b/src/chat/server/http/api/chat/bots/$id.files.$fileId.ts deleted file mode 100644 index 60cd68f7c..000000000 --- a/src/chat/server/http/api/chat/bots/$id.files.$fileId.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute( - '/api/chat/bots/$id/files/$fileId', - z.object({ id: z.string(), fileId: z.string() }), - { - GET: async ({ request, params }) => { - const { handleFiles } = await import('~/chat/server/file-http.server') - return handleFiles(request, 'bots', params.id, params.fileId) - }, - POST: async ({ request, params }) => { - const { handleFiles } = await import('~/chat/server/file-http.server') - return handleFiles(request, 'bots', params.id, params.fileId) - }, - PUT: async ({ request, params }) => { - const { handleFiles } = await import('~/chat/server/file-http.server') - return handleFiles(request, 'bots', params.id, params.fileId) - }, - DELETE: async ({ request, params }) => { - const { handleFiles } = await import('~/chat/server/file-http.server') - return handleFiles(request, 'bots', params.id, params.fileId) - }, - }, -) diff --git a/src/chat/server/http/api/chat/bots/$id.files.ts b/src/chat/server/http/api/chat/bots/$id.files.ts deleted file mode 100644 index afc646c59..000000000 --- a/src/chat/server/http/api/chat/bots/$id.files.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute( - '/api/chat/bots/$id/files', - z.object({ id: z.string() }), - { - GET: async ({ request, params }) => { - const { handleFiles } = await import('~/chat/server/file-http.server') - return handleFiles(request, 'bots', params.id) - }, - POST: async ({ request, params }) => { - const { handleFiles } = await import('~/chat/server/file-http.server') - return handleFiles(request, 'bots', params.id) - }, - PUT: async ({ request, params }) => { - const { handleFiles } = await import('~/chat/server/file-http.server') - return handleFiles(request, 'bots', params.id) - }, - DELETE: async ({ request, params }) => { - const { handleFiles } = await import('~/chat/server/file-http.server') - return handleFiles(request, 'bots', params.id) - }, - }, -) diff --git a/src/chat/server/http/api/chat/bots/$id.ts b/src/chat/server/http/api/chat/bots/$id.ts deleted file mode 100644 index 7fd5db52d..000000000 --- a/src/chat/server/http/api/chat/bots/$id.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute( - '/api/chat/bots/$id', - z.object({ id: z.string() }), - { - PATCH: async ({ request, params }) => { - const { handleBotMutation } = - await import('~/chat/server/bot-mutation-http.server') - return handleBotMutation(request, params.id) - }, - }, -) diff --git a/src/chat/server/http/api/chat/bots/bulk.ts b/src/chat/server/http/api/chat/bots/bulk.ts deleted file mode 100644 index 9707666bc..000000000 --- a/src/chat/server/http/api/chat/bots/bulk.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute('/api/chat/bots/bulk', z.object({}), { - POST: async ({ request }) => { - const { handleBotMutation } = - await import('~/chat/server/bot-mutation-http.server') - return handleBotMutation(request, undefined, undefined, 'bulk') - }, -}) diff --git a/src/chat/server/http/api/chat/bots/move.ts b/src/chat/server/http/api/chat/bots/move.ts deleted file mode 100644 index fe12c92c6..000000000 --- a/src/chat/server/http/api/chat/bots/move.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute('/api/chat/bots/move', z.object({}), { - POST: async ({ request }) => { - const { handleBotMutation } = - await import('~/chat/server/bot-mutation-http.server') - return handleBotMutation(request, undefined, undefined, 'move') - }, -}) diff --git a/src/chat/server/http/api/chat/connection.ts b/src/chat/server/http/api/chat/connection.ts deleted file mode 100644 index bba43b097..000000000 --- a/src/chat/server/http/api/chat/connection.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute('/api/chat/connection', z.object({}), { - POST: async ({ request }) => { - const { handleProviderConnection } = - await import('~/chat/server/provider-connection-http.server') - return handleProviderConnection(request) - }, -}) diff --git a/src/chat/server/http/api/chat/conversations/$id.$operation.ts b/src/chat/server/http/api/chat/conversations/$id.$operation.ts deleted file mode 100644 index 3d2023ddf..000000000 --- a/src/chat/server/http/api/chat/conversations/$id.$operation.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute( - '/api/chat/conversations/$id/$operation', - z.object({ id: z.string(), operation: z.string() }), - { - POST: async ({ request, params }) => { - const { handleConversationRetry } = - await import('~/chat/server/conversation-retry-http.server') - const { handleConversationCopy } = - await import('~/chat/server/conversation-copy-http.server') - const { handleWorkflowRun } = - await import('~/chat/server/workflow-run-http.server') - const { handleWorkflow } = - await import('~/chat/server/workflow-http.server') - const { handleConversationExecution } = - await import('~/chat/server/conversation-execution-http.server') - const { handleConversationSend } = - await import('~/chat/server/conversation-http.server') - const { handleConversationThreads } = - await import('~/chat/server/conversation-threads-http.server') - return params.operation === 'retries' - ? handleConversationRetry(request, params.id, 'create') - : params.operation === 'copies' - ? handleConversationCopy(request, params.id, 'conversation') - : params.operation === 'workflow-runs' - ? handleWorkflowRun(request, params.id) - : params.operation === 'workflows' - ? handleWorkflow(request, params.id) - : params.operation === 'execution' - ? handleConversationExecution(request, params.id) - : ['thread', 'threads'].includes(params.operation) - ? handleConversationThreads( - request, - params.id, - params.operation, - ) - : handleConversationSend(request, params.id, params.operation) - }, - DELETE: async ({ request, params }) => { - const { handleConversationThreads } = - await import('~/chat/server/conversation-threads-http.server') - return handleConversationThreads(request, params.id, params.operation) - }, - GET: async ({ request, params }) => { - const { handleConversationCopy } = - await import('~/chat/server/conversation-copy-http.server') - const { handleWorkflowRun } = - await import('~/chat/server/workflow-run-http.server') - const { handleWorkflow } = - await import('~/chat/server/workflow-http.server') - const { handleConversationExecution } = - await import('~/chat/server/conversation-execution-http.server') - const { handleConversationRead } = - await import('~/chat/server/conversation-http.server') - const { handleConversationThreads } = - await import('~/chat/server/conversation-threads-http.server') - return params.operation === 'copy-source' - ? handleConversationCopy(request, params.id, 'conversation', true) - : params.operation === 'workflow-runs' - ? handleWorkflowRun(request, params.id) - : params.operation === 'workflows' - ? handleWorkflow(request, params.id) - : params.operation === 'execution' - ? handleConversationExecution(request, params.id) - : ['thread', 'threads'].includes(params.operation) - ? handleConversationThreads( - request, - params.id, - params.operation, - ) - : handleConversationRead(request, params.id, params.operation) - }, - }, -) diff --git a/src/chat/server/http/api/chat/conversations/$id.execution.snapshots.$snapshotId.ts b/src/chat/server/http/api/chat/conversations/$id.execution.snapshots.$snapshotId.ts deleted file mode 100644 index ddec23f55..000000000 --- a/src/chat/server/http/api/chat/conversations/$id.execution.snapshots.$snapshotId.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute( - '/api/chat/conversations/$id/execution/snapshots/$snapshotId', - z.object({ id: z.string(), snapshotId: z.string() }), - { - GET: async ({ request, params }) => { - const { handleConversationExecution } = - await import('~/chat/server/conversation-execution-http.server') - return handleConversationExecution(request, params.id, params.snapshotId) - }, - PUT: async ({ request, params }) => { - const { handleConversationExecution } = - await import('~/chat/server/conversation-execution-http.server') - return handleConversationExecution(request, params.id, params.snapshotId) - }, - }, -) diff --git a/src/chat/server/http/api/chat/conversations/$id.files.$fileId.content.ts b/src/chat/server/http/api/chat/conversations/$id.files.$fileId.content.ts deleted file mode 100644 index d2d17b55b..000000000 --- a/src/chat/server/http/api/chat/conversations/$id.files.$fileId.content.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute( - '/api/chat/conversations/$id/files/$fileId/content', - z.object({ id: z.string(), fileId: z.string() }), - { - GET: async ({ request, params }) => { - const { handleFiles } = await import('~/chat/server/file-http.server') - return handleFiles( - request, - 'conversations', - params.id, - params.fileId, - true, - ) - }, - }, -) diff --git a/src/chat/server/http/api/chat/conversations/$id.files.$fileId.ts b/src/chat/server/http/api/chat/conversations/$id.files.$fileId.ts deleted file mode 100644 index c475ca668..000000000 --- a/src/chat/server/http/api/chat/conversations/$id.files.$fileId.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute( - '/api/chat/conversations/$id/files/$fileId', - z.object({ id: z.string(), fileId: z.string() }), - { - GET: async ({ request, params }) => { - const { handleFiles } = await import('~/chat/server/file-http.server') - return handleFiles(request, 'conversations', params.id, params.fileId) - }, - POST: async ({ request, params }) => { - const { handleFiles } = await import('~/chat/server/file-http.server') - return handleFiles(request, 'conversations', params.id, params.fileId) - }, - PUT: async ({ request, params }) => { - const { handleFiles } = await import('~/chat/server/file-http.server') - return handleFiles(request, 'conversations', params.id, params.fileId) - }, - DELETE: async ({ request, params }) => { - const { handleFiles } = await import('~/chat/server/file-http.server') - return handleFiles(request, 'conversations', params.id, params.fileId) - }, - }, -) diff --git a/src/chat/server/http/api/chat/conversations/$id.files.ts b/src/chat/server/http/api/chat/conversations/$id.files.ts deleted file mode 100644 index aca249c62..000000000 --- a/src/chat/server/http/api/chat/conversations/$id.files.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute( - '/api/chat/conversations/$id/files', - z.object({ id: z.string() }), - { - GET: async ({ request, params }) => { - const { handleFiles } = await import('~/chat/server/file-http.server') - return handleFiles(request, 'conversations', params.id) - }, - POST: async ({ request, params }) => { - const { handleFiles } = await import('~/chat/server/file-http.server') - return handleFiles(request, 'conversations', params.id) - }, - PUT: async ({ request, params }) => { - const { handleFiles } = await import('~/chat/server/file-http.server') - return handleFiles(request, 'conversations', params.id) - }, - DELETE: async ({ request, params }) => { - const { handleFiles } = await import('~/chat/server/file-http.server') - return handleFiles(request, 'conversations', params.id) - }, - }, -) diff --git a/src/chat/server/http/api/chat/conversations/$id.workflow-runs.$runId.cancel.ts b/src/chat/server/http/api/chat/conversations/$id.workflow-runs.$runId.cancel.ts deleted file mode 100644 index 84bff5079..000000000 --- a/src/chat/server/http/api/chat/conversations/$id.workflow-runs.$runId.cancel.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute( - '/api/chat/conversations/$id/workflow-runs/$runId/cancel', - z.object({ id: z.string(), runId: z.string() }), - { - POST: async ({ request, params }) => { - const { handleWorkflowRun } = - await import('~/chat/server/workflow-run-http.server') - return handleWorkflowRun(request, params.id, params.runId, true) - }, - }, -) diff --git a/src/chat/server/http/api/chat/conversations/$id.workflow-runs.$runId.ts b/src/chat/server/http/api/chat/conversations/$id.workflow-runs.$runId.ts deleted file mode 100644 index 2f5156c6b..000000000 --- a/src/chat/server/http/api/chat/conversations/$id.workflow-runs.$runId.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute( - '/api/chat/conversations/$id/workflow-runs/$runId', - z.object({ id: z.string(), runId: z.string() }), - { - GET: async ({ request, params }) => { - const { handleWorkflowRun } = - await import('~/chat/server/workflow-run-http.server') - return handleWorkflowRun(request, params.id, params.runId) - }, - POST: async ({ request, params }) => { - const { handleWorkflowRun } = - await import('~/chat/server/workflow-run-http.server') - return handleWorkflowRun(request, params.id, params.runId) - }, - }, -) diff --git a/src/chat/server/http/api/chat/conversations/$id.workflows.$workflowId.ts b/src/chat/server/http/api/chat/conversations/$id.workflows.$workflowId.ts deleted file mode 100644 index 095de1225..000000000 --- a/src/chat/server/http/api/chat/conversations/$id.workflows.$workflowId.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute( - '/api/chat/conversations/$id/workflows/$workflowId', - z.object({ id: z.string(), workflowId: z.string() }), - { - GET: async ({ request, params }) => { - const { handleWorkflow } = - await import('~/chat/server/workflow-http.server') - return handleWorkflow(request, params.id, params.workflowId) - }, - }, -) diff --git a/src/chat/server/http/api/chat/conversations/$id/files/import.ts b/src/chat/server/http/api/chat/conversations/$id/files/import.ts deleted file mode 100644 index 0eacc17fc..000000000 --- a/src/chat/server/http/api/chat/conversations/$id/files/import.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute( - '/api/chat/conversations/$id/files/import', - z.object({ id: z.string() }), - { - POST: async ({ request, params }) => { - const { handleFileImport } = - await import('~/chat/server/file-http.server') - return handleFileImport(request, params.id) - }, - }, -) diff --git a/src/chat/server/http/api/chat/conversations/$id/memories.ts b/src/chat/server/http/api/chat/conversations/$id/memories.ts deleted file mode 100644 index be02e94a0..000000000 --- a/src/chat/server/http/api/chat/conversations/$id/memories.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute( - '/api/chat/conversations/$id/memories', - z.object({ id: z.string() }), - { - GET: async ({ request, params }) => { - const { handleMemory } = await import('~/chat/server/memory-http.server') - return handleMemory(request, params.id) - }, - POST: async ({ request, params }) => { - const { handleMemory } = await import('~/chat/server/memory-http.server') - return handleMemory(request, params.id) - }, - }, -) diff --git a/src/chat/server/http/api/chat/conversations/$id/memories/$memoryId.ts b/src/chat/server/http/api/chat/conversations/$id/memories/$memoryId.ts deleted file mode 100644 index 6902b2362..000000000 --- a/src/chat/server/http/api/chat/conversations/$id/memories/$memoryId.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute( - '/api/chat/conversations/$id/memories/$memoryId', - z.object({ id: z.string(), memoryId: z.string() }), - { - GET: async ({ request, params }) => { - const { handleMemory } = await import('~/chat/server/memory-http.server') - return handleMemory(request, params.id, params.memoryId) - }, - POST: async ({ request, params }) => { - const { handleMemory } = await import('~/chat/server/memory-http.server') - return handleMemory(request, params.id, params.memoryId) - }, - }, -) diff --git a/src/chat/server/http/api/chat/conversations/$id/references.ts b/src/chat/server/http/api/chat/conversations/$id/references.ts deleted file mode 100644 index 47f64cd29..000000000 --- a/src/chat/server/http/api/chat/conversations/$id/references.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute( - '/api/chat/conversations/$id/references', - z.object({ id: z.string() }), - { - GET: async ({ request, params }) => { - const { handleReferences } = - await import('~/chat/server/reference-http.server') - return handleReferences(request, params.id) - }, - }, -) diff --git a/src/chat/server/http/api/chat/copies/$id.ts b/src/chat/server/http/api/chat/copies/$id.ts deleted file mode 100644 index cd877d0b5..000000000 --- a/src/chat/server/http/api/chat/copies/$id.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute( - '/api/chat/copies/$id', - z.object({ id: z.string() }), - { - GET: async ({ request, params }) => { - const { handleConversationCopy } = - await import('~/chat/server/conversation-copy-http.server') - return handleConversationCopy(request, params.id, 'operation') - }, - }, -) diff --git a/src/chat/server/http/api/chat/device-transport.ts b/src/chat/server/http/api/chat/device-transport.ts deleted file mode 100644 index 1830716d9..000000000 --- a/src/chat/server/http/api/chat/device-transport.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute('/api/chat/device-transport', z.object({}), { - POST: async ({ request }) => { - const { handleDeviceTransport } = - await import('~/chat/server/device-http.server') - return handleDeviceTransport(request) - }, -}) diff --git a/src/chat/server/http/api/chat/draft.ts b/src/chat/server/http/api/chat/draft.ts deleted file mode 100644 index a8017512d..000000000 --- a/src/chat/server/http/api/chat/draft.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute('/api/chat/draft', z.object({}), { - GET: async (context) => { - const { handlers } = await import('~/chat/server/routes/draft') - return handlers.GET(context) - }, - POST: async (context) => { - const { handlers } = await import('~/chat/server/routes/draft') - return handlers.POST(context) - }, -}) diff --git a/src/chat/server/http/api/chat/files.ts b/src/chat/server/http/api/chat/files.ts deleted file mode 100644 index 3c95bab6b..000000000 --- a/src/chat/server/http/api/chat/files.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute('/api/chat/files', z.object({}), { - GET: async (context) => { - const { handlers } = await import('~/chat/server/routes/files') - return handlers.GET(context) - }, - PUT: async (context) => { - const { handlers } = await import('~/chat/server/routes/files') - return handlers.PUT(context) - }, -}) diff --git a/src/chat/server/http/api/chat/kody/account.ts b/src/chat/server/http/api/chat/kody/account.ts deleted file mode 100644 index 2d7f625e5..000000000 --- a/src/chat/server/http/api/chat/kody/account.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute('/api/chat/kody/account', z.object({}), { - GET: async ({ request }) => { - const { handleKodyAccount } = - await import('~/chat/server/kody-account-http.server') - return handleKodyAccount(request, 'account') - }, -}) diff --git a/src/chat/server/http/api/chat/kody/callback.ts b/src/chat/server/http/api/chat/kody/callback.ts deleted file mode 100644 index 365bfe836..000000000 --- a/src/chat/server/http/api/chat/kody/callback.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute('/api/chat/kody/callback', z.object({}), { - GET: async ({ request }) => { - const { handleKodyCallback } = - await import('~/chat/server/kody-callback-http.server') - return handleKodyCallback(request) - }, -}) diff --git a/src/chat/server/http/api/chat/kody/community.ts b/src/chat/server/http/api/chat/kody/community.ts deleted file mode 100644 index b5a97765a..000000000 --- a/src/chat/server/http/api/chat/kody/community.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute('/api/chat/kody/community', z.object({}), { - GET: async ({ request }) => { - const { handleKodyAccount } = - await import('~/chat/server/kody-account-http.server') - return handleKodyAccount(request, 'community') - }, -}) diff --git a/src/chat/server/http/api/chat/kody/community/$listingId.ts b/src/chat/server/http/api/chat/kody/community/$listingId.ts deleted file mode 100644 index e3f1566f5..000000000 --- a/src/chat/server/http/api/chat/kody/community/$listingId.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute( - '/api/chat/kody/community/$listingId', - z.object({ listingId: z.string() }), - { - GET: async ({ request, params }) => { - const { handleKodyAccount } = - await import('~/chat/server/kody-account-http.server') - return handleKodyAccount(request, 'community', params.listingId) - }, - }, -) diff --git a/src/chat/server/http/api/chat/kody/connect.ts b/src/chat/server/http/api/chat/kody/connect.ts deleted file mode 100644 index 4616b63de..000000000 --- a/src/chat/server/http/api/chat/kody/connect.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute('/api/chat/kody/connect', z.object({}), { - POST: async ({ request }) => { - const { handleKodyConnect } = - await import('~/chat/server/kody-connect-http.server') - return handleKodyConnect(request) - }, -}) diff --git a/src/chat/server/http/api/chat/kody/jobs/$jobId/enabled.ts b/src/chat/server/http/api/chat/kody/jobs/$jobId/enabled.ts deleted file mode 100644 index 75531af4d..000000000 --- a/src/chat/server/http/api/chat/kody/jobs/$jobId/enabled.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute( - '/api/chat/kody/jobs/$jobId/enabled', - z.object({ jobId: z.string() }), - { - POST: async ({ request, params }) => { - const { handleKodyControl } = - await import('~/chat/server/kody-control-http.server') - return handleKodyControl(request, 'job-enabled', params.jobId) - }, - }, -) diff --git a/src/chat/server/http/api/chat/kody/mail/inboxes.ts b/src/chat/server/http/api/chat/kody/mail/inboxes.ts deleted file mode 100644 index 029690b66..000000000 --- a/src/chat/server/http/api/chat/kody/mail/inboxes.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute('/api/chat/kody/mail/inboxes', z.object({}), { - GET: async ({ request }) => { - const { handleKodyAccount } = - await import('~/chat/server/kody-account-http.server') - return handleKodyAccount(request, 'mail-inboxes') - }, -}) diff --git a/src/chat/server/http/api/chat/kody/mail/messages.ts b/src/chat/server/http/api/chat/kody/mail/messages.ts deleted file mode 100644 index 05d5ef9cf..000000000 --- a/src/chat/server/http/api/chat/kody/mail/messages.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute('/api/chat/kody/mail/messages', z.object({}), { - GET: async ({ request }) => { - const { handleKodyAccount } = - await import('~/chat/server/kody-account-http.server') - return handleKodyAccount(request, 'mail-messages') - }, -}) diff --git a/src/chat/server/http/api/chat/kody/mail/messages/$messageId.ts b/src/chat/server/http/api/chat/kody/mail/messages/$messageId.ts deleted file mode 100644 index bf54e1ab4..000000000 --- a/src/chat/server/http/api/chat/kody/mail/messages/$messageId.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute( - '/api/chat/kody/mail/messages/$messageId', - z.object({ messageId: z.string() }), - { - GET: async ({ request, params }) => { - const { handleKodyAccount } = - await import('~/chat/server/kody-account-http.server') - return handleKodyAccount(request, 'mail-messages', params.messageId) - }, - }, -) diff --git a/src/chat/server/http/api/chat/kody/memories.ts b/src/chat/server/http/api/chat/kody/memories.ts deleted file mode 100644 index 46cdfbb08..000000000 --- a/src/chat/server/http/api/chat/kody/memories.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute('/api/chat/kody/memories', z.object({}), { - GET: async ({ request }) => { - const { handleKodyAccount } = - await import('~/chat/server/kody-account-http.server') - return handleKodyAccount(request, 'memories') - }, -}) diff --git a/src/chat/server/http/api/chat/kody/memories/$memoryId.ts b/src/chat/server/http/api/chat/kody/memories/$memoryId.ts deleted file mode 100644 index 9451dd1b6..000000000 --- a/src/chat/server/http/api/chat/kody/memories/$memoryId.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute( - '/api/chat/kody/memories/$memoryId', - z.object({ memoryId: z.string() }), - { - GET: async ({ request, params }) => { - const { handleKodyAccount } = - await import('~/chat/server/kody-account-http.server') - return handleKodyAccount(request, 'memories', params.memoryId) - }, - }, -) diff --git a/src/chat/server/http/api/chat/kody/memories/$memoryId/apply.ts b/src/chat/server/http/api/chat/kody/memories/$memoryId/apply.ts deleted file mode 100644 index 00e53252e..000000000 --- a/src/chat/server/http/api/chat/kody/memories/$memoryId/apply.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute( - '/api/chat/kody/memories/$memoryId/apply', - z.object({ memoryId: z.string() }), - { - POST: async ({ request, params }) => { - const { handleKodyMemoryMutation } = - await import('~/chat/server/kody-memory-http.server') - return handleKodyMemoryMutation(request, 'apply', params.memoryId) - }, - }, -) diff --git a/src/chat/server/http/api/chat/kody/memories/$memoryId/review.ts b/src/chat/server/http/api/chat/kody/memories/$memoryId/review.ts deleted file mode 100644 index acaa93058..000000000 --- a/src/chat/server/http/api/chat/kody/memories/$memoryId/review.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute( - '/api/chat/kody/memories/$memoryId/review', - z.object({ memoryId: z.string() }), - { - POST: async ({ request, params }) => { - const { handleKodyMemoryMutation } = - await import('~/chat/server/kody-memory-http.server') - return handleKodyMemoryMutation(request, 'review', params.memoryId) - }, - }, -) diff --git a/src/chat/server/http/api/chat/kody/memories/create/apply.ts b/src/chat/server/http/api/chat/kody/memories/create/apply.ts deleted file mode 100644 index 68a6d65cf..000000000 --- a/src/chat/server/http/api/chat/kody/memories/create/apply.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute( - '/api/chat/kody/memories/create/apply', - z.object({}), - { - POST: async ({ request }) => { - const { handleKodyMemoryMutation } = - await import('~/chat/server/kody-memory-http.server') - return handleKodyMemoryMutation(request, 'apply') - }, - }, -) diff --git a/src/chat/server/http/api/chat/kody/memories/create/review.ts b/src/chat/server/http/api/chat/kody/memories/create/review.ts deleted file mode 100644 index 339d0c4a1..000000000 --- a/src/chat/server/http/api/chat/kody/memories/create/review.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute( - '/api/chat/kody/memories/create/review', - z.object({}), - { - POST: async ({ request }) => { - const { handleKodyMemoryMutation } = - await import('~/chat/server/kody-memory-http.server') - return handleKodyMemoryMutation(request, 'review') - }, - }, -) diff --git a/src/chat/server/http/api/chat/kody/packages/$packageId/document.ts b/src/chat/server/http/api/chat/kody/packages/$packageId/document.ts deleted file mode 100644 index 97e50fbab..000000000 --- a/src/chat/server/http/api/chat/kody/packages/$packageId/document.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute( - '/api/chat/kody/packages/$packageId/document', - z.object({ packageId: z.string() }), - { - GET: async ({ request, params }) => { - const { handleKodyAccount } = - await import('~/chat/server/kody-account-http.server') - return handleKodyAccount(request, 'package-document', params.packageId) - }, - }, -) diff --git a/src/chat/server/http/api/chat/kody/resources/$kind.ts b/src/chat/server/http/api/chat/kody/resources/$kind.ts deleted file mode 100644 index c887590ca..000000000 --- a/src/chat/server/http/api/chat/kody/resources/$kind.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute( - '/api/chat/kody/resources/$kind', - z.object({ kind: z.string() }), - { - GET: async ({ request, params }) => { - const { handleKodyAccount } = - await import('~/chat/server/kody-account-http.server') - return handleKodyAccount(request, 'resources', params.kind) - }, - }, -) diff --git a/src/chat/server/http/api/chat/kody/runs.ts b/src/chat/server/http/api/chat/kody/runs.ts deleted file mode 100644 index d4291380e..000000000 --- a/src/chat/server/http/api/chat/kody/runs.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute('/api/chat/kody/runs', z.object({}), { - GET: async ({ request }) => { - const { handleKodyAccount } = - await import('~/chat/server/kody-account-http.server') - return handleKodyAccount(request, 'runs') - }, -}) diff --git a/src/chat/server/http/api/chat/kody/runs/$runId.ts b/src/chat/server/http/api/chat/kody/runs/$runId.ts deleted file mode 100644 index 036631c3a..000000000 --- a/src/chat/server/http/api/chat/kody/runs/$runId.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute( - '/api/chat/kody/runs/$runId', - z.object({ runId: z.string() }), - { - GET: async ({ request, params }) => { - const { handleKodyAccount } = - await import('~/chat/server/kody-account-http.server') - return handleKodyAccount(request, 'runs', params.runId) - }, - }, -) diff --git a/src/chat/server/http/api/chat/kody/runs/$runId/triage.ts b/src/chat/server/http/api/chat/kody/runs/$runId/triage.ts deleted file mode 100644 index cd7ddbb9b..000000000 --- a/src/chat/server/http/api/chat/kody/runs/$runId/triage.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute( - '/api/chat/kody/runs/$runId/triage', - z.object({ runId: z.string() }), - { - POST: async ({ request, params }) => { - const { handleKodyControl } = - await import('~/chat/server/kody-control-http.server') - return handleKodyControl(request, 'run-triage', params.runId) - }, - }, -) diff --git a/src/chat/server/http/api/chat/kody/servers.ts b/src/chat/server/http/api/chat/kody/servers.ts deleted file mode 100644 index fab8c3b83..000000000 --- a/src/chat/server/http/api/chat/kody/servers.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute('/api/chat/kody/servers', z.object({}), { - POST: async ({ request }) => { - const { handleKodyControl } = - await import('~/chat/server/kody-control-http.server') - return handleKodyControl(request, 'server-add') - }, -}) diff --git a/src/chat/server/http/api/chat/kody/servers/$serverId/check.ts b/src/chat/server/http/api/chat/kody/servers/$serverId/check.ts deleted file mode 100644 index 87a7a3a11..000000000 --- a/src/chat/server/http/api/chat/kody/servers/$serverId/check.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute( - '/api/chat/kody/servers/$serverId/check', - z.object({ serverId: z.string() }), - { - POST: async ({ request, params }) => { - const { handleKodyControl } = - await import('~/chat/server/kody-control-http.server') - return handleKodyControl(request, 'server-check', params.serverId) - }, - }, -) diff --git a/src/chat/server/http/api/chat/kody/servers/$serverId/enabled.ts b/src/chat/server/http/api/chat/kody/servers/$serverId/enabled.ts deleted file mode 100644 index a0aa45371..000000000 --- a/src/chat/server/http/api/chat/kody/servers/$serverId/enabled.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute( - '/api/chat/kody/servers/$serverId/enabled', - z.object({ serverId: z.string() }), - { - POST: async ({ request, params }) => { - const { handleKodyControl } = - await import('~/chat/server/kody-control-http.server') - return handleKodyControl(request, 'server-enabled', params.serverId) - }, - }, -) diff --git a/src/chat/server/http/api/chat/kody/servers/$serverId/reconnect.ts b/src/chat/server/http/api/chat/kody/servers/$serverId/reconnect.ts deleted file mode 100644 index 3db15a2de..000000000 --- a/src/chat/server/http/api/chat/kody/servers/$serverId/reconnect.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute( - '/api/chat/kody/servers/$serverId/reconnect', - z.object({ serverId: z.string() }), - { - POST: async ({ request, params }) => { - const { handleKodyControl } = - await import('~/chat/server/kody-control-http.server') - return handleKodyControl(request, 'server-reconnect', params.serverId) - }, - }, -) diff --git a/src/chat/server/http/api/chat/kody/sync.ts b/src/chat/server/http/api/chat/kody/sync.ts deleted file mode 100644 index 383c5dda7..000000000 --- a/src/chat/server/http/api/chat/kody/sync.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute('/api/chat/kody/sync', z.object({}), { - POST: async ({ request }) => { - const { handleKodyAccount } = - await import('~/chat/server/kody-account-http.server') - return handleKodyAccount(request, 'sync') - }, -}) diff --git a/src/chat/server/http/api/chat/kody/unlink.ts b/src/chat/server/http/api/chat/kody/unlink.ts deleted file mode 100644 index cfec8a12c..000000000 --- a/src/chat/server/http/api/chat/kody/unlink.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute('/api/chat/kody/unlink', z.object({}), { - POST: async ({ request }) => { - const { handleKodyUnlink } = - await import('~/chat/server/kody-unlink-http.server') - return handleKodyUnlink(request) - }, -}) diff --git a/src/chat/server/http/api/chat/kody/usage.ts b/src/chat/server/http/api/chat/kody/usage.ts deleted file mode 100644 index 98e825768..000000000 --- a/src/chat/server/http/api/chat/kody/usage.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute('/api/chat/kody/usage', z.object({}), { - GET: async ({ request }) => { - const { handleKodyAccount } = - await import('~/chat/server/kody-account-http.server') - return handleKodyAccount(request, 'usage') - }, -}) diff --git a/src/chat/server/http/api/chat/mcp/$.ts b/src/chat/server/http/api/chat/mcp/$.ts deleted file mode 100644 index 7b43177ab..000000000 --- a/src/chat/server/http/api/chat/mcp/$.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute( - '/api/chat/mcp/$', - z.object({ _splat: z.string() }), - { - GET: async (context) => { - const { handlers } = await import('~/chat/server/routes/mcp/$') - return handlers.GET(context) - }, - POST: async (context) => { - const { handlers } = await import('~/chat/server/routes/mcp/$') - return handlers.POST(context) - }, - }, -) diff --git a/src/chat/server/http/api/chat/mcp/contract.ts b/src/chat/server/http/api/chat/mcp/contract.ts deleted file mode 100644 index e7e4ab1b7..000000000 --- a/src/chat/server/http/api/chat/mcp/contract.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute('/api/chat/mcp/contract', z.object({}), { - GET: async ({ request }) => { - const { handleReferenceCatalog } = - await import('~/chat/server/reference-catalog-http.server') - return handleReferenceCatalog(request, 'mcp-contract') - }, -}) diff --git a/src/chat/server/http/api/chat/model-options.ts b/src/chat/server/http/api/chat/model-options.ts deleted file mode 100644 index a3705095a..000000000 --- a/src/chat/server/http/api/chat/model-options.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute('/api/chat/model-options', z.object({}), { - GET: async ({ request }) => { - const { handleModelOptions } = - await import('~/chat/server/model-options-http.server') - return handleModelOptions(request) - }, -}) diff --git a/src/chat/server/http/api/chat/models.ts b/src/chat/server/http/api/chat/models.ts deleted file mode 100644 index f440245e9..000000000 --- a/src/chat/server/http/api/chat/models.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute('/api/chat/models', z.object({}), { - GET: async (context) => { - const { handlers } = await import('~/chat/server/routes/models') - return handlers.GET(context) - }, -}) diff --git a/src/chat/server/http/api/chat/openrouter/callback.ts b/src/chat/server/http/api/chat/openrouter/callback.ts deleted file mode 100644 index e68b87720..000000000 --- a/src/chat/server/http/api/chat/openrouter/callback.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute('/api/chat/openrouter/callback', z.object({}), { - GET: async () => { - const { handlers } = - await import('~/chat/server/routes/openrouter/callback') - return handlers.GET() - }, -}) diff --git a/src/chat/server/http/api/chat/plugins.ts b/src/chat/server/http/api/chat/plugins.ts deleted file mode 100644 index 8136ce374..000000000 --- a/src/chat/server/http/api/chat/plugins.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute('/api/chat/plugins', z.object({}), { - GET: async (context) => { - const { handlers } = await import('~/chat/server/routes/plugins') - return handlers.GET(context) - }, - POST: async (context) => { - const { handlers } = await import('~/chat/server/routes/plugins') - return handlers.POST(context) - }, -}) diff --git a/src/chat/server/http/api/chat/plugins/$id.ts b/src/chat/server/http/api/chat/plugins/$id.ts deleted file mode 100644 index ef8ac1b8c..000000000 --- a/src/chat/server/http/api/chat/plugins/$id.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute( - '/api/chat/plugins/$id', - z.object({ id: z.string() }), - { - GET: async ({ request, params }) => { - const { handlePlugins } = await import('~/chat/server/routes/plugins') - return handlePlugins(request, params.id) - }, - POST: async ({ request, params }) => { - const { handlePlugins } = await import('~/chat/server/routes/plugins') - return handlePlugins(request, params.id) - }, - }, -) diff --git a/src/chat/server/http/api/chat/policy.ts b/src/chat/server/http/api/chat/policy.ts deleted file mode 100644 index 0d08125d5..000000000 --- a/src/chat/server/http/api/chat/policy.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute('/api/chat/policy', z.object({}), { - POST: async ({ request }) => { - const { handleWorkspacePolicy } = - await import('~/chat/server/workspace-policy-http.server') - return handleWorkspacePolicy(request) - }, -}) diff --git a/src/chat/server/http/api/chat/project-snapshots.$hash.quarantine.ts b/src/chat/server/http/api/chat/project-snapshots.$hash.quarantine.ts deleted file mode 100644 index fe0e7178e..000000000 --- a/src/chat/server/http/api/chat/project-snapshots.$hash.quarantine.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute( - '/api/chat/project-snapshots/$hash/quarantine', - z.object({ hash: z.string() }), - { - POST: async (context) => { - const { handlers } = - await import('~/chat/server/routes/project-snapshots.$hash.quarantine') - return handlers.POST({ - request: context.request, - params: { hash: context.params.hash }, - }) - }, - }, -) diff --git a/src/chat/server/http/api/chat/project-snapshots.$hash.ts b/src/chat/server/http/api/chat/project-snapshots.$hash.ts deleted file mode 100644 index 3b93a7d9a..000000000 --- a/src/chat/server/http/api/chat/project-snapshots.$hash.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute( - '/api/chat/project-snapshots/$hash', - z.object({ hash: z.string() }), - { - GET: async ({ params }) => { - const { jsonError } = await import('~/utils/api-boundary.server') - const { - getBuilderProjectSnapshotCacheTag, - getBuilderProjectSnapshotObject, - isBuilderProjectSnapshotHash, - BuilderProjectSnapshotStorageUnavailableError, - } = await import('~/utils/builder-project-snapshot-storage.server') - - if (!isBuilderProjectSnapshotHash(params.hash)) { - return jsonError('Project snapshot not found', 404) - } - - try { - const object = await getBuilderProjectSnapshotObject(params.hash) - if (!object) return jsonError('Project snapshot not found', 404) - - const body = new Blob([await object.arrayBuffer()]) - .stream() - .pipeThrough(new DecompressionStream('gzip')) - - return new Response(body, { - headers: { - 'Cache-Control': 'public, max-age=300, must-revalidate', - 'Cache-Tag': getBuilderProjectSnapshotCacheTag(params.hash), - 'Cloudflare-CDN-Cache-Control': - 'public, max-age=31536000, immutable', - 'Content-Type': 'application/json; charset=utf-8', - ETag: `"${params.hash}"`, - }, - }) - } catch (error) { - if (error instanceof BuilderProjectSnapshotStorageUnavailableError) { - return jsonError('Project snapshot storage is unavailable', 503) - } - throw error - } - }, - }, -) diff --git a/src/chat/server/http/api/chat/project-snapshots.ts b/src/chat/server/http/api/chat/project-snapshots.ts deleted file mode 100644 index 96cb5a89c..000000000 --- a/src/chat/server/http/api/chat/project-snapshots.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute('/api/chat/project-snapshots', z.object({}), { - POST: async (context) => { - const { handlers } = await import('~/chat/server/routes/project-snapshots') - return handlers.POST(context) - }, -}) diff --git a/src/chat/server/http/api/chat/projects.$id.sync.ts b/src/chat/server/http/api/chat/projects.$id.sync.ts deleted file mode 100644 index eddd7e04e..000000000 --- a/src/chat/server/http/api/chat/projects.$id.sync.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute( - '/api/chat/projects/$id/sync', - z.object({ id: z.string() }), - { - GET: async (context) => { - const { handlers } = - await import('~/chat/server/routes/projects.$id.sync') - return handlers.GET({ - request: context.request, - params: { id: context.params.id }, - }) - }, - POST: async (context) => { - const { handlers } = - await import('~/chat/server/routes/projects.$id.sync') - return handlers.POST({ - request: context.request, - params: { id: context.params.id }, - }) - }, - }, -) diff --git a/src/chat/server/http/api/chat/projects.$id.ts b/src/chat/server/http/api/chat/projects.$id.ts deleted file mode 100644 index 1bbd14887..000000000 --- a/src/chat/server/http/api/chat/projects.$id.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute( - '/api/chat/projects/$id', - z.object({ id: z.string() }), - { - GET: async (context) => { - const { handlers } = await import('~/chat/server/routes/projects.$id') - return handlers.GET({ params: { id: context.params.id } }) - }, - PATCH: async (context) => { - const { handlers } = await import('~/chat/server/routes/projects.$id') - return handlers.PATCH({ - request: context.request, - params: { id: context.params.id }, - }) - }, - DELETE: async (context) => { - const { handlers } = await import('~/chat/server/routes/projects.$id') - return handlers.DELETE({ - request: context.request, - params: { id: context.params.id }, - }) - }, - }, -) diff --git a/src/chat/server/http/api/chat/projects.ts b/src/chat/server/http/api/chat/projects.ts deleted file mode 100644 index 33eca3961..000000000 --- a/src/chat/server/http/api/chat/projects.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute('/api/chat/projects', z.object({}), { - GET: async (context) => { - const { handlers } = await import('~/chat/server/routes/projects') - return handlers.GET(context) - }, - POST: async (context) => { - const { handlers } = await import('~/chat/server/routes/projects') - return handlers.POST(context) - }, -}) diff --git a/src/chat/server/http/api/chat/recipes.ts b/src/chat/server/http/api/chat/recipes.ts deleted file mode 100644 index 7947c374f..000000000 --- a/src/chat/server/http/api/chat/recipes.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute('/api/chat/recipes', z.object({}), { - POST: async ({ request }) => { - const { handleSavedActions } = - await import('~/chat/server/saved-actions-http.server') - return handleSavedActions(request) - }, -}) diff --git a/src/chat/server/http/api/chat/recipes/$id.ts b/src/chat/server/http/api/chat/recipes/$id.ts deleted file mode 100644 index 611fd07a5..000000000 --- a/src/chat/server/http/api/chat/recipes/$id.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute( - '/api/chat/recipes/$id', - z.object({ id: z.string() }), - { - DELETE: async ({ request, params }) => { - const { handleSavedActions } = - await import('~/chat/server/saved-actions-http.server') - return handleSavedActions(request, params.id) - }, - }, -) diff --git a/src/chat/server/http/api/chat/references.ts b/src/chat/server/http/api/chat/references.ts deleted file mode 100644 index 1d232e49a..000000000 --- a/src/chat/server/http/api/chat/references.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute('/api/chat/references', z.object({}), { - GET: async ({ request }) => { - const { handleReferences } = - await import('~/chat/server/reference-http.server') - return handleReferences(request) - }, -}) diff --git a/src/chat/server/http/api/chat/references/kody/inspect.ts b/src/chat/server/http/api/chat/references/kody/inspect.ts deleted file mode 100644 index edd571b30..000000000 --- a/src/chat/server/http/api/chat/references/kody/inspect.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute( - '/api/chat/references/kody/inspect', - z.object({}), - { - GET: async ({ request }) => { - const { handleReferenceCatalog } = - await import('~/chat/server/reference-catalog-http.server') - return handleReferenceCatalog(request, 'kody-inspect') - }, - }, -) diff --git a/src/chat/server/http/api/chat/references/kody/refresh.ts b/src/chat/server/http/api/chat/references/kody/refresh.ts deleted file mode 100644 index fa76bece3..000000000 --- a/src/chat/server/http/api/chat/references/kody/refresh.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute( - '/api/chat/references/kody/refresh', - z.object({}), - { - POST: async ({ request }) => { - const { handleReferenceCatalog } = - await import('~/chat/server/reference-catalog-http.server') - return handleReferenceCatalog(request, 'kody-refresh') - }, - }, -) diff --git a/src/chat/server/http/api/chat/references/tools/refresh.ts b/src/chat/server/http/api/chat/references/tools/refresh.ts deleted file mode 100644 index 0d8598f4a..000000000 --- a/src/chat/server/http/api/chat/references/tools/refresh.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute( - '/api/chat/references/tools/refresh', - z.object({}), - { - POST: async ({ request }) => { - const { handleReferenceCatalog } = - await import('~/chat/server/reference-catalog-http.server') - return handleReferenceCatalog(request, 'tools-refresh') - }, - }, -) diff --git a/src/chat/server/http/api/chat/retries/$id.prepare.ts b/src/chat/server/http/api/chat/retries/$id.prepare.ts deleted file mode 100644 index 174a36141..000000000 --- a/src/chat/server/http/api/chat/retries/$id.prepare.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute( - '/api/chat/retries/$id/prepare', - z.object({ id: z.string() }), - { - POST: async ({ request, params }) => { - const { handleConversationRetry } = - await import('~/chat/server/conversation-retry-http.server') - return handleConversationRetry(request, params.id, 'prepare') - }, - }, -) diff --git a/src/chat/server/http/api/chat/retries/$id.ts b/src/chat/server/http/api/chat/retries/$id.ts deleted file mode 100644 index 7c18e8588..000000000 --- a/src/chat/server/http/api/chat/retries/$id.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute( - '/api/chat/retries/$id', - z.object({ id: z.string() }), - { - GET: async ({ request, params }) => { - const { handleConversationRetry } = - await import('~/chat/server/conversation-retry-http.server') - return handleConversationRetry(request, params.id, 'get') - }, - }, -) diff --git a/src/chat/server/http/api/chat/sections.ts b/src/chat/server/http/api/chat/sections.ts deleted file mode 100644 index 285da9394..000000000 --- a/src/chat/server/http/api/chat/sections.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute('/api/chat/sections', z.object({}), { - POST: async ({ request }) => { - const { handleWorkspaceSections } = - await import('~/chat/server/workspace-sections-http.server') - return handleWorkspaceSections(request) - }, -}) diff --git a/src/chat/server/http/api/chat/sections/$id.ts b/src/chat/server/http/api/chat/sections/$id.ts deleted file mode 100644 index 791c34ee8..000000000 --- a/src/chat/server/http/api/chat/sections/$id.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute( - '/api/chat/sections/$id', - z.object({ id: z.string() }), - { - PATCH: async ({ request, params }) => { - const { handleWorkspaceSections } = - await import('~/chat/server/workspace-sections-http.server') - return handleWorkspaceSections(request, params.id) - }, - DELETE: async ({ request, params }) => { - const { handleWorkspaceSections } = - await import('~/chat/server/workspace-sections-http.server') - return handleWorkspaceSections(request, params.id) - }, - }, -) diff --git a/src/chat/server/http/api/chat/skills.ts b/src/chat/server/http/api/chat/skills.ts deleted file mode 100644 index 7e076f6d2..000000000 --- a/src/chat/server/http/api/chat/skills.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute('/api/chat/skills', z.object({}), { - GET: async (context) => { - const { handlers } = await import('~/chat/server/routes/skills') - return handlers.GET(context) - }, - POST: async (context) => { - const { handlers } = await import('~/chat/server/routes/skills') - return handlers.POST(context) - }, -}) diff --git a/src/chat/server/http/api/chat/skills/$id.ts b/src/chat/server/http/api/chat/skills/$id.ts deleted file mode 100644 index cde2d39d8..000000000 --- a/src/chat/server/http/api/chat/skills/$id.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute( - '/api/chat/skills/$id', - z.object({ id: z.string() }), - { - GET: async ({ request, params }) => { - const { handleSkills } = await import('~/chat/server/routes/skills') - return handleSkills(request, params.id) - }, - POST: async ({ request, params }) => { - const { handleSkills } = await import('~/chat/server/routes/skills') - return handleSkills(request, params.id) - }, - }, -) diff --git a/src/chat/server/http/api/chat/workspace-history.ts b/src/chat/server/http/api/chat/workspace-history.ts deleted file mode 100644 index 95b023552..000000000 --- a/src/chat/server/http/api/chat/workspace-history.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute('/api/chat/workspace-history', z.object({}), { - POST: async ({ request }) => { - const { handleBotMutation } = - await import('~/chat/server/bot-mutation-http.server') - return handleBotMutation(request, undefined, undefined, 'history') - }, -}) diff --git a/src/chat/server/http/api/chat/workspace-index.activity.ts b/src/chat/server/http/api/chat/workspace-index.activity.ts deleted file mode 100644 index 627dbba7a..000000000 --- a/src/chat/server/http/api/chat/workspace-index.activity.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute( - '/api/chat/workspace-index/activity', - z.object({}), - { - GET: async ({ request }) => { - const { handleWorkspaceActivity } = - await import('~/chat/server/workspace-activity-http.server') - return handleWorkspaceActivity(request, true) - }, - }, -) diff --git a/src/chat/server/http/api/chat/workspace-index.ts b/src/chat/server/http/api/chat/workspace-index.ts deleted file mode 100644 index 033d73f8f..000000000 --- a/src/chat/server/http/api/chat/workspace-index.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute('/api/chat/workspace-index', z.object({}), { - GET: async ({ request }) => { - const { handleWorkspaceIndex } = - await import('~/chat/server/workspace-index-http.server') - return handleWorkspaceIndex(request) - }, -}) diff --git a/src/chat/server/http/api/chat/workspace-sync/$operation.ts b/src/chat/server/http/api/chat/workspace-sync/$operation.ts deleted file mode 100644 index 66266512c..000000000 --- a/src/chat/server/http/api/chat/workspace-sync/$operation.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute( - '/api/chat/workspace-sync/$operation', - z.object({ operation: z.string() }), - { - GET: async ({ request, params }) => { - const { handleWorkspaceSync } = - await import('~/chat/server/workspace-sync-http.server') - return handleWorkspaceSync(request, params.operation) - }, - }, -) diff --git a/src/chat/server/http/api/chat/workspace.ts b/src/chat/server/http/api/chat/workspace.ts deleted file mode 100644 index c343844c4..000000000 --- a/src/chat/server/http/api/chat/workspace.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute('/api/chat/workspace', z.object({}), { - POST: async ({ request }) => { - const { hasChatAccess } = await import('~/chat/access.server') - const { getAuthService } = await import('~/auth/index.server') - const { openPersonalChatWorkspace } = - await import('~/chat/workspace.server') - const { jsonError, jsonResponse, validateSameOriginRequest } = - await import('~/utils/api-boundary.server') - - const boundaryError = validateSameOriginRequest(request) - if (boundaryError) - return jsonError(boundaryError.message, boundaryError.status) - const user = await getAuthService().getCurrentUser(request) - if (!user) return jsonError('Sign in to TanStack.', 401) - if (!(await hasChatAccess(user))) - return jsonError('Chat access is not enabled for this account.', 403) - const workspace = await openPersonalChatWorkspace(user.userId) - return jsonResponse(workspace) - }, -}) diff --git a/src/chat/server/http/auth/mcp/callback.ts b/src/chat/server/http/auth/mcp/callback.ts deleted file mode 100644 index e0722fdc0..000000000 --- a/src/chat/server/http/auth/mcp/callback.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute('/auth/mcp/callback', z.object({}), { - GET: async ({ request }) => { - const { handleMcpOAuth } = - await import('~/chat/server/mcp-oauth-route.server') - return handleMcpOAuth(request) - }, -}) diff --git a/src/chat/server/http/auth/mcp/client-metadata.ts b/src/chat/server/http/auth/mcp/client-metadata.ts deleted file mode 100644 index bc33b471e..000000000 --- a/src/chat/server/http/auth/mcp/client-metadata.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { z } from 'zod' -import { defineHttpRoute } from '~/server/runtime/http-route.server' - -export default defineHttpRoute('/auth/mcp/client-metadata', z.object({}), { - GET: async ({ request }) => { - const { handleMcpOAuth } = - await import('~/chat/server/mcp-oauth-route.server') - return handleMcpOAuth(request) - }, -}) diff --git a/src/chat/server/http/routes.ts b/src/chat/server/http/routes.ts deleted file mode 100644 index 3ef2cddbf..000000000 --- a/src/chat/server/http/routes.ts +++ /dev/null @@ -1,196 +0,0 @@ -import route48 from '~/chat/server/http/api/chat/kody/memories/create/apply' -import route49 from '~/chat/server/http/api/chat/kody/memories/create/review' -import route43 from '~/chat/server/http/api/chat/kody/mail/messages/$messageId' -import route42 from '~/chat/server/http/api/chat/kody/mail/inboxes' -import route44 from '~/chat/server/http/api/chat/kody/mail/messages' -import route79 from '~/chat/server/http/api/chat/references/kody/inspect' -import route80 from '~/chat/server/http/api/chat/references/kody/refresh' -import route81 from '~/chat/server/http/api/chat/references/tools/refresh' -import route41 from '~/chat/server/http/api/chat/kody/jobs/$jobId/enabled' -import route45 from '~/chat/server/http/api/chat/kody/memories/$memoryId/apply' -import route46 from '~/chat/server/http/api/chat/kody/memories/$memoryId/review' -import route51 from '~/chat/server/http/api/chat/kody/packages/$packageId/document' -import route53 from '~/chat/server/http/api/chat/kody/runs/$runId/triage' -import route56 from '~/chat/server/http/api/chat/kody/servers/$serverId/check' -import route57 from '~/chat/server/http/api/chat/kody/servers/$serverId/enabled' -import route58 from '~/chat/server/http/api/chat/kody/servers/$serverId/reconnect' -import route0 from '~/chat/server/http/api/chat/account/composer-drafts/$accountId.$scope' -import route38 from '~/chat/server/http/api/chat/kody/community/$listingId' -import route47 from '~/chat/server/http/api/chat/kody/memories/$memoryId' -import route52 from '~/chat/server/http/api/chat/kody/resources/$kind' -import route54 from '~/chat/server/http/api/chat/kody/runs/$runId' -import route1 from '~/chat/server/http/api/chat/account/devices' -import route2 from '~/chat/server/http/api/chat/account/onboarding' -import route3 from '~/chat/server/http/api/chat/account/preferences' -import route16 from '~/chat/server/http/api/chat/bots/bulk' -import route17 from '~/chat/server/http/api/chat/bots/move' -import route36 from '~/chat/server/http/api/chat/kody/account' -import route37 from '~/chat/server/http/api/chat/kody/callback' -import route39 from '~/chat/server/http/api/chat/kody/community' -import route40 from '~/chat/server/http/api/chat/kody/connect' -import route50 from '~/chat/server/http/api/chat/kody/memories' -import route55 from '~/chat/server/http/api/chat/kody/runs' -import route59 from '~/chat/server/http/api/chat/kody/servers' -import route60 from '~/chat/server/http/api/chat/kody/sync' -import route61 from '~/chat/server/http/api/chat/kody/unlink' -import route62 from '~/chat/server/http/api/chat/kody/usage' -import route64 from '~/chat/server/http/api/chat/mcp/contract' -import route67 from '~/chat/server/http/api/chat/openrouter/callback' -import route90 from '~/chat/server/http/api/chat/workspace-index.activity' -import route25 from '~/chat/server/http/api/chat/conversations/$id.execution.snapshots.$snapshotId' -import route20 from '~/chat/server/http/api/chat/conversations/$id/files/import' -import route7 from '~/chat/server/http/api/chat/bot-drafts/$id.files.$fileId.content' -import route12 from '~/chat/server/http/api/chat/bots/$id.files.$fileId.content' -import route26 from '~/chat/server/http/api/chat/conversations/$id.files.$fileId.content' -import route29 from '~/chat/server/http/api/chat/conversations/$id.workflow-runs.$runId.cancel' -import route8 from '~/chat/server/http/api/chat/bot-drafts/$id.files.$fileId' -import route13 from '~/chat/server/http/api/chat/bots/$id.files.$fileId' -import route27 from '~/chat/server/http/api/chat/conversations/$id.files.$fileId' -import route21 from '~/chat/server/http/api/chat/conversations/$id/memories/$memoryId' -import route30 from '~/chat/server/http/api/chat/conversations/$id.workflow-runs.$runId' -import route31 from '~/chat/server/http/api/chat/conversations/$id.workflows.$workflowId' -import route9 from '~/chat/server/http/api/chat/bot-drafts/$id.files' -import route14 from '~/chat/server/http/api/chat/bots/$id.files' -import route28 from '~/chat/server/http/api/chat/conversations/$id.files' -import route22 from '~/chat/server/http/api/chat/conversations/$id/memories' -import route23 from '~/chat/server/http/api/chat/conversations/$id/references' -import route71 from '~/chat/server/http/api/chat/project-snapshots.$hash.quarantine' -import route74 from '~/chat/server/http/api/chat/projects.$id.sync' -import route83 from '~/chat/server/http/api/chat/retries/$id.prepare' -import route11 from '~/chat/server/http/api/chat/bots/$id.$operation' -import route24 from '~/chat/server/http/api/chat/conversations/$id.$operation' -import route10 from '~/chat/server/http/api/chat/bot-drafts/$id' -import route15 from '~/chat/server/http/api/chat/bots/$id' -import route32 from '~/chat/server/http/api/chat/copies/$id' -import route68 from '~/chat/server/http/api/chat/plugins/$id' -import route72 from '~/chat/server/http/api/chat/project-snapshots.$hash' -import route75 from '~/chat/server/http/api/chat/projects.$id' -import route77 from '~/chat/server/http/api/chat/recipes/$id' -import route84 from '~/chat/server/http/api/chat/retries/$id' -import route85 from '~/chat/server/http/api/chat/sections/$id' -import route87 from '~/chat/server/http/api/chat/skills/$id' -import route92 from '~/chat/server/http/api/chat/workspace-sync/$operation' -import route63 from '~/chat/server/http/api/chat/mcp/$' -import route4 from '~/chat/server/http/api/chat/activity' -import route5 from '~/chat/server/http/api/chat/app-version' -import route6 from '~/chat/server/http/api/chat/bootstrap' -import route18 from '~/chat/server/http/api/chat/bots' -import route19 from '~/chat/server/http/api/chat/connection' -import route33 from '~/chat/server/http/api/chat/device-transport' -import route34 from '~/chat/server/http/api/chat/draft' -import route35 from '~/chat/server/http/api/chat/files' -import route65 from '~/chat/server/http/api/chat/model-options' -import route66 from '~/chat/server/http/api/chat/models' -import route69 from '~/chat/server/http/api/chat/plugins' -import route70 from '~/chat/server/http/api/chat/policy' -import route73 from '~/chat/server/http/api/chat/project-snapshots' -import route76 from '~/chat/server/http/api/chat/projects' -import route78 from '~/chat/server/http/api/chat/recipes' -import route82 from '~/chat/server/http/api/chat/references' -import route86 from '~/chat/server/http/api/chat/sections' -import route88 from '~/chat/server/http/api/chat/skills' -import route93 from '~/chat/server/http/api/chat/workspace' -import route89 from '~/chat/server/http/api/chat/workspace-history' -import route91 from '~/chat/server/http/api/chat/workspace-index' -import route94 from '~/chat/server/http/auth/mcp/callback' -import route95 from '~/chat/server/http/auth/mcp/client-metadata' - -// Specific paths precede parameters and splats, matching the Start route tree. -export const chatHttpRoutes = [ - route48, - route49, - route43, - route42, - route44, - route79, - route80, - route81, - route41, - route45, - route46, - route51, - route53, - route56, - route57, - route58, - route0, - route38, - route47, - route52, - route54, - route1, - route2, - route3, - route16, - route17, - route36, - route37, - route39, - route40, - route50, - route55, - route59, - route60, - route61, - route62, - route64, - route67, - route90, - route25, - route20, - route7, - route12, - route26, - route29, - route8, - route13, - route27, - route21, - route30, - route31, - route9, - route14, - route28, - route22, - route23, - route71, - route74, - route83, - route11, - route24, - route10, - route15, - route32, - route68, - route72, - route75, - route77, - route84, - route85, - route87, - route92, - route63, - route4, - route5, - route6, - route18, - route19, - route33, - route34, - route35, - route65, - route66, - route69, - route70, - route73, - route76, - route78, - route82, - route86, - route88, - route93, - route89, - route91, - route94, - route95, -] diff --git a/src/chat/server/routes/draft.ts b/src/chat/server/routes/draft.ts deleted file mode 100644 index a5e66ae05..000000000 --- a/src/chat/server/routes/draft.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { hasChatAccess } from '~/chat/access.server' -import { z } from 'zod' -import { getAuthService } from '~/auth/index.server' -import { - jsonError, - readJsonBody, - validateSameOriginRequest, -} from '~/utils/api-boundary.server' -import { composerDraftApi } from '~/chat/server/composer-drafts' - -async function handle(request: Request) { - if (request.method === 'POST') { - const rejection = validateSameOriginRequest(request) - if (rejection) return jsonError(rejection.message, rejection.status) - } - const user = await getAuthService().getCurrentUser(request) - if (!user) return jsonError('Sign in to continue.', 401) - if (!(await hasChatAccess(user))) - return jsonError('Chat access is unavailable.', 403) - const scope = new URL(request.url).searchParams.get('scope') ?? '' - const body = - request.method === 'POST' - ? await readJsonBody(request, { maxContentLength: 600_000 }) - : undefined - if (body && !body.success) - return jsonError(body.error.message, body.error.status) - try { - return await composerDraftApi( - request, - user.userId, - scope, - body?.success ? body.body : undefined, - ) - } catch (error) { - if (error instanceof z.ZodError) - return jsonError('Invalid draft request.', 400) - throw error - } -} -export const handlers = { - GET: ({ request }: { request: Request }) => handle(request), - POST: ({ request }: { request: Request }) => handle(request), -} diff --git a/src/chat/server/routes/files.ts b/src/chat/server/routes/files.ts deleted file mode 100644 index f9b08b400..000000000 --- a/src/chat/server/routes/files.ts +++ /dev/null @@ -1,84 +0,0 @@ -import { hasChatAccess } from '~/chat/access.server' -import { z } from 'zod' -import type { FileScope, DraftFileScope } from '~/chat/core/files' -import { getAuthService } from '~/auth/index.server' -import { - jsonError, - validateSameOriginRequest, -} from '~/utils/api-boundary.server' -import { fileApi } from '~/chat/server/file-api' -import { getFileEnvironment } from '~/chat/server/file-environment.server' -import { SavedFileError } from '~/chat/server/saved-file-contract' -const requestSchema = z - .object({ - workspaceId: z.string().min(1).max(1000), - botId: z.string().min(1).max(1000).optional(), - conversationId: z.string().min(1).max(1000).optional(), - draftId: z.string().uuid().optional(), - id: z.string().uuid().optional(), - content: z.enum(['0', '1']).default('0'), - }) - .superRefine((value, ctx) => { - if ( - value.draftId - ? Boolean(value.botId || value.conversationId) - : !value.botId - ) - ctx.addIssue({ - code: 'custom', - message: 'Choose a draft or a conversation.', - }) - if (value.content === '1' && !value.id) - ctx.addIssue({ code: 'custom', message: 'Choose a file.' }) - }) -export async function handleFileRequest(request: Request) { - if (request.method === 'PUT') { - const rejection = validateSameOriginRequest(request) - if (rejection) return jsonError(rejection.message, rejection.status) - } - const user = await getAuthService().getCurrentUser(request) - if (!user) return jsonError('Sign in to continue.', 401) - if (!(await hasChatAccess(user))) - return jsonError('Chat access is unavailable.', 403) - const parsed = requestSchema.safeParse( - Object.fromEntries(new URL(request.url).searchParams), - ) - if (!parsed.success) return jsonError('Invalid file request.', 400) - const value = parsed.data - let scope: FileScope | DraftFileScope - if (value.draftId) - scope = { - workspaceId: value.workspaceId, - userId: user.userId, - draftId: value.draftId, - } - else { - if (!value.botId) return jsonError('Invalid file request.', 400) - scope = { - workspaceId: value.workspaceId, - userId: user.userId, - botId: value.botId, - conversationId: value.conversationId, - } - } - - try { - return await fileApi( - request, - await getFileEnvironment(), - scope, - value.id, - value.content === '1', - ) - } catch (error) { - if (error instanceof SavedFileError) - return jsonError(error.message, error.status) - if (error instanceof z.ZodError) - return jsonError('Invalid file request.', 400) - throw error - } -} -export const handlers = { - GET: ({ request }: { request: Request }) => handleFileRequest(request), - PUT: ({ request }: { request: Request }) => handleFileRequest(request), -} diff --git a/src/chat/server/routes/mcp/$.ts b/src/chat/server/routes/mcp/$.ts deleted file mode 100644 index ad04d9a5d..000000000 --- a/src/chat/server/routes/mcp/$.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { hasChatAccess } from '~/chat/access.server' -import { z } from 'zod' -import { getAuthService } from '~/auth/index.server' -import { - jsonError, - validateSameOriginRequest, -} from '~/utils/api-boundary.server' -import { - readWorkspacePolicy, - WorkspacePolicyError, -} from '~/chat/workspace-policy.server' -import { - getMcpEnvironment, - McpEnvironmentError, -} from '~/chat/server/mcp-environment.server' -import { mcpAccountApi } from '~/chat/server/mcp-account-api' -import { McpAccountError } from '~/chat/server/mcp-account-contract' -import { McpAuthorizationError } from '~/chat/server/mcp-auth-network' -export async function handleMcp(request: Request) { - if (request.method === 'POST') { - const error = validateSameOriginRequest(request) - if (error) return jsonError(error.message, error.status) - } - const user = await getAuthService().getCurrentUser(request) - if (!user) return jsonError('Sign in to continue.', 401) - if (!(await hasChatAccess(user))) - return jsonError('Chat access is unavailable.', 403) - const url = new URL(request.url) - const workspace = z - .string() - .min(1) - .max(1000) - .safeParse(url.searchParams.get('workspaceId')) - if (!workspace.success) return jsonError('Choose a workspace.', 400) - try { - await readWorkspacePolicy(workspace.data, user.userId) - const path = url.pathname.slice('/api/chat/'.length) - return ( - (await mcpAccountApi( - request, - await getMcpEnvironment(), - { workspaceId: workspace.data, userId: user.userId }, - path, - )) ?? jsonError('Not found.', 404) - ) - } catch (error) { - if ( - error instanceof WorkspacePolicyError || - error instanceof McpEnvironmentError || - error instanceof McpAccountError || - error instanceof McpAuthorizationError - ) - return jsonError(error.message, error.status) - if (error instanceof z.ZodError) - return jsonError('The connection request is invalid.', 400) - throw error - } -} -export const handlers = { - GET: ({ request }: { request: Request }) => handleMcp(request), - POST: ({ request }: { request: Request }) => handleMcp(request), -} diff --git a/src/chat/server/routes/models.ts b/src/chat/server/routes/models.ts deleted file mode 100644 index a336181d0..000000000 --- a/src/chat/server/routes/models.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { hasChatAccess } from '~/chat/access.server' -import { z } from 'zod' -import { getAuthService } from '~/auth/index.server' -import { jsonError, jsonResponse } from '~/utils/api-boundary.server' -import { - readWorkspacePolicy, - WorkspacePolicyError, -} from '~/chat/workspace-policy.server' -import { getModelEnvironment } from '~/chat/server/model-environment.server' -import { getRunModelCatalog, RunModelError } from '~/chat/server/run-models' -const workspaceIdSchema = z.string().min(1).max(1000) -export async function handleModelCatalog(request: Request) { - const user = await getAuthService().getCurrentUser(request) - if (!user) return jsonError('Sign in to continue.', 401) - if (!(await hasChatAccess(user))) - return jsonError('Chat access is unavailable.', 403) - const parsed = workspaceIdSchema.safeParse( - new URL(request.url).searchParams.get('workspaceId'), - ) - if (!parsed.success) return jsonError('Choose a workspace.', 400) - try { - const policy = await readWorkspacePolicy(parsed.data, user.userId) - const env = await getModelEnvironment() - const catalog = await getRunModelCatalog(env, { - userId: user.userId, - policy, - fixture: false, - }) - return jsonResponse(catalog, { - headers: { 'Cache-Control': 'private, no-store' }, - }) - } catch (error) { - if (error instanceof WorkspacePolicyError || error instanceof RunModelError) - return jsonError(error.message, error.status) - throw error - } -} -export const handlers = { - GET: ({ request }: { request: Request }) => handleModelCatalog(request), -} diff --git a/src/chat/server/routes/openrouter/callback.ts b/src/chat/server/routes/openrouter/callback.ts deleted file mode 100644 index a258b3b26..000000000 --- a/src/chat/server/routes/openrouter/callback.ts +++ /dev/null @@ -1,34 +0,0 @@ -export function openRouterCallbackResponse() { - const nonce = crypto.randomUUID() - // Do not load the app, analytics, or third-party assets while the - // authorization code is in the URL. - return new Response( - ` -Connect OpenRouter | TanChat -

Return to Builder to finish connecting OpenRouter.

-`, - { - headers: { - 'Content-Type': 'text/html; charset=utf-8', - 'Cache-Control': 'no-store', - 'Referrer-Policy': 'no-referrer', - 'Content-Security-Policy': `default-src 'none'; script-src 'nonce-${nonce}'; base-uri 'none'; frame-ancestors 'none'; form-action 'none'`, - 'X-Content-Type-Options': 'nosniff', - 'Cross-Origin-Opener-Policy': 'same-origin', - }, - }, - ) -} -export const handlers = { GET: () => openRouterCallbackResponse() } diff --git a/src/chat/server/routes/plugins.ts b/src/chat/server/routes/plugins.ts deleted file mode 100644 index c8f539ced..000000000 --- a/src/chat/server/routes/plugins.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { hasChatAccess } from '~/chat/access.server' -import { z } from 'zod' -import { getAuthService } from '~/auth/index.server' -import { - jsonError, - validateSameOriginRequest, -} from '~/utils/api-boundary.server' -import { - readWorkspacePolicy, - WorkspacePolicyError, -} from '~/chat/workspace-policy.server' -import { - getKodyEnvironment, - KodyEnvironmentError, -} from '~/chat/server/kody-environment.server' -import { pluginApi } from '~/chat/server/plugin-api' -export async function handlePlugins(request: Request, id?: string) { - if (request.method === 'POST') { - const error = validateSameOriginRequest(request) - if (error) return jsonError(error.message, error.status) - } - const user = await getAuthService().getCurrentUser(request) - if (!user) return jsonError('Sign in to continue.', 401) - if (!(await hasChatAccess(user))) - return jsonError('Chat access is unavailable.', 403) - const url = new URL(request.url) - const parsed = z - .string() - .min(1) - .max(1000) - .safeParse(url.searchParams.get('workspaceId')) - if (url.searchParams.getAll('workspaceId').length !== 1 || !parsed.success) - return jsonError('Choose a workspace.', 400) - try { - await readWorkspacePolicy(parsed.data, user.userId) - return await pluginApi( - request, - await getKodyEnvironment(), - { workspaceId: parsed.data, userId: user.userId }, - id ?? url.searchParams.get('id') ?? undefined, - ) - } catch (error) { - if ( - error instanceof WorkspacePolicyError || - error instanceof KodyEnvironmentError - ) - return jsonError(error.message, error.status) - throw error - } -} -export const handlers = { - GET: ({ request }: { request: Request }) => handlePlugins(request), - POST: ({ request }: { request: Request }) => handlePlugins(request), -} diff --git a/src/chat/server/routes/project-snapshots.$hash.quarantine.ts b/src/chat/server/routes/project-snapshots.$hash.quarantine.ts deleted file mode 100644 index 4367eb5ad..000000000 --- a/src/chat/server/routes/project-snapshots.$hash.quarantine.ts +++ /dev/null @@ -1,163 +0,0 @@ -import { - jsonError, - jsonResponse, - validateSameOriginRequest, -} from '~/utils/api-boundary.server' -import { - purgeHostingCacheTags, - type PurgeResult, -} from '~/utils/hosting-cache.server' -import { - getBuilderProjectSnapshotCacheTag, - isBuilderProjectSnapshotHash, - isBuilderProjectSnapshotQuarantined, - BuilderProjectSnapshotStorageUnavailableError, - quarantineBuilderProjectSnapshot, -} from '~/utils/builder-project-snapshot-storage.server' -import { - BuilderProjectStorageUnavailableError, - quarantineStoredBuilderProjectsBySnapshotHash, -} from '~/utils/builder-project-storage.server' -import { quarantineBuilderProjectsBySnapshotHash } from '~/utils/builder-project-events.server' - -type BuilderProjectQuarantineOperations = { - quarantineSnapshot: (hash: string, userId: string) => Promise - isSnapshotQuarantined: (hash: string) => Promise - purgeCacheTags: (tags: Array) => Promise - quarantineProjects: (input: { - snapshotHash: string - actorId: string - }) => Promise> - quarantineStableProjects: ( - snapshotHash: string, - actorId: string, - ) => Promise -} - -export class BuilderProjectQuarantineCleanupError extends Error { - constructor(readonly failures: Array) { - super('Builder project quarantine cleanup did not finish') - this.name = 'BuilderProjectQuarantineCleanupError' - } -} - -export async function quarantineBuilderProjectSnapshotForAdmin( - { - hash, - actorId, - }: { - hash: string - actorId: string - }, - operations: BuilderProjectQuarantineOperations = { - quarantineSnapshot: quarantineBuilderProjectSnapshot, - isSnapshotQuarantined: isBuilderProjectSnapshotQuarantined, - purgeCacheTags: purgeHostingCacheTags, - quarantineProjects: quarantineBuilderProjectsBySnapshotHash, - quarantineStableProjects: quarantineStoredBuilderProjectsBySnapshotHash, - }, -) { - const failures: Array = [] - let tombstoned = false - try { - await operations.quarantineSnapshot(hash, actorId) - tombstoned = true - } catch (error) { - failures.push(error) - } - - const purge = await operations.purgeCacheTags([ - getBuilderProjectSnapshotCacheTag(hash), - ]) - if (!purge.purged) failures.push(new Error('Cache purge failed')) - if (!tombstoned) { - try { - tombstoned = await operations.isSnapshotQuarantined(hash) - } catch (statusError) { - failures.push(statusError) - } - } - if (!tombstoned) { - throw new BuilderProjectQuarantineCleanupError(failures) - } - - let projectsQuarantined: Array = [] - try { - projectsQuarantined = await operations.quarantineProjects({ - snapshotHash: hash, - actorId, - }) - } catch (error) { - failures.push(error) - } - - let stableRecordsQuarantined = 0 - try { - stableRecordsQuarantined = await operations.quarantineStableProjects( - hash, - actorId, - ) - } catch (error) { - failures.push(error) - } - - if (failures.length > 0) { - throw new BuilderProjectQuarantineCleanupError(failures) - } - return { projectsQuarantined, purge, stableRecordsQuarantined } -} -export const handlers = { - POST: async ({ - params, - request, - }: { - params: { hash: string } - request: Request - }) => { - const requestError = validateSameOriginRequest(request) - if (requestError) { - return jsonError(requestError.message, requestError.status) - } - if (!isBuilderProjectSnapshotHash(params.hash)) { - return jsonError('Builder project not found', 404) - } - - const { getAuthService } = await import('~/auth/index.server') - const user = await getAuthService().getCurrentUser(request) - if (!user) { - return jsonError('Not authenticated', 401) - } - if (!user.capabilities.includes('admin')) { - return jsonError('Not authorized', 403) - } - - try { - const { projectsQuarantined, purge, stableRecordsQuarantined } = - await quarantineBuilderProjectSnapshotForAdmin({ - hash: params.hash, - actorId: user.userId, - }) - return jsonResponse({ - purge, - quarantined: true, - projectsQuarantined: projectsQuarantined.length, - stableRecordsQuarantined, - }) - } catch (error) { - if (error instanceof BuilderProjectQuarantineCleanupError) { - for (const failure of error.failures) { - console.error('Builder project quarantine cleanup failed:', failure) - } - return jsonError('Builder quarantine cleanup is unavailable', 503) - } - if ( - error instanceof BuilderProjectSnapshotStorageUnavailableError || - error instanceof BuilderProjectStorageUnavailableError - ) { - return jsonError('Builder storage is unavailable', 503) - } - console.error('Failed to quarantine builder project:', error) - return jsonError('Failed to quarantine builder project', 500) - } - }, -} diff --git a/src/chat/server/routes/project-snapshots.ts b/src/chat/server/routes/project-snapshots.ts deleted file mode 100644 index 4376a3044..000000000 --- a/src/chat/server/routes/project-snapshots.ts +++ /dev/null @@ -1,108 +0,0 @@ -import { - jsonError, - jsonResponse, - readJsonBody, - validateJsonRequest, -} from '~/utils/api-boundary.server' -import { - BuilderProjectSnapshotQuarantinedError, - BuilderProjectSnapshotStorageUnavailableError, - parseStoredBuilderProjectSnapshot, -} from '~/utils/builder-project-snapshot-storage.server' -import { - BuilderProjectSnapshotLimitError, - BuilderProjectSnapshotRegistryConflictError, - storeBuilderProjectSnapshotForOwner, -} from '~/utils/builder-project-snapshot-registry.server' -import { - checkIpRateLimit, - RATE_LIMITS, - rateLimitedResponse, -} from '~/utils/rateLimit.server' - -const maxRequestBytes = 2 * 1024 * 1024 -export const handlers = { - POST: async ({ request }: { request: Request }) => { - const requestError = validateJsonRequest(request, { - maxContentLength: maxRequestBytes, - }) - if (requestError) { - return jsonError(requestError.message, requestError.status) - } - - const rateLimit = await checkIpRateLimit( - request, - RATE_LIMITS.builderProjectWrite, - ) - if (!rateLimit.allowed) return rateLimitedResponse(rateLimit) - - const { getAuthService } = await import('~/auth/index.server') - const user = await getAuthService().getCurrentUser(request) - if (!user) { - return jsonError('Not authenticated', 401, rateLimit.headers) - } - - const body = await readJsonBody(request, { - maxContentLength: maxRequestBytes, - }) - if (!body.success) { - return jsonError(body.error.message, body.error.status, rateLimit.headers) - } - - let project - try { - project = parseStoredBuilderProjectSnapshot(body.body) - } catch (error) { - return jsonError( - error instanceof Error ? error.message : 'Invalid project snapshot', - 400, - rateLimit.headers, - ) - } - - try { - const result = await storeBuilderProjectSnapshotForOwner( - user.userId, - project, - ) - return jsonResponse( - { - hash: result.hash, - url: `/builder/p/${result.hash}`, - sourceUrl: `/api/chat/project-snapshots/${result.hash}`, - }, - { - status: result.created ? 201 : 200, - headers: rateLimit.headers, - }, - ) - } catch (error) { - if (error instanceof BuilderProjectSnapshotQuarantinedError) { - return jsonError( - 'Project snapshot is unavailable', - 410, - rateLimit.headers, - ) - } - if ( - error instanceof BuilderProjectSnapshotLimitError || - error instanceof BuilderProjectSnapshotRegistryConflictError - ) { - return jsonError(error.message, 409, rateLimit.headers) - } - if (error instanceof BuilderProjectSnapshotStorageUnavailableError) { - return jsonError( - 'Project snapshot storage is unavailable', - 503, - rateLimit.headers, - ) - } - console.error('Failed to store Builder project snapshot:', error) - return jsonError( - 'Failed to store project snapshot', - 500, - rateLimit.headers, - ) - } - }, -} diff --git a/src/chat/server/routes/projects.$id.sync.ts b/src/chat/server/routes/projects.$id.sync.ts deleted file mode 100644 index f1f7494fa..000000000 --- a/src/chat/server/routes/projects.$id.sync.ts +++ /dev/null @@ -1,536 +0,0 @@ -import { - jsonError, - jsonResponse, - readJsonBody, - validateJsonRequest, - validateSameOriginRequest, -} from '~/utils/api-boundary.server' -import { - BuilderProjectConflictError, - BuilderProjectDeletedError, - BuilderProjectLeaseError, - BuilderProjectNotFoundError, - BuilderProjectOwnershipError, - BuilderProjectRevisionConflictError, - cancelPendingBuilderProjectRun, - claimBuilderProjectRun, - createBuilderProjectThread, - enqueueBuilderProjectRun, - finishBuilderProjectRun, - getBuilderProjectMutationRequestHash, - getBuilderProjectConversationSnapshotPage, - getBuilderProjectState, - heartbeatBuilderProjectRun, - importBuilderProjectTranscript, - interruptExpiredBuilderProjectRuns, - listBuilderProjectEvents, - updateBuilderProjectState, -} from '~/utils/builder-project-events.server' -import { isBuilderProjectId } from '~/utils/builder-project' -import { getOrImportBuilderProjectState } from '~/utils/builder-project-state.server' -import { - createBuilderProjectEventStreamResponse, - isBuilderProjectSyncStreamRequest, - parseBuilderProjectSyncCursor, -} from '~/utils/builder-project-sync-http.server' -import { - encodeBuilderProjectSyncSnapshotContinuation, - parseBuilderProjectSyncSnapshotContinuation, - parseBuilderProjectSyncSnapshotPage, - parseBuilderProjectSyncRequest, - type BuilderProjectSyncCommand, - type BuilderProjectSyncCommandOutcome, -} from '~/utils/builder-project-sync' -import { - BuilderProjectSnapshotQuarantinedError, - BuilderProjectSnapshotStorageUnavailableError, -} from '~/utils/builder-project-snapshot-storage.server' -import { - BuilderProjectSnapshotLimitError, - BuilderProjectSnapshotRegistryConflictError, - storeBuilderProjectSnapshotForOwner, -} from '~/utils/builder-project-snapshot-registry.server' -import { BuilderProjectStorageUnavailableError } from '~/utils/builder-project-storage.server' -import { - checkIpRateLimit, - checkUserRateLimit, - RATE_LIMITS, - rateLimitedResponse, -} from '~/utils/rateLimit.server' - -const maxRequestBytes = 2 * 1024 * 1024 - -async function applyBuilderProjectSyncCommand({ - projectId, - ownerId, - command, -}: { - projectId: string - ownerId: string - command: BuilderProjectSyncCommand -}) { - const requestHash = await getBuilderProjectMutationRequestHash(command) - switch (command.type) { - case 'project.revise': { - const snapshot = await storeBuilderProjectSnapshotForOwner( - ownerId, - command.project, - ) - const project = await updateBuilderProjectState({ - projectId, - ownerId, - clientMutationId: command.clientMutationId, - requestHash, - revisionId: command.revisionId, - snapshotHash: snapshot.hash, - title: command.project.title, - description: command.project.description, - expectedRevisionNumber: command.expectedRevisionNumber, - }) - return { - clientMutationId: command.clientMutationId, - sequence: project.lastEventSequence, - events: [], - } - } - case 'thread.create': - return createBuilderProjectThread({ - projectId, - ownerId, - id: command.thread.id, - clientMutationId: command.clientMutationId, - requestHash, - title: command.thread.title, - ...(command.thread.createdAt - ? { createdAt: new Date(command.thread.createdAt) } - : {}), - }) - case 'run.enqueue': - return enqueueBuilderProjectRun({ - projectId, - ownerId, - runId: command.run.id, - threadId: command.run.threadId, - clientMutationId: command.clientMutationId, - requestHash, - queueKind: command.run.queueKind, - provider: command.run.provider, - model: command.run.model, - userMessage: { - id: command.userMessage.id, - clientMutationId: command.userMessage.clientMutationId, - content: command.userMessage.content, - parts: command.userMessage.parts, - }, - }) - case 'run.claim': - return claimBuilderProjectRun({ - projectId, - ownerId, - runId: command.runId, - clientMutationId: command.clientMutationId, - requestHash, - leaseOwnerId: command.leaseOwnerId, - }) - case 'run.cancel': - return cancelPendingBuilderProjectRun({ - projectId, - ownerId, - runId: command.runId, - clientMutationId: command.clientMutationId, - requestHash, - browserSessionId: command.browserSessionId, - }) - case 'run.heartbeat': - return heartbeatBuilderProjectRun({ - projectId, - ownerId, - runId: command.runId, - clientMutationId: command.clientMutationId, - leaseOwnerId: command.leaseOwnerId, - fencingToken: command.leaseFencingToken, - }) - case 'run.finish': - const finishResult = await finishBuilderProjectRun({ - projectId, - ownerId, - runId: command.runId, - clientMutationId: command.clientMutationId, - requestHash, - status: command.status, - leaseOwnerId: command.leaseOwnerId, - fencingToken: command.leaseFencingToken, - ...(command.revision ? { revision: command.revision } : {}), - ...(command.error ? { error: command.error } : {}), - ...(command.activity ? { activity: command.activity } : {}), - ...(command.revision && command.assistantMessage - ? { - revisionConflictFallback: { - clientMutationId: command.assistantMessage.clientMutationId, - error: { - message: - 'The project changed before the assistant edit could be saved.', - }, - }, - } - : {}), - ...(command.assistantMessage - ? { - assistantMessage: { - id: command.assistantMessage.id, - clientMutationId: command.assistantMessage.clientMutationId, - content: command.assistantMessage.content, - parts: command.assistantMessage.parts, - ...(command.assistantMessage.createdAt - ? { - createdAt: new Date(command.assistantMessage.createdAt), - } - : {}), - }, - } - : {}), - }) - if (finishResult.revisionConflict) { - throw new BuilderProjectRevisionConflictError( - undefined, - finishResult.sequence, - ) - } - return { - clientMutationId: finishResult.clientMutationId, - sequence: finishResult.sequence, - events: finishResult.events, - ...(finishResult.leaseFencingToken === undefined - ? {} - : { leaseFencingToken: finishResult.leaseFencingToken }), - } - case 'transcript.import': - return importBuilderProjectTranscript({ - projectId, - ownerId, - clientMutationId: command.clientMutationId, - requestHash, - threads: command.threads.map((thread) => ({ - id: thread.id, - title: thread.title, - createdAt: new Date(thread.createdAt), - updatedAt: new Date(thread.updatedAt), - ...(thread.archivedAt - ? { archivedAt: new Date(thread.archivedAt) } - : {}), - })), - messages: command.messages.map((message) => ({ - id: message.id, - threadId: message.threadId, - ...(message.runId ? { runId: message.runId } : {}), - role: message.role, - content: message.content, - parts: message.parts, - position: message.position, - createdAt: new Date(message.createdAt), - updatedAt: new Date(message.updatedAt), - })), - runs: command.runs.map((run) => ({ - id: run.id, - threadId: run.threadId, - status: run.status, - provider: run.provider, - model: run.model, - ...(run.error ? { error: run.error } : {}), - ...(run.activity ? { activity: run.activity } : {}), - ...(run.startedAt ? { startedAt: new Date(run.startedAt) } : {}), - completedAt: new Date(run.completedAt), - })), - }) - } -} - -function builderProjectSyncErrorResponse(error: unknown, headers: HeadersInit) { - if (error instanceof BuilderProjectNotFoundError) { - return jsonError('Project not found', 404, headers) - } - if (error instanceof BuilderProjectOwnershipError) { - return jsonError('Not authorized', 403, headers) - } - if (error instanceof BuilderProjectSnapshotRegistryConflictError) { - return jsonError( - 'Project snapshot must be uploaded before completing the run', - 409, - headers, - ) - } - if (error instanceof BuilderProjectSnapshotQuarantinedError) { - return jsonError('Builder project is unavailable', 410, headers) - } - if (error instanceof BuilderProjectSnapshotLimitError) { - return jsonError(error.message, 409, headers) - } - if (error instanceof BuilderProjectSnapshotStorageUnavailableError) { - return jsonError( - 'Builder project snapshot storage is unavailable', - 503, - headers, - ) - } - if (error instanceof BuilderProjectStorageUnavailableError) { - return jsonError('Builder project storage is unavailable', 503, headers) - } - if ( - error instanceof BuilderProjectConflictError || - error instanceof BuilderProjectDeletedError || - error instanceof BuilderProjectLeaseError - ) { - return jsonError(error.message, 409, headers) - } - console.error('Builder project sync failed:', error) - return jsonError('Failed to sync Builder project', 500, headers) -} -export const handlers = { - GET: async ({ - params, - request, - }: { - params: { id: string } - request: Request - }) => { - const requestError = validateSameOriginRequest(request) - if (requestError) { - return jsonError(requestError.message, requestError.status) - } - if (!isBuilderProjectId(params.id)) { - return jsonError('Project not found', 404) - } - - const { getAuthService } = await import('~/auth/index.server') - const user = await getAuthService().getCurrentUser(request) - if (!user) return jsonError('Not authenticated', 401) - - const streamRequest = isBuilderProjectSyncStreamRequest(request) - const continuationValues = streamRequest - ? [] - : new URL(request.url).searchParams.getAll('continuation') - let continuation - try { - if (continuationValues.length > 1) throw new Error() - const value = continuationValues[0] - continuation = value - ? parseBuilderProjectSyncSnapshotContinuation(value) - : undefined - if (continuation && continuation.projectId !== params.id) { - throw new Error() - } - } catch { - return jsonError('Invalid Builder project sync continuation', 400) - } - const rateLimitConfig = continuation - ? RATE_LIMITS.builderProjectSyncSnapshotPage - : RATE_LIMITS.builderProjectSyncStream - const ipRateLimitConfig = continuation - ? RATE_LIMITS.builderProjectSyncSnapshotPageIp - : RATE_LIMITS.builderProjectSyncStreamIp - const rateLimit = await checkUserRateLimit( - `${user.userId}:${params.id}`, - rateLimitConfig, - ) - if (!rateLimit.allowed) return rateLimitedResponse(rateLimit) - const ipBackstop = await checkIpRateLimit(request, ipRateLimitConfig) - if (!ipBackstop.allowed) return rateLimitedResponse(ipBackstop) - - try { - if (streamRequest) { - let cursor - try { - cursor = parseBuilderProjectSyncCursor(request) - } catch { - return jsonError( - 'Invalid Builder project sync cursor', - 400, - rateLimit.headers, - ) - } - let project - try { - project = await getBuilderProjectState({ - projectId: params.id, - ownerId: user.userId, - includeDeleted: true, - }) - } catch (error) { - if (!(error instanceof BuilderProjectNotFoundError)) throw error - await getOrImportBuilderProjectState(params.id) - project = await getBuilderProjectState({ - projectId: params.id, - ownerId: user.userId, - includeDeleted: true, - }) - } - if (cursor > project.lastEventSequence) { - return jsonError( - 'Builder project sync cursor is ahead of the project', - 400, - rateLimit.headers, - ) - } - - return createBuilderProjectEventStreamResponse({ - cursor, - signal: request.signal, - headers: rateLimit.headers, - listEvents: (afterSequence) => - listBuilderProjectEvents({ - projectId: params.id, - ownerId: user.userId, - afterSequence, - limit: 25, - }), - interruptExpiredRuns: async () => { - await interruptExpiredBuilderProjectRuns({ - projectId: params.id, - ownerId: user.userId, - includeDeleted: true, - }) - }, - }) - } - - if (!continuation) await getOrImportBuilderProjectState(params.id) - const snapshot = await getBuilderProjectConversationSnapshotPage({ - projectId: params.id, - ownerId: user.userId, - ...(continuation ? { continuation } : {}), - }) - const page = parseBuilderProjectSyncSnapshotPage({ - project: snapshot.project, - cursor: snapshot.cursor, - headCursor: snapshot.headCursor, - threads: snapshot.threads, - messages: snapshot.messages, - runs: snapshot.runs, - continuation: snapshot.continuation - ? encodeBuilderProjectSyncSnapshotContinuation(snapshot.continuation) - : null, - }) - return jsonResponse(page, { headers: rateLimit.headers }) - } catch (error) { - return builderProjectSyncErrorResponse(error, rateLimit.headers) - } - }, - POST: async ({ - params, - request, - }: { - params: { id: string } - request: Request - }) => { - const requestError = validateJsonRequest(request, { - maxContentLength: maxRequestBytes, - }) - if (requestError) { - return jsonError(requestError.message, requestError.status) - } - if (!isBuilderProjectId(params.id)) { - return jsonError('Project not found', 404) - } - - const { getAuthService } = await import('~/auth/index.server') - const user = await getAuthService().getCurrentUser(request) - if (!user) return jsonError('Not authenticated', 401) - - const rateLimit = await checkUserRateLimit( - `${user.userId}:${params.id}`, - RATE_LIMITS.builderProjectSyncCommand, - ) - if (!rateLimit.allowed) return rateLimitedResponse(rateLimit) - const ipBackstop = await checkIpRateLimit( - request, - RATE_LIMITS.builderProjectSyncCommandIp, - ) - if (!ipBackstop.allowed) return rateLimitedResponse(ipBackstop) - - const body = await readJsonBody(request, { - maxContentLength: maxRequestBytes, - }) - if (!body.success) { - return jsonError(body.error.message, body.error.status, rateLimit.headers) - } - - let input - try { - input = parseBuilderProjectSyncRequest(body.body) - } catch { - return jsonError( - 'Invalid Builder project sync request', - 400, - rateLimit.headers, - ) - } - - try { - await getOrImportBuilderProjectState(params.id) - await getBuilderProjectState({ - projectId: params.id, - ownerId: user.userId, - }) - const results: Array = [] - for (const command of input.commands) { - try { - results.push( - await applyBuilderProjectSyncCommand({ - projectId: params.id, - ownerId: user.userId, - command, - }), - ) - } catch (error) { - if (error instanceof BuilderProjectLeaseError) { - results.push({ - clientMutationId: command.clientMutationId, - rejected: true, - code: 'run-lease-invalid', - message: error.message, - }) - continue - } - if ( - command.type === 'project.revise' && - error instanceof BuilderProjectConflictError - ) { - results.push({ - clientMutationId: command.clientMutationId, - rejected: true, - code: 'project-revision-conflict', - message: error.message, - }) - continue - } - if ( - command.type === 'run.finish' && - command.revision !== undefined && - error instanceof BuilderProjectRevisionConflictError - ) { - results.push({ - clientMutationId: command.clientMutationId, - rejected: true, - code: 'project-revision-conflict', - message: error.message, - ...(error.sequence === undefined - ? {} - : { sequence: error.sequence }), - }) - continue - } - throw error - } - } - return jsonResponse( - { - cursor: Math.max(0, ...results.map((result) => result.sequence ?? 0)), - results, - }, - { headers: rateLimit.headers }, - ) - } catch (error) { - return builderProjectSyncErrorResponse(error, rateLimit.headers) - } - }, -} diff --git a/src/chat/server/routes/projects.$id.ts b/src/chat/server/routes/projects.$id.ts deleted file mode 100644 index 76ccc0205..000000000 --- a/src/chat/server/routes/projects.$id.ts +++ /dev/null @@ -1,364 +0,0 @@ -import { - jsonError, - jsonResponse, - readJsonBody, - validateJsonRequest, -} from '~/utils/api-boundary.server' -import { isBuilderProjectId } from '~/utils/builder-project' -import { - BuilderProjectConflictError, - BuilderProjectDeletedError, - BuilderProjectNotFoundError, - BuilderProjectOwnershipError, - deleteBuilderProjectState, - getBuilderProjectMutationRequestHash, - updateBuilderProjectState, -} from '~/utils/builder-project-events.server' -import { - getOrImportBuilderProjectState, - toBuilderProject, -} from '~/utils/builder-project-state.server' -import { BuilderProjectStorageUnavailableError } from '~/utils/builder-project-storage.server' -import { - BuilderProjectSnapshotQuarantinedError, - BuilderProjectSnapshotStorageUnavailableError, - parseStoredBuilderProjectSnapshot, -} from '~/utils/builder-project-snapshot-storage.server' -import { - BuilderProjectSnapshotLimitError, - BuilderProjectSnapshotRegistryConflictError, - storeBuilderProjectSnapshotForOwner, -} from '~/utils/builder-project-snapshot-registry.server' -import { - checkIpRateLimit, - RATE_LIMITS, - rateLimitedResponse, -} from '~/utils/rateLimit.server' - -const maxRequestBytes = 2 * 1024 * 1024 - -function parseBuilderProjectRequest(value: unknown) { - if ( - typeof value !== 'object' || - value === null || - Array.isArray(value) || - Object.keys(value).some( - (key) => - key !== 'clientMutationId' && - key !== 'expectedRevisionNumber' && - key !== 'project' && - key !== 'revisionId', - ) || - !('clientMutationId' in value) || - !('expectedRevisionNumber' in value) || - !('project' in value) || - !('revisionId' in value) || - typeof value.clientMutationId !== 'string' || - !isBuilderProjectId(value.clientMutationId) || - typeof value.expectedRevisionNumber !== 'number' || - !Number.isSafeInteger(value.expectedRevisionNumber) || - value.expectedRevisionNumber < 1 || - typeof value.revisionId !== 'string' || - !isBuilderProjectId(value.revisionId) - ) { - throw new Error('Invalid builder project request') - } - - return { - clientMutationId: value.clientMutationId, - expectedRevisionNumber: value.expectedRevisionNumber, - project: parseStoredBuilderProjectSnapshot(value.project), - revisionId: value.revisionId, - } -} - -function parseDeleteBuilderProjectRequest(value: unknown) { - if ( - typeof value !== 'object' || - value === null || - Array.isArray(value) || - Object.keys(value).some((key) => key !== 'clientMutationId') || - !('clientMutationId' in value) || - typeof value.clientMutationId !== 'string' || - !isBuilderProjectId(value.clientMutationId) - ) { - throw new Error('Invalid Builder project delete request') - } - return value.clientMutationId -} -export const handlers = { - GET: async ({ params }: { params: { id: string } }) => { - if (!isBuilderProjectId(params.id)) { - return jsonError('Project not found', 404) - } - - try { - const project = await getOrImportBuilderProjectState(params.id) - return jsonResponse({ project: toBuilderProject(project) }) - } catch (error) { - if (error instanceof BuilderProjectNotFoundError) { - return jsonError('Project not found', 404) - } - if (error instanceof BuilderProjectSnapshotQuarantinedError) { - return jsonError('Builder project is unavailable', 410) - } - if ( - error instanceof BuilderProjectSnapshotLimitError || - error instanceof BuilderProjectSnapshotRegistryConflictError - ) { - return jsonError(error.message, 409) - } - if (error instanceof BuilderProjectSnapshotStorageUnavailableError) { - return jsonError('Builder project storage is unavailable', 503) - } - if (error instanceof BuilderProjectStorageUnavailableError) { - return jsonError('Builder project storage is unavailable', 503) - } - console.error('Failed to load builder project:', error) - return jsonError('Failed to load builder project', 500) - } - }, - PATCH: async ({ - params, - request, - }: { - params: { id: string } - request: Request - }) => { - const requestError = validateJsonRequest(request, { - maxContentLength: maxRequestBytes, - }) - if (requestError) { - return jsonError(requestError.message, requestError.status) - } - if (!isBuilderProjectId(params.id)) { - return jsonError('Project not found', 404) - } - - const { getAuthService } = await import('~/auth/index.server') - const user = await getAuthService().getCurrentUser(request) - if (!user) return jsonError('Not authenticated', 401) - - const rateLimit = await checkIpRateLimit( - request, - RATE_LIMITS.builderProjectSave, - ) - if (!rateLimit.allowed) return rateLimitedResponse(rateLimit) - - let existing - try { - existing = await getOrImportBuilderProjectState(params.id) - } catch (error) { - if (error instanceof BuilderProjectNotFoundError) { - return jsonError('Project not found', 404, rateLimit.headers) - } - if (error instanceof BuilderProjectSnapshotQuarantinedError) { - return jsonError( - 'Builder project is unavailable', - 410, - rateLimit.headers, - ) - } - if ( - error instanceof BuilderProjectSnapshotLimitError || - error instanceof BuilderProjectSnapshotRegistryConflictError - ) { - return jsonError(error.message, 409, rateLimit.headers) - } - if (error instanceof BuilderProjectSnapshotStorageUnavailableError) { - return jsonError( - 'Builder project storage is unavailable', - 503, - rateLimit.headers, - ) - } - if (error instanceof BuilderProjectStorageUnavailableError) { - return jsonError( - 'Builder project storage is unavailable', - 503, - rateLimit.headers, - ) - } - console.error('Failed to load builder project for update:', error) - return jsonError('Failed to load builder project', 500, rateLimit.headers) - } - if (existing.ownerId !== user.userId) { - return jsonError('Not authorized', 403, rateLimit.headers) - } - - const body = await readJsonBody(request, { - maxContentLength: maxRequestBytes, - }) - if (!body.success) { - return jsonError(body.error.message, body.error.status, rateLimit.headers) - } - - let input - try { - input = parseBuilderProjectRequest(body.body) - } catch (error) { - return jsonError( - error instanceof Error ? error.message : 'Invalid builder project', - 400, - rateLimit.headers, - ) - } - - try { - const snapshot = input.project - const requestHash = await getBuilderProjectMutationRequestHash({ - type: 'project.revise', - ...input, - }) - const storedSnapshot = await storeBuilderProjectSnapshotForOwner( - user.userId, - snapshot, - ) - const project = await updateBuilderProjectState({ - clientMutationId: input.clientMutationId, - requestHash, - description: snapshot.description, - expectedRevisionNumber: input.expectedRevisionNumber, - projectId: existing.id, - revisionId: input.revisionId, - ownerId: user.userId, - snapshotHash: storedSnapshot.hash, - title: snapshot.title, - }) - return jsonResponse( - { project: toBuilderProject(project) }, - { headers: rateLimit.headers }, - ) - } catch (error) { - if ( - error instanceof BuilderProjectSnapshotLimitError || - error instanceof BuilderProjectSnapshotRegistryConflictError - ) { - return jsonError(error.message, 409, rateLimit.headers) - } - if (error instanceof BuilderProjectConflictError) { - return jsonError(error.message, 409, rateLimit.headers) - } - if (error instanceof BuilderProjectOwnershipError) { - return jsonError('Not authorized', 403, rateLimit.headers) - } - if ( - error instanceof BuilderProjectDeletedError || - error instanceof BuilderProjectSnapshotQuarantinedError - ) { - return jsonError( - 'Builder project is unavailable', - 410, - rateLimit.headers, - ) - } - if ( - error instanceof BuilderProjectStorageUnavailableError || - error instanceof BuilderProjectSnapshotStorageUnavailableError - ) { - return jsonError( - 'Builder storage is unavailable', - 503, - rateLimit.headers, - ) - } - console.error('Failed to update builder project:', error) - return jsonError( - 'Failed to update builder project', - 500, - rateLimit.headers, - ) - } - }, - DELETE: async ({ - params, - request, - }: { - params: { id: string } - request: Request - }) => { - const requestError = validateJsonRequest(request, { - maxContentLength: 1_024, - }) - if (requestError) { - return jsonError(requestError.message, requestError.status) - } - if (!isBuilderProjectId(params.id)) { - return jsonError('Project not found', 404) - } - - const { getAuthService } = await import('~/auth/index.server') - const user = await getAuthService().getCurrentUser(request) - if (!user) return jsonError('Not authenticated', 401) - - const rateLimit = await checkIpRateLimit( - request, - RATE_LIMITS.builderProjectWrite, - ) - if (!rateLimit.allowed) return rateLimitedResponse(rateLimit) - - const body = await readJsonBody(request, { maxContentLength: 1_024 }) - if (!body.success) { - return jsonError(body.error.message, body.error.status, rateLimit.headers) - } - let clientMutationId - try { - clientMutationId = parseDeleteBuilderProjectRequest(body.body) - } catch { - return jsonError( - 'Invalid Builder project delete request', - 400, - rateLimit.headers, - ) - } - - try { - await getOrImportBuilderProjectState(params.id) - await deleteBuilderProjectState({ - projectId: params.id, - ownerId: user.userId, - clientMutationId, - }) - return jsonResponse( - { deleted: true, id: params.id }, - { headers: rateLimit.headers }, - ) - } catch (error) { - if (error instanceof BuilderProjectNotFoundError) { - return jsonError('Project not found', 404, rateLimit.headers) - } - if (error instanceof BuilderProjectSnapshotQuarantinedError) { - return jsonError( - 'Builder project is unavailable', - 410, - rateLimit.headers, - ) - } - if ( - error instanceof BuilderProjectSnapshotLimitError || - error instanceof BuilderProjectSnapshotRegistryConflictError - ) { - return jsonError(error.message, 409, rateLimit.headers) - } - if (error instanceof BuilderProjectOwnershipError) { - return jsonError('Not authorized', 403, rateLimit.headers) - } - if ( - error instanceof BuilderProjectStorageUnavailableError || - error instanceof BuilderProjectSnapshotStorageUnavailableError - ) { - return jsonError( - 'Builder project storage is unavailable', - 503, - rateLimit.headers, - ) - } - console.error('Failed to delete builder project:', error) - return jsonError( - 'Failed to delete builder project', - 500, - rateLimit.headers, - ) - } - }, -} diff --git a/src/chat/server/routes/projects.ts b/src/chat/server/routes/projects.ts deleted file mode 100644 index 77bc69349..000000000 --- a/src/chat/server/routes/projects.ts +++ /dev/null @@ -1,275 +0,0 @@ -import { - jsonError, - jsonResponse, - readJsonBody, - validateJsonRequest, -} from '~/utils/api-boundary.server' -import { - BuilderProjectLimitError, - BuilderProjectNotFoundError, - BuilderProjectConflictError, - createBuilderProjectState, - preflightBuilderProjectCreation, -} from '~/utils/builder-project-events.server' -import { - getOrImportBuilderProjectState, - listOrImportBuilderProjectStates, - reserveLegacyBuilderProjectId, - toBuilderProject, -} from '~/utils/builder-project-state.server' -import { BuilderProjectStorageUnavailableError } from '~/utils/builder-project-storage.server' -import { isBuilderProjectId } from '~/utils/builder-project' -import { - BuilderProjectSnapshotQuarantinedError, - BuilderProjectSnapshotStorageUnavailableError, - getBuilderProjectSnapshotHash, - parseStoredBuilderProjectSnapshot, -} from '~/utils/builder-project-snapshot-storage.server' -import { - BuilderProjectSnapshotLimitError, - BuilderProjectSnapshotRegistryConflictError, - storeBuilderProjectSnapshotForOwner, -} from '~/utils/builder-project-snapshot-registry.server' -import { - checkIpRateLimit, - checkUserWindowRateLimit, - RATE_LIMITS, - rateLimitedResponse, -} from '~/utils/rateLimit.server' - -const maxRequestBytes = 2 * 1024 * 1024 - -function parseBuilderProjectRequest(value: unknown) { - if ( - typeof value !== 'object' || - value === null || - Array.isArray(value) || - Object.keys(value).some( - (key) => - key !== 'clientMutationId' && - key !== 'forkedFromId' && - key !== 'id' && - key !== 'project' && - key !== 'revisionId', - ) || - !('clientMutationId' in value) || - !('id' in value) || - !('project' in value) || - !('revisionId' in value) || - typeof value.clientMutationId !== 'string' || - !isBuilderProjectId(value.clientMutationId) || - typeof value.id !== 'string' || - !isBuilderProjectId(value.id) || - typeof value.revisionId !== 'string' || - !isBuilderProjectId(value.revisionId) - ) { - throw new Error('Invalid builder project request') - } - - const forkedFromId = 'forkedFromId' in value ? value.forkedFromId : undefined - if ( - forkedFromId !== undefined && - (typeof forkedFromId !== 'string' || !isBuilderProjectId(forkedFromId)) - ) { - throw new Error('Invalid fork source builder ID') - } - - return { - clientMutationId: value.clientMutationId, - id: value.id, - project: parseStoredBuilderProjectSnapshot(value.project), - revisionId: value.revisionId, - ...(forkedFromId ? { forkedFromId } : {}), - } -} -export const handlers = { - GET: async ({ request }: { request: Request }) => { - const { getAuthService } = await import('~/auth/index.server') - const user = await getAuthService().getCurrentUser(request) - if (!user) return jsonError('Not authenticated', 401) - - const rateLimit = await checkIpRateLimit( - request, - RATE_LIMITS.builderProjectList, - ) - if (!rateLimit.allowed) return rateLimitedResponse(rateLimit) - - try { - const projects = await listOrImportBuilderProjectStates(user.userId) - return jsonResponse( - { projects: projects.map(toBuilderProject) }, - { headers: rateLimit.headers }, - ) - } catch (error) { - if (error instanceof BuilderProjectSnapshotQuarantinedError) { - return jsonError( - 'Builder project is unavailable', - 410, - rateLimit.headers, - ) - } - if ( - error instanceof BuilderProjectSnapshotLimitError || - error instanceof BuilderProjectSnapshotRegistryConflictError - ) { - return jsonError(error.message, 409, rateLimit.headers) - } - if (error instanceof BuilderProjectSnapshotStorageUnavailableError) { - return jsonError( - 'Builder project storage is unavailable', - 503, - rateLimit.headers, - ) - } - if (error instanceof BuilderProjectStorageUnavailableError) { - return jsonError( - 'Builder project storage is unavailable', - 503, - rateLimit.headers, - ) - } - console.error('Failed to list builder projects:', error) - return jsonError( - 'Failed to list builder projects', - 500, - rateLimit.headers, - ) - } - }, - POST: async ({ request }: { request: Request }) => { - const requestError = validateJsonRequest(request, { - maxContentLength: maxRequestBytes, - }) - if (requestError) { - return jsonError(requestError.message, requestError.status) - } - - const { getAuthService } = await import('~/auth/index.server') - const user = await getAuthService().getCurrentUser(request) - if (!user) return jsonError('Not authenticated', 401) - - const rateLimit = await checkIpRateLimit( - request, - RATE_LIMITS.builderProjectWrite, - ) - if (!rateLimit.allowed) return rateLimitedResponse(rateLimit) - - const body = await readJsonBody(request, { - maxContentLength: maxRequestBytes, - }) - if (!body.success) { - return jsonError(body.error.message, body.error.status, rateLimit.headers) - } - - let input - try { - input = parseBuilderProjectRequest(body.body) - } catch (error) { - return jsonError( - error instanceof Error ? error.message : 'Invalid builder project', - 400, - rateLimit.headers, - ) - } - - try { - await listOrImportBuilderProjectStates(user.userId) - const snapshotHash = await getBuilderProjectSnapshotHash(input.project) - const existing = await preflightBuilderProjectCreation({ - id: input.id, - ownerId: user.userId, - clientMutationId: input.clientMutationId, - revisionId: input.revisionId, - snapshotHash, - title: input.project.title, - description: input.project.description, - ...(input.forkedFromId ? { forkedFromId: input.forkedFromId } : {}), - }) - if (existing) { - return jsonResponse( - { project: toBuilderProject(existing) }, - { status: 201, headers: rateLimit.headers }, - ) - } - const creationLimit = await checkUserWindowRateLimit( - user.userId, - RATE_LIMITS.builderProjectCreateDaily, - ) - if (!creationLimit.allowed) { - return rateLimitedResponse(creationLimit) - } - await reserveLegacyBuilderProjectId(input.id) - - if (input.forkedFromId) { - try { - await getOrImportBuilderProjectState(input.forkedFromId) - } catch (error) { - if (error instanceof BuilderProjectNotFoundError) { - return jsonError( - 'Fork source builder was not found', - 400, - rateLimit.headers, - ) - } - throw error - } - } - - const snapshot = input.project - const storedSnapshot = await storeBuilderProjectSnapshotForOwner( - user.userId, - snapshot, - ) - const state = await createBuilderProjectState({ - id: input.id, - revisionId: input.revisionId, - clientMutationId: input.clientMutationId, - description: snapshot.description, - forkedFromId: input.forkedFromId, - ownerId: user.userId, - snapshotHash: storedSnapshot.hash, - title: snapshot.title, - }) - return jsonResponse( - { project: toBuilderProject(state) }, - { status: 201, headers: rateLimit.headers }, - ) - } catch (error) { - if (error instanceof BuilderProjectLimitError) { - return jsonError(error.message, 409, rateLimit.headers) - } - if ( - error instanceof BuilderProjectSnapshotLimitError || - error instanceof BuilderProjectSnapshotRegistryConflictError - ) { - return jsonError(error.message, 409, rateLimit.headers) - } - if (error instanceof BuilderProjectConflictError) { - return jsonError(error.message, 409, rateLimit.headers) - } - if (error instanceof BuilderProjectSnapshotQuarantinedError) { - return jsonError( - 'Builder project is unavailable', - 410, - rateLimit.headers, - ) - } - if ( - error instanceof BuilderProjectStorageUnavailableError || - error instanceof BuilderProjectSnapshotStorageUnavailableError - ) { - return jsonError( - 'Builder storage is unavailable', - 503, - rateLimit.headers, - ) - } - console.error('Failed to create builder project:', error) - return jsonError( - 'Failed to create builder project', - 500, - rateLimit.headers, - ) - } - }, -} diff --git a/src/chat/server/routes/skills.ts b/src/chat/server/routes/skills.ts deleted file mode 100644 index 9c324284d..000000000 --- a/src/chat/server/routes/skills.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { hasChatAccess } from '~/chat/access.server' -import { z } from 'zod' -import { getAuthService } from '~/auth/index.server' -import { - jsonError, - validateSameOriginRequest, -} from '~/utils/api-boundary.server' -import { - readWorkspacePolicy, - WorkspacePolicyError, -} from '~/chat/workspace-policy.server' -import { - getKodyEnvironment, - KodyEnvironmentError, -} from '~/chat/server/kody-environment.server' -import { skillApi } from '~/chat/server/skill-api' -export async function handleSkills(request: Request, id?: string) { - if (request.method === 'POST') { - const error = validateSameOriginRequest(request) - if (error) return jsonError(error.message, error.status) - } - const user = await getAuthService().getCurrentUser(request) - if (!user) return jsonError('Sign in to continue.', 401) - if (!(await hasChatAccess(user))) - return jsonError('Chat access is unavailable.', 403) - const url = new URL(request.url) - const parsed = z - .string() - .min(1) - .max(1000) - .safeParse(url.searchParams.get('workspaceId')) - if (url.searchParams.getAll('workspaceId').length !== 1 || !parsed.success) - return jsonError('Choose a workspace.', 400) - try { - await readWorkspacePolicy(parsed.data, user.userId) - return await skillApi( - request, - await getKodyEnvironment(), - { workspaceId: parsed.data, userId: user.userId }, - id ?? url.searchParams.get('id') ?? undefined, - ) - } catch (error) { - if ( - error instanceof WorkspacePolicyError || - error instanceof KodyEnvironmentError - ) - return jsonError(error.message, error.status) - throw error - } -} -export const handlers = { - GET: ({ request }: { request: Request }) => handleSkills(request), - POST: ({ request }: { request: Request }) => handleSkills(request), -} diff --git a/src/components/Navbar.tsx b/src/components/Navbar.tsx index fc6171e5a..1d6c29b84 100644 --- a/src/components/Navbar.tsx +++ b/src/components/Navbar.tsx @@ -849,7 +849,7 @@ function DesktopNavTrigger({ data-menu-key={group.key} className={triggerClassName} onClick={onDismiss} - preload={group.key === 'chat' ? false : 'intent'} + preload="intent" > {group.label} {group.key === 'chat' && ( diff --git a/src/components/ds/IconographyPage.client.tsx b/src/components/ds/IconographyPage.client.tsx deleted file mode 100644 index 99bccfd7e..000000000 --- a/src/components/ds/IconographyPage.client.tsx +++ /dev/null @@ -1,219 +0,0 @@ -import * as React from 'react' -import { twMerge } from 'tailwind-merge' -import { - CaretDownIcon, - CheckIcon, - MagnifyingGlassIcon, - StarIcon, -} from '@phosphor-icons/react' -import type { IconWeight } from '@phosphor-icons/react' -import { copyTextToClipboard } from '~/utils/browser-effects' -import { DsPage, DsSection } from '~/components/ds/DsKit' -import { phosphorIconRegistry } from '~/components/ds/phosphor-icons.generated' -import { - Dropdown, - DropdownContent, - DropdownItem, - DropdownTrigger, -} from '~/components/ds/ui' - -const WEIGHTS: Array = [ - 'thin', - 'light', - 'regular', - 'bold', - 'fill', - 'duotone', -] -const SIZES = [16, 20, 24, 32, 48] -const PAGE_SIZE = 120 - -const triggerClass = - 'inline-flex h-10 items-center gap-2 rounded-lg border border-border-default bg-background-surface px-3 text-sm text-text-primary transition-colors hover:bg-background-subtle' - -// A small square that scales with the icon size — the visual size cue. -function SizeGlyph({ px }: { px: number }) { - const box = Math.max(8, Math.min(22, Math.round(px * 0.5))) - return ( - - ) -} - -export function IconographyPage() { - const [weight, setWeight] = React.useState('regular') - const [size, setSize] = React.useState(24) - const [query, setQuery] = React.useState('') - const [searchOpen, setSearchOpen] = React.useState(false) - const [copied, setCopied] = React.useState(null) - const [visible, setVisible] = React.useState(PAGE_SIZE) - const searchInputRef = React.useRef(null) - - React.useEffect(() => { - if (searchOpen) searchInputRef.current?.focus() - }, [searchOpen]) - - const closeSearch = React.useCallback(() => { - setQuery('') - setSearchOpen(false) - }, []) - - const filtered = React.useMemo(() => { - const q = query.trim().toLowerCase() - if (!q) return phosphorIconRegistry - return phosphorIconRegistry.filter((icon) => - icon.name.toLowerCase().includes(q), - ) - }, [query]) - - // Reset paging when the result set changes. - React.useEffect(() => { - setVisible(PAGE_SIZE) - }, [query]) - - const shown = filtered.slice(0, visible) - - // The registry keys icons by their bare name, but `NameIcon` is the export - // callers actually import — copy and advertise that one. - const handleCopy = React.useCallback(async (name: string) => { - await copyTextToClipboard(`<${name}Icon />`) - setCopied(name) - window.setTimeout(() => setCopied(null), 1200) - }, []) - - return ( - - -
- {/* Style (weight) — dropdown with a live preview per weight */} - - - - - - {WEIGHTS.map((w) => ( - setWeight(w)}> - - {w} - {w === weight ? ( - - ) : null} - - ))} - - - - {/* Size — dropdown with a scaling size glyph per option */} - - - - - - {SIZES.map((s) => ( - setSize(s)}> - - - - {s}px - {s === size ? ( - - ) : null} - - ))} - - - - {/* Expanding search — icon grows on hover, opens into a field */} -
- - setQuery(e.target.value)} - onKeyDown={(e) => e.key === 'Escape' && closeSearch()} - placeholder="Search icons…" - className={twMerge( - 'min-w-0 flex-1 bg-transparent pr-3 text-sm text-text-primary placeholder-text-muted outline-none transition-opacity duration-200', - searchOpen ? 'opacity-100' : 'pointer-events-none opacity-0', - )} - /> -
- - - {filtered.length.toLocaleString()} icons - -
- -
- {shown.map(({ name, Cmp }) => ( - - ))} -
- - {shown.length < filtered.length ? ( -
- -
- ) : null} -
-
- ) -} diff --git a/src/db/client.ts b/src/db/client.ts index 12e0b1e51..9563d0a7a 100644 --- a/src/db/client.ts +++ b/src/db/client.ts @@ -1,7 +1,3 @@ -import { - markRequestDatabaseUse, - timeRequestWork, -} from '../utils/request-timing.server' import { drizzle } from 'drizzle-orm/postgres-js' import postgres from 'postgres' import { AsyncLocalStorage } from 'node:async_hooks' @@ -67,7 +63,6 @@ function getRequestDb(context: DatabaseContext) { } function getDb() { - markRequestDatabaseUse() const context = databaseStorage.getStore() if (context) { return getRequestDb(context) @@ -92,10 +87,7 @@ export async function runWithDatabaseContext( return fn() } - const connectionString = await timeRequestWork( - 'db_config', - getDatabaseConnectionString, - ) + const connectionString = await getDatabaseConnectionString() if (!connectionString) { return fn() } diff --git a/src/queries/docsManifest.ts b/src/queries/docsManifest.ts deleted file mode 100644 index 7d307e5db..000000000 --- a/src/queries/docsManifest.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { queryOptions } from '@tanstack/react-query' -import { fetchDocsPathManifest } from '~/utils/docs.functions' - -export function docsPathManifestQueryOptions(request: { - repo: string - branch: string - docsRoot: string -}) { - const { repo, branch, docsRoot } = request - - return queryOptions({ - queryKey: ['docs-path-manifest', repo, branch, docsRoot], - queryFn: () => fetchDocsPathManifest({ data: { repo, branch, docsRoot } }), - staleTime: 1000 * 60 * 5, - }) -} diff --git a/src/routes/__root.tsx b/src/routes/__root.tsx index 27716d291..bec6e5ce1 100644 --- a/src/routes/__root.tsx +++ b/src/routes/__root.tsx @@ -40,11 +40,10 @@ import { ThemeProvider, useHtmlClass } from '~/components/ThemeProvider' import { Navbar } from '~/components/Navbar' import { Footer } from '~/components/Footer' import { ProductScarf } from '~/components/ProductScarf' -const BuilderRouteContent = React.lazy(() => - import('~/chat/components/projects/Loading').then((module) => ({ - default: module.BuilderRouteContent, - })), -) +import { + BuilderRouteFrame, + BuilderRouteSkeleton, +} from '~/chat/components/projects/Loading' import { THEME_COLORS } from '~/utils/utils' import { trackPageView } from '~/utils/analytics' import { @@ -344,15 +343,11 @@ function ShellComponent({ children }: { children: React.ReactNode }) { const htmlClass = useHtmlClass() const routeContent = ( - - {pathname === '/builder' || pathname.startsWith('/builder/') ? ( - - {children} - - ) : ( - children - )} - + + }> + {children} + + ) return ( diff --git a/src/routes/_library/$libraryId/$version.docs.$.tsx b/src/routes/_library/$libraryId/$version.docs.$.tsx index 1690b432c..a8919cbb8 100644 --- a/src/routes/_library/$libraryId/$version.docs.$.tsx +++ b/src/routes/_library/$libraryId/$version.docs.$.tsx @@ -37,7 +37,6 @@ export const Route = createFileRoute('/_library/$libraryId/$version/docs/$')({ const docsRoot = library.docsRoot || 'docs' const requestedDocsPath = docsPath ?? '' const result = await loadDocsRoute({ - queryClient: ctx.context.queryClient, repo: library.repo, branch, docsRoot, @@ -127,7 +126,6 @@ export const Route = createFileRoute('/_library/$libraryId/$version/docs/$')({ return { ...getDocsCacheHeaders({ libraryId, version }), - 'X-Docs-Html': loaderData?.isFallback ? 'no-store' : '1', ...getDocsEmbedRuntimeHeaders({ content: loaderData?.content ?? '', version, diff --git a/src/routes/_library/$libraryId/$version.docs.framework.$framework.$.tsx b/src/routes/_library/$libraryId/$version.docs.framework.$framework.$.tsx index c35243ddc..f028d6fac 100644 --- a/src/routes/_library/$libraryId/$version.docs.framework.$framework.$.tsx +++ b/src/routes/_library/$libraryId/$version.docs.framework.$framework.$.tsx @@ -36,7 +36,6 @@ export const Route = createFileRoute( const docsRoot = library.docsRoot || 'docs' const requestedDocsPath = `framework/${framework}/${docsPath ?? ''}` const result = await loadDocsRoute({ - queryClient: ctx.context.queryClient, repo: library.repo, branch, docsRoot, @@ -84,7 +83,6 @@ export const Route = createFileRoute( return { ...getDocsCacheHeaders({ libraryId, version }), - 'X-Docs-Html': loaderData?.isFallback ? 'no-store' : '1', ...getDocsEmbedRuntimeHeaders({ content: loaderData?.content ?? '', version, diff --git a/src/routes/admin/chat-access.tsx b/src/routes/admin/chat-access.tsx index 2eb894f2c..b46fc56af 100644 --- a/src/routes/admin/chat-access.tsx +++ b/src/routes/admin/chat-access.tsx @@ -35,7 +35,7 @@ export const Route = createFileRoute('/admin/chat-access')({ component: ChatAccessAdminPage, }) -function ChatAccessAdminPage() { +export function ChatAccessAdminPage() { const guard = useAdminGuard() const queryClient = useQueryClient() const [tab, setTab] = useState<'waitlist' | 'invites'>('waitlist') diff --git a/src/routes/api/application-starter/compile-attributed.ts b/src/routes/api/application-starter/compile-attributed.ts index 829d53f91..4eab27ac3 100644 --- a/src/routes/api/application-starter/compile-attributed.ts +++ b/src/routes/api/application-starter/compile-attributed.ts @@ -1,12 +1,50 @@ import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' +import { + applicationStarterErrorResponse, + applicationStarterInternalErrorResponse, + applicationStarterJsonResponse, + readApplicationStarterJsonRequest, +} from '~/application-starter/api/request-boundary.server' +import { + applicationStarterValidateBodySchema, + parseApplicationStarterRequest, +} from '~/application-starter/api/request-schema.server' -export const Route = createFileRoute( - '/api/application-starter/compile-attributed', -)({ +export const Route = createFileRoute('/api/application-starter/compile-attributed')({ server: { handlers: { - POST: ({ request }) => forwardWorkerRequest('STARTER', request), + POST: async ({ request }: { request: Request }) => { + try { + const requestBody = await readApplicationStarterJsonRequest(request) + if ('response' in requestBody) { + return requestBody.response + } + + let body + try { + body = parseApplicationStarterRequest( + applicationStarterValidateBodySchema, + requestBody.body, + ) + } catch { + return applicationStarterErrorResponse( + 'Invalid request body', + 400, + requestBody.rateLimit, + ) + } + + const { compileWithAttributionHandler } = await import( + '~/application-starter/api/compile' + ) + const response = await compileWithAttributionHandler(body.definition) + + return applicationStarterJsonResponse(response, requestBody.rateLimit) + } catch (error) { + console.error('Error compiling project with attribution:', error) + return applicationStarterInternalErrorResponse('Failed to compile project') + } + }, }, }, }) diff --git a/src/routes/api/application-starter/compile.ts b/src/routes/api/application-starter/compile.ts index 55f95454b..18fb22cfb 100644 --- a/src/routes/api/application-starter/compile.ts +++ b/src/routes/api/application-starter/compile.ts @@ -1,10 +1,49 @@ import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' +import { + applicationStarterErrorResponse, + applicationStarterInternalErrorResponse, + applicationStarterJsonResponse, + readApplicationStarterJsonRequest, +} from '~/application-starter/api/request-boundary.server' +import { + applicationStarterCompileBodySchema, + parseApplicationStarterRequest, +} from '~/application-starter/api/request-schema.server' export const Route = createFileRoute('/api/application-starter/compile')({ server: { handlers: { - POST: ({ request }) => forwardWorkerRequest('STARTER', request), + POST: async ({ request }: { request: Request }) => { + try { + const requestBody = await readApplicationStarterJsonRequest(request) + if ('response' in requestBody) { + return requestBody.response + } + + let body + try { + body = parseApplicationStarterRequest( + applicationStarterCompileBodySchema, + requestBody.body, + ) + } catch { + return applicationStarterErrorResponse( + 'Invalid request body', + 400, + requestBody.rateLimit, + ) + } + + const { compileHandler } = await import('~/application-starter/api/compile') + const response = await compileHandler(body.definition, { + format: body.format, + }) + return applicationStarterJsonResponse(response, requestBody.rateLimit) + } catch (error) { + console.error('Error compiling project:', error) + return applicationStarterInternalErrorResponse('Failed to compile project') + } + }, }, }, }) diff --git a/src/routes/api/application-starter/deploy/check-name.ts b/src/routes/api/application-starter/deploy/check-name.ts index ced4bd6e0..fd7d65133 100644 --- a/src/routes/api/application-starter/deploy/check-name.ts +++ b/src/routes/api/application-starter/deploy/check-name.ts @@ -1,12 +1,84 @@ -import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' +import { createFileRoute } from "@tanstack/react-router"; +import { validateApplicationStarterGetRequest } from "~/application-starter/api/request-boundary.server"; +import { jsonResponse } from "~/utils/api-boundary.server"; +import { RATE_LIMITS } from "~/utils/rateLimit.server"; -export const Route = createFileRoute( - '/api/application-starter/deploy/check-name', -)({ +export const Route = createFileRoute("/api/application-starter/deploy/check-name")({ server: { handlers: { - GET: ({ request }) => forwardWorkerRequest('STARTER', request), + GET: async ({ request }: { request: Request }) => { + const requestGuard = await validateApplicationStarterGetRequest(request, { + rateLimit: RATE_LIMITS.deploy, + }); + if ("response" in requestGuard) { + return requestGuard.response; + } + + const [ + { getAuthService }, + { getGitHubAuthState }, + { checkRepoNameAvailable, validateRepoName }, + ] = await Promise.all([ + import("~/auth/index.server"), + import("~/auth/github.server"), + import("~/utils/github-repo.server"), + ]); + const url = new URL(request.url); + const name = url.searchParams.get("name"); + + if (!name) { + return jsonResponse( + { available: false, error: "Name required" }, + { status: 400, headers: requestGuard.rateLimit.headers }, + ); + } + + const validation = validateRepoName(name); + if (!validation.valid) { + return jsonResponse( + { + available: false, + error: validation.error ?? "Invalid repository name", + }, + { status: 400, headers: requestGuard.rateLimit.headers }, + ); + } + + const authService = getAuthService(); + const user = await authService.getCurrentUser(request); + + if (!user) { + return jsonResponse( + { available: false, error: "Not authenticated" }, + { status: 401, headers: requestGuard.rateLimit.headers }, + ); + } + + const authState = await getGitHubAuthState(user.userId); + + if (!authState.hasRepoScope || !authState.accessToken) { + return jsonResponse( + { available: false, error: "Missing scope" }, + { status: 403, headers: requestGuard.rateLimit.headers }, + ); + } + + try { + const available = await checkRepoNameAvailable( + authState.accessToken, + name, + ); + return jsonResponse( + { available }, + { headers: requestGuard.rateLimit.headers }, + ); + } catch { + return jsonResponse( + { available: false, error: "Could not check repository name" }, + { status: 502, headers: requestGuard.rateLimit.headers }, + ); + } + }, }, }, -}) +}); diff --git a/src/routes/api/application-starter/deploy/github.ts b/src/routes/api/application-starter/deploy/github.ts index 60bac4587..b3234607e 100644 --- a/src/routes/api/application-starter/deploy/github.ts +++ b/src/routes/api/application-starter/deploy/github.ts @@ -1,11 +1,332 @@ -import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' +import { createFileRoute } from "@tanstack/react-router"; +import { + jsonResponse, + readJsonBody, + validateJsonRequest, +} from "~/utils/api-boundary.server"; +import { + applicationStarterDeployBodySchema, + parseApplicationStarterRequest, +} from "~/application-starter/api/request-schema.server"; +import { + checkIpRateLimit, + rateLimitedResponse, + RATE_LIMITS, +} from "~/utils/rateLimit.server"; -export const Route = createFileRoute('/api/application-starter/deploy/github')({ +interface DeployResponse { + success: true; + repoUrl: string; + owner: string; + repoName: string; +} + +interface DeployError { + success: false; + error: string; + code: + | "NOT_AUTHENTICATED" + | "NO_GITHUB_ACCOUNT" + | "MISSING_REPO_SCOPE" + | "INVALID_REPO_NAME" + | "REPO_NAME_TAKEN" + | "REPO_CREATION_FAILED" + | "PUSH_FAILED" + | "COMPILE_FAILED" + | "INVALID_REQUEST"; +} + +function deployErrorResponse(error: DeployError, status: number, headers?: Headers) { + return jsonResponse(error, { status, headers }); +} + +export const Route = createFileRoute("/api/application-starter/deploy/github")({ server: { handlers: { - GET: ({ request }) => forwardWorkerRequest('STARTER', request), - POST: ({ request }) => forwardWorkerRequest('STARTER', request), + /** + * GET: Check GitHub auth state for current user + */ + GET: async ({ request }: { request: Request }) => { + const [{ getAuthService }, { getGitHubAuthState }] = await Promise.all([ + import("~/auth/index.server"), + import("~/auth/github.server"), + ]); + const authService = getAuthService(); + const user = await authService.getCurrentUser(request); + + if (!user) { + return jsonResponse({ + authenticated: false, + hasGitHubAccount: false, + hasRepoScope: false, + }); + } + + const authState = await getGitHubAuthState(user.userId); + + return jsonResponse({ + authenticated: true, + ...authState, + }); + }, + + /** + * POST: Create GitHub repo and push project files + */ + POST: async ({ request }: { request: Request }) => { + const [authIndex, authGithub, githubRepo] = await Promise.all([ + import("~/auth/index.server"), + import("~/auth/github.server"), + import("~/utils/github-repo.server"), + ]); + const { getAuthService } = authIndex; + const { getGitHubAuthState } = authGithub; + const { + createRepository, + pushFiles, + validateRepoName, + validateGitHubFiles, + generateRepoDescription, + } = githubRepo; + // Rate limiting (10 requests/minute per IP) + const rateLimit = await checkIpRateLimit(request, RATE_LIMITS.deploy); + if (!rateLimit.allowed) { + return rateLimitedResponse(rateLimit); + } + + const guardError = validateJsonRequest(request, { + maxContentLength: 1024 * 1024, + }); + if (guardError) { + return deployErrorResponse( + { + success: false, + error: guardError.message, + code: "INVALID_REQUEST", + }, + guardError.status, + rateLimit.headers, + ); + } + + const authService = getAuthService(); + const user = await authService.getCurrentUser(request); + + if (!user) { + return deployErrorResponse( + { + success: false, + error: "You must be logged in to deploy", + code: "NOT_AUTHENTICATED", + }, + 401, + rateLimit.headers, + ); + } + + const authState = await getGitHubAuthState(user.userId); + + if (!authState.hasGitHubAccount) { + return deployErrorResponse( + { + success: false, + error: "No GitHub account linked", + code: "NO_GITHUB_ACCOUNT", + }, + 403, + rateLimit.headers, + ); + } + + if (!authState.hasRepoScope || !authState.accessToken) { + console.log("[Deploy] Auth state check failed:", { + hasRepoScope: authState.hasRepoScope, + hasToken: !!authState.accessToken, + }); + return deployErrorResponse( + { + success: false, + error: + "Missing public_repo scope. Please re-authenticate with GitHub.", + code: "MISSING_REPO_SCOPE", + }, + 403, + rateLimit.headers, + ); + } + console.log( + "[Deploy] Auth state OK, hasRepoScope:", + authState.hasRepoScope, + ); + + let body; + try { + const bodyResult = await readJsonBody(request, { + maxContentLength: 1024 * 1024, + }); + if (!bodyResult.success) { + throw new Error(bodyResult.error.message); + } + body = parseApplicationStarterRequest(applicationStarterDeployBodySchema, bodyResult.body); + } catch { + return deployErrorResponse( + { + success: false, + error: "Invalid request body", + code: "INVALID_REQUEST", + }, + 400, + rateLimit.headers, + ); + } + + const { + repoName, + isPrivate, + projectName, + framework, + packageManager, + features, + featureOptions, + tailwind, + files, + } = body; + const safeFeatureOptions = featureOptions ?? {}; + + // Validate repo name + const validation = validateRepoName(repoName); + if (!validation.valid) { + return deployErrorResponse( + { + success: false, + error: validation.error ?? "Invalid repository name", + code: "INVALID_REPO_NAME", + }, + 400, + rateLimit.headers, + ); + } + + // Compile the project, or use files generated by the client-only applicationStarter. + let compiledFiles: Record; + if (files) { + const fileValidation = validateGitHubFiles(files); + if (!fileValidation.valid) { + return deployErrorResponse( + { + success: false, + error: fileValidation.error, + code: "INVALID_REQUEST", + }, + 400, + rateLimit.headers, + ); + } + compiledFiles = files; + } else { + try { + const { compileHandler } = await import("~/application-starter/api/compile"); + const result = await compileHandler({ + name: projectName, + framework, + packageManager, + tailwind, + features, + featureOptions: safeFeatureOptions, + }); + compiledFiles = result.files; + } catch (error) { + console.error("[Deploy] Compile failed:", error); + return deployErrorResponse( + { + success: false, + error: "Failed to compile project", + code: "COMPILE_FAILED", + }, + 500, + rateLimit.headers, + ); + } + } + + const compiledFileValidation = validateGitHubFiles(compiledFiles); + if (!compiledFileValidation.valid) { + return deployErrorResponse( + { + success: false, + error: compiledFileValidation.error, + code: "INVALID_REQUEST", + }, + 400, + rateLimit.headers, + ); + } + + // Create the repository + const description = generateRepoDescription(features); + console.log("[Deploy] Creating repository:", { + repoName, + isPrivate, + description, + }); + const createResult = await createRepository(authState.accessToken, { + name: repoName, + description, + isPrivate, + }); + + if (!createResult.success) { + console.error("[Deploy] Repository creation failed:", { + error: createResult.error, + code: createResult.code, + }); + const code = + createResult.code === "NAME_TAKEN" + ? "REPO_NAME_TAKEN" + : "REPO_CREATION_FAILED"; + return deployErrorResponse( + { + success: false, + error: createResult.error, + code, + }, + code === "REPO_NAME_TAKEN" ? 409 : 500, + rateLimit.headers, + ); + } + console.log("[Deploy] Repository created:", createResult.repoUrl); + + // Push files to the repository + const pushResult = await pushFiles(authState.accessToken, { + owner: createResult.owner, + repo: createResult.name, + files: compiledFiles, + message: "Initial commit from TanStack Application Starter", + }); + + if (!pushResult.success) { + console.error("[Deploy] Push failed:", pushResult.error); + return deployErrorResponse( + { + success: false, + error: `Repository created but failed to push files: ${pushResult.error}`, + code: "PUSH_FAILED", + }, + 500, + rateLimit.headers, + ); + } + + return jsonResponse( + { + success: true, + repoUrl: createResult.repoUrl, + owner: createResult.owner, + repoName: createResult.name, + } satisfies DeployResponse, + { headers: rateLimit.headers }, + ); + }, }, }, -}) +}); diff --git a/src/routes/api/application-starter/download.ts b/src/routes/api/application-starter/download.ts index e7cb00de5..2b343171c 100644 --- a/src/routes/api/application-starter/download.ts +++ b/src/routes/api/application-starter/download.ts @@ -1,10 +1,142 @@ -import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' +import { createFileRoute } from "@tanstack/react-router"; +import JSZip from "jszip"; +import { + getContentDispositionHeader, + sanitizeResponseFilename, +} from "~/utils/http-response"; +import { + applicationStarterErrorResponse, + applicationStarterInternalErrorResponse, + validateApplicationStarterGetRequest, +} from "~/application-starter/api/request-boundary.server"; -export const Route = createFileRoute('/api/application-starter/download')({ +const BASE64_PREFIX = "base64::"; +const MAX_BUILDER_DOWNLOAD_FEATURES = 80; +const MAX_BUILDER_DOWNLOAD_OPTIONS = 200; +const BUILDER_ID_PATTERN = /^[a-z0-9._-]{1,120}$/i; +const BUILDER_PROJECT_NAME_PATTERN = /^[a-z0-9][a-z0-9_-]{0,119}$/; + +function decodeBase64File(content: string): Uint8Array | null { + if (content.startsWith(BASE64_PREFIX)) { + const decoded = atob(content.slice(BASE64_PREFIX.length)); + + return Uint8Array.from(decoded, (char) => char.charCodeAt(0)); + } + + return null; +} + +export const Route = createFileRoute("/api/application-starter/download")({ server: { handlers: { - GET: ({ request }) => forwardWorkerRequest('STARTER', request), + GET: async ({ request }: { request: Request }) => { + try { + const requestGuard = await validateApplicationStarterGetRequest(request); + if ("response" in requestGuard) { + return requestGuard.response; + } + + const url = new URL(request.url); + const name = url.searchParams.get("name") || "my-tanstack-app"; + const featuresParam = url.searchParams.get("features") || ""; + const framework = url.searchParams.get("framework") || "react"; + const packageManager = url.searchParams.get("pm") || "pnpm"; + const tailwind = url.searchParams.get("tailwind") !== "false"; + + const features = featuresParam + .split(",") + .map((f) => f.trim()) + .filter(Boolean); + + if ( + !BUILDER_PROJECT_NAME_PATTERN.test(name) || + features.length > MAX_BUILDER_DOWNLOAD_FEATURES || + features.some((feature) => !BUILDER_ID_PATTERN.test(feature)) + ) { + return applicationStarterErrorResponse( + "Invalid applicationStarter download request", + 400, + requestGuard.rateLimit, + ); + } + + // Parse feature options (keys like "drizzle.database=postgres") + const featureOptions: Record> = {}; + let optionCount = 0; + for (const [key, value] of url.searchParams.entries()) { + if (key.includes(".") && value) { + const [featureId, optionKey] = key.split("."); + optionCount++; + if ( + optionCount > MAX_BUILDER_DOWNLOAD_OPTIONS || + !BUILDER_ID_PATTERN.test(featureId) || + !BUILDER_ID_PATTERN.test(optionKey) || + value.length > 500 + ) { + return applicationStarterErrorResponse( + "Invalid applicationStarter download options", + 400, + requestGuard.rateLimit, + ); + } + if (!featureOptions[featureId]) { + featureOptions[featureId] = {}; + } + featureOptions[featureId][optionKey] = value; + } + } + + const { compileHandler } = await import("~/application-starter/api/compile"); + const result = await compileHandler({ + name, + framework: framework === "solid" ? "solid" : "react", + packageManager: + packageManager === "bun" || + packageManager === "npm" || + packageManager === "yarn" + ? packageManager + : "pnpm", + tailwind, + features, + featureOptions, + }); + + const zip = new JSZip(); + const zipFilename = sanitizeResponseFilename(`${name}.zip`, "app.zip"); + const rootFolderName = sanitizeResponseFilename(name, "app"); + const rootFolder = zip.folder(rootFolderName); + if (!rootFolder) { + throw new Error("Failed to create ZIP folder"); + } + + for (const [filePath, content] of Object.entries(result.files)) { + // Handle base64-encoded binary files (SVGs, images, etc.) + const binaryContent = decodeBase64File(content); + if (binaryContent) { + rootFolder.file(filePath, binaryContent, { binary: true }); + } else { + rootFolder.file(filePath, content); + } + } + + const blob = await zip.generateAsync({ type: "arraybuffer" }); + + return new Response(blob, { + headers: { + "Content-Type": "application/zip", + "Content-Disposition": getContentDispositionHeader( + "attachment", + zipFilename, + "app.zip", + ), + "Cache-Control": "no-store", + }, + }); + } catch (error) { + console.error("Error generating ZIP:", error); + return applicationStarterInternalErrorResponse("Failed to generate ZIP"); + } + }, }, }, -}) +}); diff --git a/src/routes/api/application-starter/feature-artifacts.ts b/src/routes/api/application-starter/feature-artifacts.ts index 51a8e83c5..e721cd0ce 100644 --- a/src/routes/api/application-starter/feature-artifacts.ts +++ b/src/routes/api/application-starter/feature-artifacts.ts @@ -1,12 +1,59 @@ import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' +import { normalizeFrameworkId } from '~/application-starter/frameworks' +import { + applicationStarterErrorResponse, + applicationStarterInternalErrorResponse, + applicationStarterJsonResponse, + readApplicationStarterJsonRequest, +} from '~/application-starter/api/request-boundary.server' +import { + applicationStarterFeatureArtifactsBodySchema, + parseApplicationStarterRequest, +} from '~/application-starter/api/request-schema.server' -export const Route = createFileRoute( - '/api/application-starter/feature-artifacts', -)({ +export const Route = createFileRoute('/api/application-starter/feature-artifacts')({ server: { handlers: { - POST: ({ request }) => forwardWorkerRequest('STARTER', request), + POST: async ({ request }: { request: Request }) => { + try { + const requestBody = await readApplicationStarterJsonRequest(request) + if ('response' in requestBody) { + return requestBody.response + } + + let body + try { + body = parseApplicationStarterRequest( + applicationStarterFeatureArtifactsBodySchema, + requestBody.body, + ) + } catch { + return applicationStarterErrorResponse( + 'Invalid request body', + 400, + requestBody.rateLimit, + ) + } + + const { featureArtifactsHandler } = await import( + '~/application-starter/api/feature-artifacts' + ) + const response = await featureArtifactsHandler({ + features: body.features, + projectName: body.projectName, + framework: normalizeFrameworkId(body.framework), + featureOptions: body.featureOptions, + tailwind: body.tailwind, + }) + + return applicationStarterJsonResponse(response, requestBody.rateLimit) + } catch (error) { + console.error('Error fetching feature artifacts:', error) + return applicationStarterInternalErrorResponse( + 'Failed to fetch feature artifacts', + ) + } + }, }, }, }) diff --git a/src/routes/api/application-starter/features.ts b/src/routes/api/application-starter/features.ts index 5f4bf86c1..981941ce0 100644 --- a/src/routes/api/application-starter/features.ts +++ b/src/routes/api/application-starter/features.ts @@ -1,10 +1,31 @@ import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' +import { normalizeFrameworkId } from '~/application-starter/frameworks' export const Route = createFileRoute('/api/application-starter/features')({ server: { handlers: { - GET: ({ request }) => forwardWorkerRequest('STARTER', request), + GET: async ({ request }: { request: Request }) => { + try { + const url = new URL(request.url) + const framework = normalizeFrameworkId( + url.searchParams.get('framework') ?? 'react', + ) + const { getFeaturesHandler } = await import('~/application-starter/api/features') + const response = await getFeaturesHandler(framework) + return new Response(JSON.stringify(response), { + headers: { 'Content-Type': 'application/json' }, + }) + } catch (error) { + console.error('Error fetching features:', error) + return new Response( + JSON.stringify({ error: 'Failed to fetch features' }), + { + status: 500, + headers: { 'Content-Type': 'application/json' }, + }, + ) + } + }, }, }, }) diff --git a/src/routes/api/application-starter/load-remote-addon.ts b/src/routes/api/application-starter/load-remote-addon.ts index 18a328eeb..851657737 100644 --- a/src/routes/api/application-starter/load-remote-addon.ts +++ b/src/routes/api/application-starter/load-remote-addon.ts @@ -1,12 +1,35 @@ -import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' +import { createFileRoute } from "@tanstack/react-router"; +import { + applicationStarterErrorResponse, + applicationStarterJsonResponse, + validateApplicationStarterGetRequest, +} from "~/application-starter/api/request-boundary.server"; +import { RATE_LIMITS } from "~/utils/rateLimit.server"; -export const Route = createFileRoute( - '/api/application-starter/load-remote-addon', -)({ +export const Route = createFileRoute("/api/application-starter/load-remote-addon")({ server: { handlers: { - GET: ({ request }) => forwardWorkerRequest('STARTER', request), + GET: async ({ request }: { request: Request }) => { + const requestGuard = await validateApplicationStarterGetRequest(request, { + rateLimit: RATE_LIMITS.applicationStarterRemote, + }); + if ("response" in requestGuard) { + return requestGuard.response; + } + + const url = new URL(request.url); + const integrationUrl = url.searchParams.get("url"); + + if (!integrationUrl) { + return applicationStarterErrorResponse("URL is required", 400, requestGuard.rateLimit); + } + + const { loadRemoteIntegrationHandler } = await import( + "~/application-starter/api/remote", + ); + const response = await loadRemoteIntegrationHandler(integrationUrl); + return applicationStarterJsonResponse(response, requestGuard.rateLimit); + }, }, }, -}) +}); diff --git a/src/routes/api/application-starter/load-remote-template.ts b/src/routes/api/application-starter/load-remote-template.ts index 5e3028a76..efd90f95d 100644 --- a/src/routes/api/application-starter/load-remote-template.ts +++ b/src/routes/api/application-starter/load-remote-template.ts @@ -1,12 +1,33 @@ -import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' +import { createFileRoute } from "@tanstack/react-router"; +import { + applicationStarterErrorResponse, + applicationStarterJsonResponse, + validateApplicationStarterGetRequest, +} from "~/application-starter/api/request-boundary.server"; +import { RATE_LIMITS } from "~/utils/rateLimit.server"; -export const Route = createFileRoute( - '/api/application-starter/load-remote-template', -)({ +export const Route = createFileRoute("/api/application-starter/load-remote-template")({ server: { handlers: { - GET: ({ request }) => forwardWorkerRequest('STARTER', request), + GET: async ({ request }: { request: Request }) => { + const requestGuard = await validateApplicationStarterGetRequest(request, { + rateLimit: RATE_LIMITS.applicationStarterRemote, + }); + if ("response" in requestGuard) { + return requestGuard.response; + } + + const url = new URL(request.url); + const templateUrl = url.searchParams.get("url"); + + if (!templateUrl) { + return applicationStarterErrorResponse("URL is required", 400, requestGuard.rateLimit); + } + + const { loadRemoteTemplateHandler } = await import("~/application-starter/api/remote"); + const response = await loadRemoteTemplateHandler(templateUrl); + return applicationStarterJsonResponse(response, requestGuard.rateLimit); + }, }, }, -}) +}); diff --git a/src/routes/api/application-starter/load-template.ts b/src/routes/api/application-starter/load-template.ts index a50f792c3..cd3d59b90 100644 --- a/src/routes/api/application-starter/load-template.ts +++ b/src/routes/api/application-starter/load-template.ts @@ -1,10 +1,51 @@ -import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' +import { createFileRoute } from "@tanstack/react-router"; +import { + applicationStarterErrorResponse, + applicationStarterJsonResponse, + readApplicationStarterJsonRequest, +} from "~/application-starter/api/request-boundary.server"; +import { + applicationStarterRemoteLoadBodySchema, + parseApplicationStarterRequest, +} from "~/application-starter/api/request-schema.server"; +import { RATE_LIMITS } from "~/utils/rateLimit.server"; -export const Route = createFileRoute('/api/application-starter/load-template')({ +export const Route = createFileRoute("/api/application-starter/load-template")({ server: { handlers: { - POST: ({ request }) => forwardWorkerRequest('STARTER', request), + POST: async ({ request }: { request: Request }) => { + try { + const requestBody = await readApplicationStarterJsonRequest(request, { + rateLimit: RATE_LIMITS.applicationStarterRemote, + }); + if ("response" in requestBody) { + return requestBody.response; + } + + let body; + try { + body = parseApplicationStarterRequest( + applicationStarterRemoteLoadBodySchema, + requestBody.body, + ); + } catch { + return applicationStarterErrorResponse( + "Invalid request body", + 400, + requestBody.rateLimit, + ); + } + + const { loadRemoteTemplateHandler } = await import( + "~/application-starter/api/remote", + ); + const response = await loadRemoteTemplateHandler(body.url); + return applicationStarterJsonResponse(response, requestBody.rateLimit); + } catch (error) { + console.error("Error loading remote template:", error); + return applicationStarterErrorResponse("Failed to load remote template", 500); + } + }, }, }, -}) +}); diff --git a/src/routes/api/application-starter/resolve.ts b/src/routes/api/application-starter/resolve.ts index edb676170..5e8975635 100644 --- a/src/routes/api/application-starter/resolve.ts +++ b/src/routes/api/application-starter/resolve.ts @@ -1,11 +1,206 @@ import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' +import { + checkIpWindowRateLimit, + checkIpRateLimit, + getIpWindowRateLimitStatus, + RATE_LIMITS, + rateLimitedResponse, +} from '~/utils/rateLimit.server' +import { envFunctions } from '~/utils/env.functions' +import { + isRecord, + readJsonBody, + validateJsonRequest, +} from '~/utils/api-boundary.server' + +const MAX_APPLICATION_STARTER_BODY_BYTES = 16 * 1024 export const Route = createFileRoute('/api/application-starter/resolve')({ server: { handlers: { - GET: ({ request }) => forwardWorkerRequest('STARTER', request), - POST: ({ request }) => forwardWorkerRequest('STARTER', request), + GET: async ({ request }: { request: Request }) => { + try { + if (!envFunctions.DATABASE_URL) { + return new Response( + JSON.stringify({ + authenticated: false, + anonymousGenerationQuota: { + limit: RATE_LIMITS.applicationStarterAnonymousDaily.limit, + remaining: RATE_LIMITS.applicationStarterAnonymousDaily.limit, + resetAt: new Date( + Date.now() + + RATE_LIMITS.applicationStarterAnonymousDaily.windowMs, + ).toISOString(), + }, + }), + { + headers: { + 'Cache-Control': 'no-store', + 'Content-Type': 'application/json', + }, + }, + ) + } + + const [{ getAuthService }, anonymousQuota] = await Promise.all([ + import('~/auth/index.server'), + getIpWindowRateLimitStatus( + request, + RATE_LIMITS.applicationStarterAnonymousDaily, + ), + ]) + + const authService = getAuthService() + const user = await authService.getCurrentUser(request) + + return new Response( + JSON.stringify({ + authenticated: !!user, + anonymousGenerationQuota: user + ? null + : { + limit: anonymousQuota.limit, + remaining: anonymousQuota.remaining, + resetAt: anonymousQuota.resetAt.toISOString(), + }, + }), + { + headers: { + 'Cache-Control': 'no-store', + 'Content-Type': 'application/json', + }, + }, + ) + } catch (error) { + console.error('Error loading application starter status:', error) + + return new Response( + JSON.stringify({ + error: 'Failed to load application starter status', + }), + { + status: 500, + headers: { + 'Cache-Control': 'no-store', + 'Content-Type': 'application/json', + }, + }, + ) + } + }, + POST: async ({ request }: { request: Request }) => { + try { + const [{ getAuthService }, starterServer] = await Promise.all([ + import('~/auth/index.server'), + import('~/utils/application-starter.server'), + ]) + + const rateLimit = await checkIpRateLimit( + request, + RATE_LIMITS.applicationStarter, + ) + + if (!rateLimit.allowed) { + return rateLimitedResponse(rateLimit) + } + + const requestGuardError = validateJsonRequest(request, { + maxContentLength: MAX_APPLICATION_STARTER_BODY_BYTES, + }) + if (requestGuardError) { + return new Response( + JSON.stringify({ error: requestGuardError.message }), + { + status: requestGuardError.status, + headers: { + 'Content-Type': 'application/json', + ...Object.fromEntries(rateLimit.headers.entries()), + }, + }, + ) + } + + const bodyResult = await readJsonBody(request, { + maxContentLength: MAX_APPLICATION_STARTER_BODY_BYTES, + }) + if (!bodyResult.success) { + return new Response( + JSON.stringify({ error: bodyResult.error.message }), + { + status: bodyResult.error.status, + headers: { + 'Content-Type': 'application/json', + ...Object.fromEntries(rateLimit.headers.entries()), + }, + }, + ) + } + + const rawBody = bodyResult.body + const isAnalyzeRequest = + isRecord(rawBody) && rawBody.mode === 'analyze' + const body = starterServer.applicationStarterRequestSchema.parse(rawBody) + + const authService = getAuthService() + const user = await authService.getCurrentUser(request) + + if (!user && !isAnalyzeRequest) { + const anonymousQuota = await checkIpWindowRateLimit( + request, + RATE_LIMITS.applicationStarterAnonymousDaily, + ) + + if (!anonymousQuota.allowed) { + return new Response( + JSON.stringify({ + code: 'LOGIN_REQUIRED_FOR_MORE_GENERATIONS', + error: 'Anonymous generation limit reached', + limit: RATE_LIMITS.applicationStarterAnonymousDaily.limit, + loginRequired: true, + retryAfter: Math.ceil( + (anonymousQuota.resetAt.getTime() - Date.now()) / 1000, + ), + }), + { + status: 429, + headers: { + 'Content-Type': 'application/json', + ...Object.fromEntries(rateLimit.headers.entries()), + ...Object.fromEntries(anonymousQuota.headers.entries()), + }, + }, + ) + } + } + + const response = isAnalyzeRequest + ? await starterServer.analyzeApplicationStarterServer({ + data: body, + }) + : await starterServer.resolveApplicationStarterServer({ + data: body, + }) + + return new Response(JSON.stringify(response), { + headers: { + 'Cache-Control': 'no-store', + 'Content-Type': 'application/json', + ...Object.fromEntries(rateLimit.headers.entries()), + }, + }) + } catch (error) { + console.error('Error resolving application starter:', error) + return new Response( + JSON.stringify({ + error: 'Failed to resolve application starter', + }), + { + status: 500, + headers: { 'Content-Type': 'application/json' }, + }, + ) + } + }, }, }, }) diff --git a/src/routes/api/application-starter/suggest.ts b/src/routes/api/application-starter/suggest.ts index 67e2b36ba..08b04be22 100644 --- a/src/routes/api/application-starter/suggest.ts +++ b/src/routes/api/application-starter/suggest.ts @@ -1,10 +1,44 @@ import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' +import { + applicationStarterErrorResponse, + applicationStarterInternalErrorResponse, + applicationStarterJsonResponse, + readApplicationStarterJsonRequest, +} from '~/application-starter/api/request-boundary.server' +import { + applicationStarterSuggestBodySchema, + parseApplicationStarterRequest, +} from '~/application-starter/api/request-schema.server' export const Route = createFileRoute('/api/application-starter/suggest')({ server: { handlers: { - POST: ({ request }) => forwardWorkerRequest('STARTER', request), + POST: async ({ request }: { request: Request }) => { + try { + const requestBody = await readApplicationStarterJsonRequest(request) + if ('response' in requestBody) { + return requestBody.response + } + + let body + try { + body = parseApplicationStarterRequest(applicationStarterSuggestBodySchema, requestBody.body) + } catch { + return applicationStarterErrorResponse( + 'Invalid request body', + 400, + requestBody.rateLimit, + ) + } + + const { suggestHandler } = await import('~/application-starter/api/suggest') + const response = await suggestHandler(body) + return applicationStarterJsonResponse(response, requestBody.rateLimit) + } catch (error) { + console.error('Error suggesting features:', error) + return applicationStarterInternalErrorResponse('Failed to generate suggestions') + } + }, }, }, }) diff --git a/src/routes/api/application-starter/validate.ts b/src/routes/api/application-starter/validate.ts index 0c3d95dd4..11187445d 100644 --- a/src/routes/api/application-starter/validate.ts +++ b/src/routes/api/application-starter/validate.ts @@ -1,10 +1,47 @@ import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' +import { + applicationStarterErrorResponse, + applicationStarterInternalErrorResponse, + applicationStarterJsonResponse, + readApplicationStarterJsonRequest, +} from '~/application-starter/api/request-boundary.server' +import { + applicationStarterValidateBodySchema, + parseApplicationStarterRequest, +} from '~/application-starter/api/request-schema.server' export const Route = createFileRoute('/api/application-starter/validate')({ server: { handlers: { - POST: ({ request }) => forwardWorkerRequest('STARTER', request), + POST: async ({ request }: { request: Request }) => { + try { + const requestBody = await readApplicationStarterJsonRequest(request) + if ('response' in requestBody) { + return requestBody.response + } + + let body + try { + body = parseApplicationStarterRequest( + applicationStarterValidateBodySchema, + requestBody.body, + ) + } catch { + return applicationStarterErrorResponse( + 'Invalid request body', + 400, + requestBody.rateLimit, + ) + } + + const { validateHandler } = await import('~/application-starter/api/validate') + const response = await validateHandler(body.definition) + return applicationStarterJsonResponse(response, requestBody.rateLimit) + } catch (error) { + console.error('Error validating project:', error) + return applicationStarterInternalErrorResponse('Failed to validate project') + } + }, }, }, }) diff --git a/src/routes/api/chat/account/composer-drafts/$accountId.$scope.ts b/src/routes/api/chat/account/composer-drafts/$accountId.$scope.ts index 1680950d9..5d00de380 100644 --- a/src/routes/api/chat/account/composer-drafts/$accountId.$scope.ts +++ b/src/routes/api/chat/account/composer-drafts/$accountId.$scope.ts @@ -1,13 +1,8 @@ import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' - -export const Route = createFileRoute( - '/api/chat/account/composer-drafts/$accountId/$scope', -)({ - server: { - handlers: { - GET: ({ request }) => forwardWorkerRequest('CHAT', request), - POST: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, +import { handleComposerDraft } from '~/chat/server/composer-draft-http.server' +export const Route = createFileRoute('/api/chat/account/composer-drafts/$accountId/$scope')({ + server: { handlers: { + GET: ({ request, params }) => handleComposerDraft(request, params.accountId, params.scope), + POST: ({ request, params }) => handleComposerDraft(request, params.accountId, params.scope), + } }, }) diff --git a/src/routes/api/chat/account/devices.ts b/src/routes/api/chat/account/devices.ts index 1a0ad8f4d..aeadef6c2 100644 --- a/src/routes/api/chat/account/devices.ts +++ b/src/routes/api/chat/account/devices.ts @@ -1,11 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' - -export const Route = createFileRoute('/api/chat/account/devices')({ - server: { - handlers: { - GET: ({ request }) => forwardWorkerRequest('CHAT', request), - POST: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, -}) +import {createFileRoute} from '@tanstack/react-router' +import {handleDeviceAccount} from '~/chat/server/device-http.server' +export const Route=createFileRoute('/api/chat/account/devices')({server:{handlers:{GET:({request})=>handleDeviceAccount(request),POST:({request})=>handleDeviceAccount(request)}}}) diff --git a/src/routes/api/chat/account/onboarding.ts b/src/routes/api/chat/account/onboarding.ts index 7b695f48c..d4ff3ac44 100644 --- a/src/routes/api/chat/account/onboarding.ts +++ b/src/routes/api/chat/account/onboarding.ts @@ -1,11 +1,5 @@ import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' - +import { handleOnboarding } from '~/chat/server/onboarding-http.server' export const Route = createFileRoute('/api/chat/account/onboarding')({ - server: { - handlers: { - GET: ({ request }) => forwardWorkerRequest('CHAT', request), - POST: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, + server: { handlers: { GET: ({ request }) => handleOnboarding(request), POST: ({ request }) => handleOnboarding(request) } }, }) diff --git a/src/routes/api/chat/account/preferences.ts b/src/routes/api/chat/account/preferences.ts index a071b17dc..f77631d31 100644 --- a/src/routes/api/chat/account/preferences.ts +++ b/src/routes/api/chat/account/preferences.ts @@ -1,11 +1,5 @@ import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' - +import { handleAccountPreferences } from '~/chat/server/account-preferences-http.server' export const Route = createFileRoute('/api/chat/account/preferences')({ - server: { - handlers: { - GET: ({ request }) => forwardWorkerRequest('CHAT', request), - POST: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, + server: { handlers: { GET: ({ request }) => handleAccountPreferences(request), POST: ({ request }) => handleAccountPreferences(request) } }, }) diff --git a/src/routes/api/chat/activity.ts b/src/routes/api/chat/activity.ts index 8c98a4f78..883c835e3 100644 --- a/src/routes/api/chat/activity.ts +++ b/src/routes/api/chat/activity.ts @@ -1,10 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' - -export const Route = createFileRoute('/api/chat/activity')({ - server: { - handlers: { - GET: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, -}) +import {createFileRoute} from '@tanstack/react-router' +import {handleWorkspaceActivity} from '~/chat/server/workspace-activity-http.server' +export const Route=createFileRoute('/api/chat/activity')({server:{handlers:{GET:({request})=>handleWorkspaceActivity(request)}}}) diff --git a/src/routes/api/chat/app-version.ts b/src/routes/api/chat/app-version.ts index e031b382e..63077f000 100644 --- a/src/routes/api/chat/app-version.ts +++ b/src/routes/api/chat/app-version.ts @@ -1,10 +1,3 @@ import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' - -export const Route = createFileRoute('/api/chat/app-version')({ - server: { - handlers: { - GET: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, -}) +import { appBuildId } from '~/chat/core/app-version' +export const Route = createFileRoute('/api/chat/app-version')({ server: { handlers: { GET: () => Response.json({ build: appBuildId }, { headers: { 'Cache-Control': 'no-store' } }) } } }) diff --git a/src/routes/api/chat/bootstrap.ts b/src/routes/api/chat/bootstrap.ts index ac2f42a73..f5829bb8a 100644 --- a/src/routes/api/chat/bootstrap.ts +++ b/src/routes/api/chat/bootstrap.ts @@ -1,10 +1,3 @@ import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' - -export const Route = createFileRoute('/api/chat/bootstrap')({ - server: { - handlers: { - GET: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, -}) +import { handleBootstrap } from '~/chat/server/bootstrap-http.server' +export const Route = createFileRoute('/api/chat/bootstrap')({server:{handlers:{GET:({request})=>handleBootstrap(request)}}}) diff --git a/src/routes/api/chat/bot-drafts/$id.files.$fileId.content.ts b/src/routes/api/chat/bot-drafts/$id.files.$fileId.content.ts index 4ce540b90..b8c1f2dc9 100644 --- a/src/routes/api/chat/bot-drafts/$id.files.$fileId.content.ts +++ b/src/routes/api/chat/bot-drafts/$id.files.$fileId.content.ts @@ -1,12 +1,5 @@ -import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' - -export const Route = createFileRoute( - '/api/chat/bot-drafts/$id/files/$fileId/content', -)({ - server: { - handlers: { - GET: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, -}) +import {createFileRoute} from '@tanstack/react-router' +import {handleFiles} from '~/chat/server/file-http.server' +export const Route=createFileRoute('/api/chat/bot-drafts/$id/files/$fileId/content')({server:{handlers:{ +GET: ({request,params}) => handleFiles(request, 'bot-drafts', params.id, params.fileId, true) +}}}) diff --git a/src/routes/api/chat/bot-drafts/$id.files.$fileId.ts b/src/routes/api/chat/bot-drafts/$id.files.$fileId.ts index 1782e5708..c7798d1fc 100644 --- a/src/routes/api/chat/bot-drafts/$id.files.$fileId.ts +++ b/src/routes/api/chat/bot-drafts/$id.files.$fileId.ts @@ -1,13 +1,8 @@ -import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' - -export const Route = createFileRoute('/api/chat/bot-drafts/$id/files/$fileId')({ - server: { - handlers: { - GET: ({ request }) => forwardWorkerRequest('CHAT', request), - POST: ({ request }) => forwardWorkerRequest('CHAT', request), - PUT: ({ request }) => forwardWorkerRequest('CHAT', request), - DELETE: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, -}) +import {createFileRoute} from '@tanstack/react-router' +import {handleFiles} from '~/chat/server/file-http.server' +export const Route=createFileRoute('/api/chat/bot-drafts/$id/files/$fileId')({server:{handlers:{ +GET: ({request,params}) => handleFiles(request, 'bot-drafts', params.id, params.fileId), +POST: ({request,params}) => handleFiles(request, 'bot-drafts', params.id, params.fileId), +PUT: ({request,params}) => handleFiles(request, 'bot-drafts', params.id, params.fileId), +DELETE: ({request,params}) => handleFiles(request, 'bot-drafts', params.id, params.fileId) +}}}) diff --git a/src/routes/api/chat/bot-drafts/$id.files.ts b/src/routes/api/chat/bot-drafts/$id.files.ts index 54a838ac3..d1d1daed2 100644 --- a/src/routes/api/chat/bot-drafts/$id.files.ts +++ b/src/routes/api/chat/bot-drafts/$id.files.ts @@ -1,13 +1,8 @@ -import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' - -export const Route = createFileRoute('/api/chat/bot-drafts/$id/files')({ - server: { - handlers: { - GET: ({ request }) => forwardWorkerRequest('CHAT', request), - POST: ({ request }) => forwardWorkerRequest('CHAT', request), - PUT: ({ request }) => forwardWorkerRequest('CHAT', request), - DELETE: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, -}) +import {createFileRoute} from '@tanstack/react-router' +import {handleFiles} from '~/chat/server/file-http.server' +export const Route=createFileRoute('/api/chat/bot-drafts/$id/files')({server:{handlers:{ +GET: ({request,params}) => handleFiles(request, 'bot-drafts', params.id), +POST: ({request,params}) => handleFiles(request, 'bot-drafts', params.id), +PUT: ({request,params}) => handleFiles(request, 'bot-drafts', params.id), +DELETE: ({request,params}) => handleFiles(request, 'bot-drafts', params.id) +}}}) diff --git a/src/routes/api/chat/bot-drafts/$id.ts b/src/routes/api/chat/bot-drafts/$id.ts index 2ae91df3f..027c48ec7 100644 --- a/src/routes/api/chat/bot-drafts/$id.ts +++ b/src/routes/api/chat/bot-drafts/$id.ts @@ -1,11 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' - -export const Route = createFileRoute('/api/chat/bot-drafts/$id')({ - server: { - handlers: { - GET: ({ request }) => forwardWorkerRequest('CHAT', request), - POST: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, -}) +import {createFileRoute} from '@tanstack/react-router' +import {handleBotDraft} from '~/chat/server/bot-draft-http.server' +export const Route=createFileRoute('/api/chat/bot-drafts/$id')({server:{handlers:{GET:({request,params})=>handleBotDraft(request,params.id),POST:({request,params})=>handleBotDraft(request,params.id)}}}) diff --git a/src/routes/api/chat/bots.ts b/src/routes/api/chat/bots.ts index 6f501c15c..a135beb01 100644 --- a/src/routes/api/chat/bots.ts +++ b/src/routes/api/chat/bots.ts @@ -1,10 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' - -export const Route = createFileRoute('/api/chat/bots')({ - server: { - handlers: { - POST: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, -}) +import {createFileRoute} from '@tanstack/react-router' +import {handleBotMutation} from '~/chat/server/bot-mutation-http.server' +export const Route=createFileRoute('/api/chat/bots')({server:{handlers:{POST:({request})=>handleBotMutation(request)}}}) diff --git a/src/routes/api/chat/bots/$id.$operation.ts b/src/routes/api/chat/bots/$id.$operation.ts index 4974442fe..972b022ae 100644 --- a/src/routes/api/chat/bots/$id.$operation.ts +++ b/src/routes/api/chat/bots/$id.$operation.ts @@ -1,12 +1,15 @@ +import {handleConversationCopy} from '~/chat/server/conversation-copy-http.server' import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' +import { handleConversationRead, handleConversationSend } from '~/chat/server/conversation-http.server' + +import { handleBotMutation } from '~/chat/server/bot-mutation-http.server' export const Route = createFileRoute('/api/chat/bots/$id/$operation')({ server: { handlers: { - POST: ({ request }) => forwardWorkerRequest('CHAT', request), - PATCH: ({ request }) => forwardWorkerRequest('CHAT', request), - GET: ({ request }) => forwardWorkerRequest('CHAT', request), + POST: ({ request, params }) => params.operation==='copies' ? handleConversationCopy(request,params.id,'bot') : ['move','delete','restore'].includes(params.operation) ? handleBotMutation(request,params.id,params.operation) : handleConversationSend(request, params.id, params.operation, 'bot'), + PATCH: ({request,params}) => handleBotMutation(request,params.id,params.operation), + GET: ({ request, params }) => params.operation==='copy-source' ? handleConversationCopy(request,params.id,'bot',true) : handleConversationRead(request, params.id, params.operation, 'bot'), }, }, }) diff --git a/src/routes/api/chat/bots/$id.files.$fileId.content.ts b/src/routes/api/chat/bots/$id.files.$fileId.content.ts index 456f4965f..a2c02f7da 100644 --- a/src/routes/api/chat/bots/$id.files.$fileId.content.ts +++ b/src/routes/api/chat/bots/$id.files.$fileId.content.ts @@ -1,12 +1,5 @@ -import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' - -export const Route = createFileRoute( - '/api/chat/bots/$id/files/$fileId/content', -)({ - server: { - handlers: { - GET: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, -}) +import {createFileRoute} from '@tanstack/react-router' +import {handleFiles} from '~/chat/server/file-http.server' +export const Route=createFileRoute('/api/chat/bots/$id/files/$fileId/content')({server:{handlers:{ +GET: ({request,params}) => handleFiles(request, 'bots', params.id, params.fileId, true) +}}}) diff --git a/src/routes/api/chat/bots/$id.files.$fileId.ts b/src/routes/api/chat/bots/$id.files.$fileId.ts index 9d7767f03..1f606bef7 100644 --- a/src/routes/api/chat/bots/$id.files.$fileId.ts +++ b/src/routes/api/chat/bots/$id.files.$fileId.ts @@ -1,13 +1,8 @@ -import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' - -export const Route = createFileRoute('/api/chat/bots/$id/files/$fileId')({ - server: { - handlers: { - GET: ({ request }) => forwardWorkerRequest('CHAT', request), - POST: ({ request }) => forwardWorkerRequest('CHAT', request), - PUT: ({ request }) => forwardWorkerRequest('CHAT', request), - DELETE: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, -}) +import {createFileRoute} from '@tanstack/react-router' +import {handleFiles} from '~/chat/server/file-http.server' +export const Route=createFileRoute('/api/chat/bots/$id/files/$fileId')({server:{handlers:{ +GET: ({request,params}) => handleFiles(request, 'bots', params.id, params.fileId), +POST: ({request,params}) => handleFiles(request, 'bots', params.id, params.fileId), +PUT: ({request,params}) => handleFiles(request, 'bots', params.id, params.fileId), +DELETE: ({request,params}) => handleFiles(request, 'bots', params.id, params.fileId) +}}}) diff --git a/src/routes/api/chat/bots/$id.files.ts b/src/routes/api/chat/bots/$id.files.ts index 058b514f6..fbaca1a20 100644 --- a/src/routes/api/chat/bots/$id.files.ts +++ b/src/routes/api/chat/bots/$id.files.ts @@ -1,13 +1,8 @@ -import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' - -export const Route = createFileRoute('/api/chat/bots/$id/files')({ - server: { - handlers: { - GET: ({ request }) => forwardWorkerRequest('CHAT', request), - POST: ({ request }) => forwardWorkerRequest('CHAT', request), - PUT: ({ request }) => forwardWorkerRequest('CHAT', request), - DELETE: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, -}) +import {createFileRoute} from '@tanstack/react-router' +import {handleFiles} from '~/chat/server/file-http.server' +export const Route=createFileRoute('/api/chat/bots/$id/files')({server:{handlers:{ +GET: ({request,params}) => handleFiles(request, 'bots', params.id), +POST: ({request,params}) => handleFiles(request, 'bots', params.id), +PUT: ({request,params}) => handleFiles(request, 'bots', params.id), +DELETE: ({request,params}) => handleFiles(request, 'bots', params.id) +}}}) diff --git a/src/routes/api/chat/bots/$id.ts b/src/routes/api/chat/bots/$id.ts index 344cc2584..c887f0ca3 100644 --- a/src/routes/api/chat/bots/$id.ts +++ b/src/routes/api/chat/bots/$id.ts @@ -1,10 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' - -export const Route = createFileRoute('/api/chat/bots/$id')({ - server: { - handlers: { - PATCH: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, -}) +import {createFileRoute} from '@tanstack/react-router' +import {handleBotMutation} from '~/chat/server/bot-mutation-http.server' +export const Route=createFileRoute('/api/chat/bots/$id')({server:{handlers:{PATCH:({request,params})=>handleBotMutation(request,params.id)}}}) diff --git a/src/routes/api/chat/bots/bulk.ts b/src/routes/api/chat/bots/bulk.ts index 540c184b5..b14ab0eae 100644 --- a/src/routes/api/chat/bots/bulk.ts +++ b/src/routes/api/chat/bots/bulk.ts @@ -1,10 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' - -export const Route = createFileRoute('/api/chat/bots/bulk')({ - server: { - handlers: { - POST: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, -}) +import {createFileRoute} from '@tanstack/react-router' +import {handleBotMutation} from '~/chat/server/bot-mutation-http.server' +export const Route=createFileRoute('/api/chat/bots/bulk')({server:{handlers:{POST:({request})=>handleBotMutation(request,undefined,undefined,'bulk')}}}) diff --git a/src/routes/api/chat/bots/move.ts b/src/routes/api/chat/bots/move.ts index 0c631fa83..c2b30fe72 100644 --- a/src/routes/api/chat/bots/move.ts +++ b/src/routes/api/chat/bots/move.ts @@ -1,10 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' - -export const Route = createFileRoute('/api/chat/bots/move')({ - server: { - handlers: { - POST: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, -}) +import {createFileRoute} from '@tanstack/react-router' +import {handleBotMutation} from '~/chat/server/bot-mutation-http.server' +export const Route=createFileRoute('/api/chat/bots/move')({server:{handlers:{POST:({request})=>handleBotMutation(request,undefined,undefined,'move')}}}) diff --git a/src/routes/api/chat/connection.ts b/src/routes/api/chat/connection.ts index ab394ffcc..18ff8f6ad 100644 --- a/src/routes/api/chat/connection.ts +++ b/src/routes/api/chat/connection.ts @@ -1,10 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' - -export const Route = createFileRoute('/api/chat/connection')({ - server: { - handlers: { - POST: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, -}) +import {createFileRoute} from '@tanstack/react-router' +import {handleProviderConnection} from '~/chat/server/provider-connection-http.server' +export const Route=createFileRoute('/api/chat/connection')({server:{handlers:{POST:({request})=>handleProviderConnection(request)}}}) diff --git a/src/routes/api/chat/conversations/$id.$operation.ts b/src/routes/api/chat/conversations/$id.$operation.ts index 5da4605c7..4e1201612 100644 --- a/src/routes/api/chat/conversations/$id.$operation.ts +++ b/src/routes/api/chat/conversations/$id.$operation.ts @@ -1,12 +1,19 @@ +import {handleConversationRetry} from '~/chat/server/conversation-retry-http.server' +import {handleConversationCopy} from '~/chat/server/conversation-copy-http.server' +import {handleWorkflowRun} from '~/chat/server/workflow-run-http.server' +import {handleWorkflow} from '~/chat/server/workflow-http.server' +import {handleConversationExecution} from '~/chat/server/conversation-execution-http.server' import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' +import { handleConversationRead, handleConversationSend } from '~/chat/server/conversation-http.server' + +import {handleConversationThreads} from '~/chat/server/conversation-threads-http.server' export const Route = createFileRoute('/api/chat/conversations/$id/$operation')({ server: { handlers: { - POST: ({ request }) => forwardWorkerRequest('CHAT', request), - DELETE: ({ request }) => forwardWorkerRequest('CHAT', request), - GET: ({ request }) => forwardWorkerRequest('CHAT', request), + POST: ({ request, params }) => params.operation==='retries' ? handleConversationRetry(request,params.id,'create') : params.operation==='copies' ? handleConversationCopy(request,params.id,'conversation') : params.operation==='workflow-runs' ? handleWorkflowRun(request,params.id) : params.operation==='workflows' ? handleWorkflow(request,params.id) : params.operation==='execution' ? handleConversationExecution(request,params.id) : ['thread','threads'].includes(params.operation) ? handleConversationThreads(request,params.id,params.operation) : handleConversationSend(request, params.id, params.operation), + DELETE: ({request,params}) => handleConversationThreads(request,params.id,params.operation), + GET: ({ request, params }) => params.operation==='copy-source' ? handleConversationCopy(request,params.id,'conversation',true) : params.operation==='workflow-runs' ? handleWorkflowRun(request,params.id) : params.operation==='workflows' ? handleWorkflow(request,params.id) : params.operation==='execution' ? handleConversationExecution(request,params.id) : ['thread','threads'].includes(params.operation) ? handleConversationThreads(request,params.id,params.operation) : handleConversationRead(request, params.id, params.operation), }, }, }) diff --git a/src/routes/api/chat/conversations/$id.execution.snapshots.$snapshotId.ts b/src/routes/api/chat/conversations/$id.execution.snapshots.$snapshotId.ts index b998c1955..8fdf248e0 100644 --- a/src/routes/api/chat/conversations/$id.execution.snapshots.$snapshotId.ts +++ b/src/routes/api/chat/conversations/$id.execution.snapshots.$snapshotId.ts @@ -1,13 +1,6 @@ -import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' - -export const Route = createFileRoute( - '/api/chat/conversations/$id/execution/snapshots/$snapshotId', -)({ - server: { - handlers: { - GET: ({ request }) => forwardWorkerRequest('CHAT', request), - PUT: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, -}) +import {createFileRoute} from '@tanstack/react-router' +import {handleConversationExecution} from '~/chat/server/conversation-execution-http.server' +export const Route=createFileRoute('/api/chat/conversations/$id/execution/snapshots/$snapshotId')({server:{handlers:{ + GET:({request,params})=>handleConversationExecution(request,params.id,params.snapshotId), + PUT:({request,params})=>handleConversationExecution(request,params.id,params.snapshotId), +}}}) diff --git a/src/routes/api/chat/conversations/$id.files.$fileId.content.ts b/src/routes/api/chat/conversations/$id.files.$fileId.content.ts index 2497c0752..dce31ee24 100644 --- a/src/routes/api/chat/conversations/$id.files.$fileId.content.ts +++ b/src/routes/api/chat/conversations/$id.files.$fileId.content.ts @@ -1,12 +1,5 @@ -import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' - -export const Route = createFileRoute( - '/api/chat/conversations/$id/files/$fileId/content', -)({ - server: { - handlers: { - GET: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, -}) +import {createFileRoute} from '@tanstack/react-router' +import {handleFiles} from '~/chat/server/file-http.server' +export const Route=createFileRoute('/api/chat/conversations/$id/files/$fileId/content')({server:{handlers:{ +GET: ({request,params}) => handleFiles(request, 'conversations', params.id, params.fileId, true) +}}}) diff --git a/src/routes/api/chat/conversations/$id.files.$fileId.ts b/src/routes/api/chat/conversations/$id.files.$fileId.ts index fd827ab8b..c1806bbb0 100644 --- a/src/routes/api/chat/conversations/$id.files.$fileId.ts +++ b/src/routes/api/chat/conversations/$id.files.$fileId.ts @@ -1,15 +1,8 @@ -import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' - -export const Route = createFileRoute( - '/api/chat/conversations/$id/files/$fileId', -)({ - server: { - handlers: { - GET: ({ request }) => forwardWorkerRequest('CHAT', request), - POST: ({ request }) => forwardWorkerRequest('CHAT', request), - PUT: ({ request }) => forwardWorkerRequest('CHAT', request), - DELETE: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, -}) +import {createFileRoute} from '@tanstack/react-router' +import {handleFiles} from '~/chat/server/file-http.server' +export const Route=createFileRoute('/api/chat/conversations/$id/files/$fileId')({server:{handlers:{ +GET: ({request,params}) => handleFiles(request, 'conversations', params.id, params.fileId), +POST: ({request,params}) => handleFiles(request, 'conversations', params.id, params.fileId), +PUT: ({request,params}) => handleFiles(request, 'conversations', params.id, params.fileId), +DELETE: ({request,params}) => handleFiles(request, 'conversations', params.id, params.fileId) +}}}) diff --git a/src/routes/api/chat/conversations/$id.files.ts b/src/routes/api/chat/conversations/$id.files.ts index 67e809897..0be2b15f5 100644 --- a/src/routes/api/chat/conversations/$id.files.ts +++ b/src/routes/api/chat/conversations/$id.files.ts @@ -1,13 +1,8 @@ -import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' - -export const Route = createFileRoute('/api/chat/conversations/$id/files')({ - server: { - handlers: { - GET: ({ request }) => forwardWorkerRequest('CHAT', request), - POST: ({ request }) => forwardWorkerRequest('CHAT', request), - PUT: ({ request }) => forwardWorkerRequest('CHAT', request), - DELETE: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, -}) +import {createFileRoute} from '@tanstack/react-router' +import {handleFiles} from '~/chat/server/file-http.server' +export const Route=createFileRoute('/api/chat/conversations/$id/files')({server:{handlers:{ +GET: ({request,params}) => handleFiles(request, 'conversations', params.id), +POST: ({request,params}) => handleFiles(request, 'conversations', params.id), +PUT: ({request,params}) => handleFiles(request, 'conversations', params.id), +DELETE: ({request,params}) => handleFiles(request, 'conversations', params.id) +}}}) diff --git a/src/routes/api/chat/conversations/$id.workflow-runs.$runId.cancel.ts b/src/routes/api/chat/conversations/$id.workflow-runs.$runId.cancel.ts index 0833c782c..eee00e580 100644 --- a/src/routes/api/chat/conversations/$id.workflow-runs.$runId.cancel.ts +++ b/src/routes/api/chat/conversations/$id.workflow-runs.$runId.cancel.ts @@ -1,12 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' - -export const Route = createFileRoute( - '/api/chat/conversations/$id/workflow-runs/$runId/cancel', -)({ - server: { - handlers: { - POST: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, -}) +import {createFileRoute} from '@tanstack/react-router' +import {handleWorkflowRun} from '~/chat/server/workflow-run-http.server' +export const Route=createFileRoute('/api/chat/conversations/$id/workflow-runs/$runId/cancel')({server:{handlers:{POST:({request,params})=>handleWorkflowRun(request,params.id,params.runId,true)}}}) diff --git a/src/routes/api/chat/conversations/$id.workflow-runs.$runId.ts b/src/routes/api/chat/conversations/$id.workflow-runs.$runId.ts index 3517f9233..bded70607 100644 --- a/src/routes/api/chat/conversations/$id.workflow-runs.$runId.ts +++ b/src/routes/api/chat/conversations/$id.workflow-runs.$runId.ts @@ -1,13 +1,6 @@ -import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' - -export const Route = createFileRoute( - '/api/chat/conversations/$id/workflow-runs/$runId', -)({ - server: { - handlers: { - GET: ({ request }) => forwardWorkerRequest('CHAT', request), - POST: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, -}) +import {createFileRoute} from '@tanstack/react-router' +import {handleWorkflowRun} from '~/chat/server/workflow-run-http.server' +export const Route=createFileRoute('/api/chat/conversations/$id/workflow-runs/$runId')({server:{handlers:{ +GET:({request,params})=>handleWorkflowRun(request,params.id,params.runId), +POST:({request,params})=>handleWorkflowRun(request,params.id,params.runId), +}}}) diff --git a/src/routes/api/chat/conversations/$id.workflows.$workflowId.ts b/src/routes/api/chat/conversations/$id.workflows.$workflowId.ts index ce035cf89..3b379a66e 100644 --- a/src/routes/api/chat/conversations/$id.workflows.$workflowId.ts +++ b/src/routes/api/chat/conversations/$id.workflows.$workflowId.ts @@ -1,12 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' - -export const Route = createFileRoute( - '/api/chat/conversations/$id/workflows/$workflowId', -)({ - server: { - handlers: { - GET: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, -}) +import {createFileRoute} from '@tanstack/react-router' +import {handleWorkflow} from '~/chat/server/workflow-http.server' +export const Route=createFileRoute('/api/chat/conversations/$id/workflows/$workflowId')({server:{handlers:{GET:({request,params})=>handleWorkflow(request,params.id,params.workflowId)}}}) diff --git a/src/routes/api/chat/conversations/$id/files/import.ts b/src/routes/api/chat/conversations/$id/files/import.ts index c68b5ef9c..c63b839c6 100644 --- a/src/routes/api/chat/conversations/$id/files/import.ts +++ b/src/routes/api/chat/conversations/$id/files/import.ts @@ -1,12 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' - -export const Route = createFileRoute( - '/api/chat/conversations/$id/files/import', -)({ - server: { - handlers: { - POST: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, -}) +import {createFileRoute} from '@tanstack/react-router' +import {handleFileImport} from '~/chat/server/file-http.server' +export const Route=createFileRoute('/api/chat/conversations/$id/files/import')({server:{handlers:{POST:({request,params})=>handleFileImport(request,params.id)}}}) diff --git a/src/routes/api/chat/conversations/$id/memories.ts b/src/routes/api/chat/conversations/$id/memories.ts index 121ead735..d420e1a05 100644 --- a/src/routes/api/chat/conversations/$id/memories.ts +++ b/src/routes/api/chat/conversations/$id/memories.ts @@ -1,11 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' - -export const Route = createFileRoute('/api/chat/conversations/$id/memories')({ - server: { - handlers: { - GET: ({ request }) => forwardWorkerRequest('CHAT', request), - POST: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, -}) +import {createFileRoute} from '@tanstack/react-router' +import {handleMemory} from '~/chat/server/memory-http.server' +export const Route=createFileRoute('/api/chat/conversations/$id/memories')({server:{handlers:{GET:({request,params})=>handleMemory(request,params.id),POST:({request,params})=>handleMemory(request,params.id)}}}) diff --git a/src/routes/api/chat/conversations/$id/memories/$memoryId.ts b/src/routes/api/chat/conversations/$id/memories/$memoryId.ts index e26d80bcc..30830c3d7 100644 --- a/src/routes/api/chat/conversations/$id/memories/$memoryId.ts +++ b/src/routes/api/chat/conversations/$id/memories/$memoryId.ts @@ -1,13 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' - -export const Route = createFileRoute( - '/api/chat/conversations/$id/memories/$memoryId', -)({ - server: { - handlers: { - GET: ({ request }) => forwardWorkerRequest('CHAT', request), - POST: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, -}) +import {createFileRoute} from '@tanstack/react-router' +import {handleMemory} from '~/chat/server/memory-http.server' +export const Route=createFileRoute('/api/chat/conversations/$id/memories/$memoryId')({server:{handlers:{GET:({request,params})=>handleMemory(request,params.id,params.memoryId),POST:({request,params})=>handleMemory(request,params.id,params.memoryId)}}}) diff --git a/src/routes/api/chat/conversations/$id/references.ts b/src/routes/api/chat/conversations/$id/references.ts index 2857e6af9..f4f4069b9 100644 --- a/src/routes/api/chat/conversations/$id/references.ts +++ b/src/routes/api/chat/conversations/$id/references.ts @@ -1,10 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' - -export const Route = createFileRoute('/api/chat/conversations/$id/references')({ - server: { - handlers: { - GET: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, -}) +import {createFileRoute} from '@tanstack/react-router' +import {handleReferences} from '~/chat/server/reference-http.server' +export const Route=createFileRoute('/api/chat/conversations/$id/references')({server:{handlers:{GET:({request,params})=>handleReferences(request,params.id)}}}) diff --git a/src/routes/api/chat/copies/$id.ts b/src/routes/api/chat/copies/$id.ts index 145314da2..77c3a7509 100644 --- a/src/routes/api/chat/copies/$id.ts +++ b/src/routes/api/chat/copies/$id.ts @@ -1,10 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' - -export const Route = createFileRoute('/api/chat/copies/$id')({ - server: { - handlers: { - GET: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, -}) +import {createFileRoute} from '@tanstack/react-router' +import {handleConversationCopy} from '~/chat/server/conversation-copy-http.server' +export const Route=createFileRoute('/api/chat/copies/$id')({server:{handlers:{GET:({request,params})=>handleConversationCopy(request,params.id,'operation')}}}) diff --git a/src/routes/api/chat/device-transport.ts b/src/routes/api/chat/device-transport.ts index 9e093977c..dd46a2e97 100644 --- a/src/routes/api/chat/device-transport.ts +++ b/src/routes/api/chat/device-transport.ts @@ -1,10 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' - -export const Route = createFileRoute('/api/chat/device-transport')({ - server: { - handlers: { - POST: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, -}) +import {createFileRoute} from '@tanstack/react-router' +import {handleDeviceTransport} from '~/chat/server/device-http.server' +export const Route=createFileRoute('/api/chat/device-transport')({server:{handlers:{POST:({request})=>handleDeviceTransport(request)}}}) diff --git a/src/routes/api/chat/draft.ts b/src/routes/api/chat/draft.ts index 4091797cd..2df67f3a8 100644 --- a/src/routes/api/chat/draft.ts +++ b/src/routes/api/chat/draft.ts @@ -1,11 +1,34 @@ +import { hasChatAccess } from '~/chat/access.server' +import { z } from 'zod' import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' +import { getAuthService } from '~/auth/index.server' +import { jsonError, readJsonBody, validateSameOriginRequest } from '~/utils/api-boundary.server' +import { composerDraftApi } from '~/chat/server/composer-drafts' +async function handle(request: Request) { + if (request.method === 'POST') { + const rejection = validateSameOriginRequest(request) + if (rejection) return jsonError(rejection.message, rejection.status) + } + const user = await getAuthService().getCurrentUser(request) + if (!user) return jsonError('Sign in to continue.', 401) + if (!await hasChatAccess(user)) + return jsonError('Chat access is unavailable.', 403) + const scope = new URL(request.url).searchParams.get('scope') ?? '' + const body = request.method === 'POST' + ? await readJsonBody(request, { maxContentLength: 600_000 }) + : undefined + if (body && !body.success) return jsonError(body.error.message, body.error.status) + try { + return await composerDraftApi(request, user.userId, scope, body?.success ? body.body : undefined) + } catch (error) { + if (error instanceof z.ZodError) return jsonError('Invalid draft request.', 400) + throw error + } +} export const Route = createFileRoute('/api/chat/draft')({ - server: { - handlers: { - GET: ({ request }) => forwardWorkerRequest('CHAT', request), - POST: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, + server: { handlers: { + GET: ({ request }) => handle(request), + POST: ({ request }) => handle(request), + } }, }) diff --git a/src/routes/api/chat/files.ts b/src/routes/api/chat/files.ts index 5fb0cfc6e..3dedc2165 100644 --- a/src/routes/api/chat/files.ts +++ b/src/routes/api/chat/files.ts @@ -1,11 +1,91 @@ +import { hasChatAccess } from '~/chat/access.server' +import { z } from 'zod' +import type { FileScope, DraftFileScope } from '~/chat/core/files' import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' +import { getAuthService } from '~/auth/index.server' +import { + jsonError, + validateSameOriginRequest, +} from '~/utils/api-boundary.server' +import { fileApi } from '~/chat/server/file-api' +import { getFileEnvironment } from '~/chat/server/file-environment.server' +import { SavedFileError } from '~/chat/server/saved-file-contract' +const requestSchema = z + .object({ + workspaceId: z.string().min(1).max(1000), + botId: z.string().min(1).max(1000).optional(), + conversationId: z.string().min(1).max(1000).optional(), + draftId: z.string().uuid().optional(), + id: z.string().uuid().optional(), + content: z.enum(['0', '1']).default('0'), + }) + .superRefine((value, ctx) => { + if ( + value.draftId + ? Boolean(value.botId || value.conversationId) + : !value.botId + ) + ctx.addIssue({ + code: 'custom', + message: 'Choose a draft or a conversation.', + }) + if (value.content === '1' && !value.id) + ctx.addIssue({ code: 'custom', message: 'Choose a file.' }) + }) +export async function handleFileRequest(request: Request) { + if (request.method === 'PUT') { + const rejection = validateSameOriginRequest(request) + if (rejection) return jsonError(rejection.message, rejection.status) + } + const user = await getAuthService().getCurrentUser(request) + if (!user) return jsonError('Sign in to continue.', 401) + if ( + !await hasChatAccess(user) + ) + return jsonError('Chat access is unavailable.', 403) + const parsed = requestSchema.safeParse( + Object.fromEntries(new URL(request.url).searchParams), + ) + if (!parsed.success) return jsonError('Invalid file request.', 400) + const value = parsed.data + let scope: FileScope | DraftFileScope + if (value.draftId) + scope = { + workspaceId: value.workspaceId, + userId: user.userId, + draftId: value.draftId, + } + else { + if (!value.botId) return jsonError('Invalid file request.', 400) + scope = { + workspaceId: value.workspaceId, + userId: user.userId, + botId: value.botId, + conversationId: value.conversationId, + } + } + try { + return await fileApi( + request, + await getFileEnvironment(), + scope, + value.id, + value.content === '1', + ) + } catch (error) { + if (error instanceof SavedFileError) + return jsonError(error.message, error.status) + if (error instanceof z.ZodError) + return jsonError('Invalid file request.', 400) + throw error + } +} export const Route = createFileRoute('/api/chat/files')({ server: { handlers: { - GET: ({ request }) => forwardWorkerRequest('CHAT', request), - PUT: ({ request }) => forwardWorkerRequest('CHAT', request), + GET: ({ request }) => handleFileRequest(request), + PUT: ({ request }) => handleFileRequest(request), }, }, }) diff --git a/src/routes/api/chat/kody/account.ts b/src/routes/api/chat/kody/account.ts index 8364be391..69476253b 100644 --- a/src/routes/api/chat/kody/account.ts +++ b/src/routes/api/chat/kody/account.ts @@ -1,10 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' - -export const Route = createFileRoute('/api/chat/kody/account')({ - server: { - handlers: { - GET: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, -}) +import {createFileRoute} from '@tanstack/react-router' +import {handleKodyAccount} from '~/chat/server/kody-account-http.server' +export const Route=createFileRoute('/api/chat/kody/account')({server:{handlers:{GET:({request})=>handleKodyAccount(request,'account')}}}) diff --git a/src/routes/api/chat/kody/callback.ts b/src/routes/api/chat/kody/callback.ts index f9bf6c0fa..b0f886f9f 100644 --- a/src/routes/api/chat/kody/callback.ts +++ b/src/routes/api/chat/kody/callback.ts @@ -1,10 +1,3 @@ import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' - -export const Route = createFileRoute('/api/chat/kody/callback')({ - server: { - handlers: { - GET: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, -}) +import { handleKodyCallback } from '~/chat/server/kody-callback-http.server' +export const Route = createFileRoute('/api/chat/kody/callback')({ server: { handlers: { GET: ({ request }) => handleKodyCallback(request) } } }) diff --git a/src/routes/api/chat/kody/community.ts b/src/routes/api/chat/kody/community.ts index 1bca81205..ab7bf52d1 100644 --- a/src/routes/api/chat/kody/community.ts +++ b/src/routes/api/chat/kody/community.ts @@ -1,10 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' - -export const Route = createFileRoute('/api/chat/kody/community')({ - server: { - handlers: { - GET: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, -}) +import {createFileRoute} from '@tanstack/react-router' +import {handleKodyAccount} from '~/chat/server/kody-account-http.server' +export const Route=createFileRoute('/api/chat/kody/community')({server:{handlers:{GET:({request})=>handleKodyAccount(request,'community')}}}) diff --git a/src/routes/api/chat/kody/community/$listingId.ts b/src/routes/api/chat/kody/community/$listingId.ts index 093d812f5..a6b52b8f0 100644 --- a/src/routes/api/chat/kody/community/$listingId.ts +++ b/src/routes/api/chat/kody/community/$listingId.ts @@ -1,10 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' - -export const Route = createFileRoute('/api/chat/kody/community/$listingId')({ - server: { - handlers: { - GET: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, -}) +import {createFileRoute} from '@tanstack/react-router' +import {handleKodyAccount} from '~/chat/server/kody-account-http.server' +export const Route=createFileRoute('/api/chat/kody/community/$listingId')({server:{handlers:{GET:({request,params})=>handleKodyAccount(request,'community',params.listingId)}}}) diff --git a/src/routes/api/chat/kody/connect.ts b/src/routes/api/chat/kody/connect.ts index 4eb5d717b..37c90b9e5 100644 --- a/src/routes/api/chat/kody/connect.ts +++ b/src/routes/api/chat/kody/connect.ts @@ -1,10 +1,3 @@ import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' - -export const Route = createFileRoute('/api/chat/kody/connect')({ - server: { - handlers: { - POST: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, -}) +import { handleKodyConnect } from '~/chat/server/kody-connect-http.server' +export const Route = createFileRoute('/api/chat/kody/connect')({ server: { handlers: { POST: ({ request }) => handleKodyConnect(request) } } }) diff --git a/src/routes/api/chat/kody/jobs/$jobId/enabled.ts b/src/routes/api/chat/kody/jobs/$jobId/enabled.ts index ce8e20dcb..3b5eaea88 100644 --- a/src/routes/api/chat/kody/jobs/$jobId/enabled.ts +++ b/src/routes/api/chat/kody/jobs/$jobId/enabled.ts @@ -1,10 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' - -export const Route = createFileRoute('/api/chat/kody/jobs/$jobId/enabled')({ - server: { - handlers: { - POST: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, -}) +import {createFileRoute} from '@tanstack/react-router' +import {handleKodyControl} from '~/chat/server/kody-control-http.server' +export const Route=createFileRoute('/api/chat/kody/jobs/$jobId/enabled')({server:{handlers:{POST:({request,params})=>handleKodyControl(request,'job-enabled',params.jobId)}}}) diff --git a/src/routes/api/chat/kody/mail/inboxes.ts b/src/routes/api/chat/kody/mail/inboxes.ts index 5af1382bd..b98a1f62f 100644 --- a/src/routes/api/chat/kody/mail/inboxes.ts +++ b/src/routes/api/chat/kody/mail/inboxes.ts @@ -1,10 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' - -export const Route = createFileRoute('/api/chat/kody/mail/inboxes')({ - server: { - handlers: { - GET: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, -}) +import {createFileRoute} from '@tanstack/react-router' +import {handleKodyAccount} from '~/chat/server/kody-account-http.server' +export const Route=createFileRoute('/api/chat/kody/mail/inboxes')({server:{handlers:{GET:({request})=>handleKodyAccount(request,'mail-inboxes')}}}) diff --git a/src/routes/api/chat/kody/mail/messages.ts b/src/routes/api/chat/kody/mail/messages.ts index d771aa4a8..3818894e0 100644 --- a/src/routes/api/chat/kody/mail/messages.ts +++ b/src/routes/api/chat/kody/mail/messages.ts @@ -1,10 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' - -export const Route = createFileRoute('/api/chat/kody/mail/messages')({ - server: { - handlers: { - GET: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, -}) +import {createFileRoute} from '@tanstack/react-router' +import {handleKodyAccount} from '~/chat/server/kody-account-http.server' +export const Route=createFileRoute('/api/chat/kody/mail/messages')({server:{handlers:{GET:({request})=>handleKodyAccount(request,'mail-messages')}}}) diff --git a/src/routes/api/chat/kody/mail/messages/$messageId.ts b/src/routes/api/chat/kody/mail/messages/$messageId.ts index 42d82e67a..5813ba23b 100644 --- a/src/routes/api/chat/kody/mail/messages/$messageId.ts +++ b/src/routes/api/chat/kody/mail/messages/$messageId.ts @@ -1,12 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' - -export const Route = createFileRoute('/api/chat/kody/mail/messages/$messageId')( - { - server: { - handlers: { - GET: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, - }, -) +import {createFileRoute} from '@tanstack/react-router' +import {handleKodyAccount} from '~/chat/server/kody-account-http.server' +export const Route=createFileRoute('/api/chat/kody/mail/messages/$messageId')({server:{handlers:{GET:({request,params})=>handleKodyAccount(request,'mail-messages',params.messageId)}}}) diff --git a/src/routes/api/chat/kody/memories.ts b/src/routes/api/chat/kody/memories.ts index cdc0693da..a1b2758f3 100644 --- a/src/routes/api/chat/kody/memories.ts +++ b/src/routes/api/chat/kody/memories.ts @@ -1,10 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' - -export const Route = createFileRoute('/api/chat/kody/memories')({ - server: { - handlers: { - GET: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, -}) +import {createFileRoute} from '@tanstack/react-router' +import {handleKodyAccount} from '~/chat/server/kody-account-http.server' +export const Route=createFileRoute('/api/chat/kody/memories')({server:{handlers:{GET:({request})=>handleKodyAccount(request,'memories')}}}) diff --git a/src/routes/api/chat/kody/memories/$memoryId.ts b/src/routes/api/chat/kody/memories/$memoryId.ts index 31660c8a0..e6cd4718e 100644 --- a/src/routes/api/chat/kody/memories/$memoryId.ts +++ b/src/routes/api/chat/kody/memories/$memoryId.ts @@ -1,10 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' - -export const Route = createFileRoute('/api/chat/kody/memories/$memoryId')({ - server: { - handlers: { - GET: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, -}) +import {createFileRoute} from '@tanstack/react-router' +import {handleKodyAccount} from '~/chat/server/kody-account-http.server' +export const Route=createFileRoute('/api/chat/kody/memories/$memoryId')({server:{handlers:{GET:({request,params})=>handleKodyAccount(request,'memories',params.memoryId)}}}) diff --git a/src/routes/api/chat/kody/memories/$memoryId/apply.ts b/src/routes/api/chat/kody/memories/$memoryId/apply.ts index d65c164e5..87ac3e4cf 100644 --- a/src/routes/api/chat/kody/memories/$memoryId/apply.ts +++ b/src/routes/api/chat/kody/memories/$memoryId/apply.ts @@ -1,12 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' - -export const Route = createFileRoute('/api/chat/kody/memories/$memoryId/apply')( - { - server: { - handlers: { - POST: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, - }, -) +import {createFileRoute} from '@tanstack/react-router' +import {handleKodyMemoryMutation} from '~/chat/server/kody-memory-http.server' +export const Route=createFileRoute('/api/chat/kody/memories/$memoryId/apply')({server:{handlers:{POST:({request,params})=>handleKodyMemoryMutation(request,'apply',params.memoryId)}}}) diff --git a/src/routes/api/chat/kody/memories/$memoryId/review.ts b/src/routes/api/chat/kody/memories/$memoryId/review.ts index c7bec624d..f7991eaff 100644 --- a/src/routes/api/chat/kody/memories/$memoryId/review.ts +++ b/src/routes/api/chat/kody/memories/$memoryId/review.ts @@ -1,12 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' - -export const Route = createFileRoute( - '/api/chat/kody/memories/$memoryId/review', -)({ - server: { - handlers: { - POST: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, -}) +import {createFileRoute} from '@tanstack/react-router' +import {handleKodyMemoryMutation} from '~/chat/server/kody-memory-http.server' +export const Route=createFileRoute('/api/chat/kody/memories/$memoryId/review')({server:{handlers:{POST:({request,params})=>handleKodyMemoryMutation(request,'review',params.memoryId)}}}) diff --git a/src/routes/api/chat/kody/memories/create/apply.ts b/src/routes/api/chat/kody/memories/create/apply.ts index 3400964f6..2015a280c 100644 --- a/src/routes/api/chat/kody/memories/create/apply.ts +++ b/src/routes/api/chat/kody/memories/create/apply.ts @@ -1,10 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' - -export const Route = createFileRoute('/api/chat/kody/memories/create/apply')({ - server: { - handlers: { - POST: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, -}) +import {createFileRoute} from '@tanstack/react-router' +import {handleKodyMemoryMutation} from '~/chat/server/kody-memory-http.server' +export const Route=createFileRoute('/api/chat/kody/memories/create/apply')({server:{handlers:{POST:({request})=>handleKodyMemoryMutation(request,'apply')}}}) diff --git a/src/routes/api/chat/kody/memories/create/review.ts b/src/routes/api/chat/kody/memories/create/review.ts index 1a1afffe9..c6e54ea7b 100644 --- a/src/routes/api/chat/kody/memories/create/review.ts +++ b/src/routes/api/chat/kody/memories/create/review.ts @@ -1,10 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' - -export const Route = createFileRoute('/api/chat/kody/memories/create/review')({ - server: { - handlers: { - POST: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, -}) +import {createFileRoute} from '@tanstack/react-router' +import {handleKodyMemoryMutation} from '~/chat/server/kody-memory-http.server' +export const Route=createFileRoute('/api/chat/kody/memories/create/review')({server:{handlers:{POST:({request})=>handleKodyMemoryMutation(request,'review')}}}) diff --git a/src/routes/api/chat/kody/packages/$packageId/document.ts b/src/routes/api/chat/kody/packages/$packageId/document.ts index 36b275781..071cf7fdb 100644 --- a/src/routes/api/chat/kody/packages/$packageId/document.ts +++ b/src/routes/api/chat/kody/packages/$packageId/document.ts @@ -1,12 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' - -export const Route = createFileRoute( - '/api/chat/kody/packages/$packageId/document', -)({ - server: { - handlers: { - GET: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, -}) +import {createFileRoute} from '@tanstack/react-router' +import {handleKodyAccount} from '~/chat/server/kody-account-http.server' +export const Route=createFileRoute('/api/chat/kody/packages/$packageId/document')({server:{handlers:{GET:({request,params})=>handleKodyAccount(request,'package-document',params.packageId)}}}) diff --git a/src/routes/api/chat/kody/resources/$kind.ts b/src/routes/api/chat/kody/resources/$kind.ts index a4ae4974c..8109f8ce6 100644 --- a/src/routes/api/chat/kody/resources/$kind.ts +++ b/src/routes/api/chat/kody/resources/$kind.ts @@ -1,10 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' - -export const Route = createFileRoute('/api/chat/kody/resources/$kind')({ - server: { - handlers: { - GET: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, -}) +import {createFileRoute} from '@tanstack/react-router' +import {handleKodyAccount} from '~/chat/server/kody-account-http.server' +export const Route=createFileRoute('/api/chat/kody/resources/$kind')({server:{handlers:{GET:({request,params})=>handleKodyAccount(request,'resources',params.kind)}}}) diff --git a/src/routes/api/chat/kody/runs.ts b/src/routes/api/chat/kody/runs.ts index 54030cf4e..fc9d7babe 100644 --- a/src/routes/api/chat/kody/runs.ts +++ b/src/routes/api/chat/kody/runs.ts @@ -1,10 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' - -export const Route = createFileRoute('/api/chat/kody/runs')({ - server: { - handlers: { - GET: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, -}) +import {createFileRoute} from '@tanstack/react-router' +import {handleKodyAccount} from '~/chat/server/kody-account-http.server' +export const Route=createFileRoute('/api/chat/kody/runs')({server:{handlers:{GET:({request})=>handleKodyAccount(request,'runs')}}}) diff --git a/src/routes/api/chat/kody/runs/$runId.ts b/src/routes/api/chat/kody/runs/$runId.ts index ed8e8e446..cdeab0470 100644 --- a/src/routes/api/chat/kody/runs/$runId.ts +++ b/src/routes/api/chat/kody/runs/$runId.ts @@ -1,10 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' - -export const Route = createFileRoute('/api/chat/kody/runs/$runId')({ - server: { - handlers: { - GET: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, -}) +import {createFileRoute} from '@tanstack/react-router' +import {handleKodyAccount} from '~/chat/server/kody-account-http.server' +export const Route=createFileRoute('/api/chat/kody/runs/$runId')({server:{handlers:{GET:({request,params})=>handleKodyAccount(request,'runs',params.runId)}}}) diff --git a/src/routes/api/chat/kody/runs/$runId/triage.ts b/src/routes/api/chat/kody/runs/$runId/triage.ts index bf5ace45d..f6f23edba 100644 --- a/src/routes/api/chat/kody/runs/$runId/triage.ts +++ b/src/routes/api/chat/kody/runs/$runId/triage.ts @@ -1,10 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' - -export const Route = createFileRoute('/api/chat/kody/runs/$runId/triage')({ - server: { - handlers: { - POST: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, -}) +import {createFileRoute} from '@tanstack/react-router' +import {handleKodyControl} from '~/chat/server/kody-control-http.server' +export const Route=createFileRoute('/api/chat/kody/runs/$runId/triage')({server:{handlers:{POST:({request,params})=>handleKodyControl(request,'run-triage',params.runId)}}}) diff --git a/src/routes/api/chat/kody/servers.ts b/src/routes/api/chat/kody/servers.ts index b64756602..5d3ecf3d7 100644 --- a/src/routes/api/chat/kody/servers.ts +++ b/src/routes/api/chat/kody/servers.ts @@ -1,10 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' - -export const Route = createFileRoute('/api/chat/kody/servers')({ - server: { - handlers: { - POST: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, -}) +import {createFileRoute} from '@tanstack/react-router' +import {handleKodyControl} from '~/chat/server/kody-control-http.server' +export const Route=createFileRoute('/api/chat/kody/servers')({server:{handlers:{POST:({request})=>handleKodyControl(request,'server-add')}}}) diff --git a/src/routes/api/chat/kody/servers/$serverId/check.ts b/src/routes/api/chat/kody/servers/$serverId/check.ts index e4aec94d8..e69cdbd82 100644 --- a/src/routes/api/chat/kody/servers/$serverId/check.ts +++ b/src/routes/api/chat/kody/servers/$serverId/check.ts @@ -1,10 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' - -export const Route = createFileRoute('/api/chat/kody/servers/$serverId/check')({ - server: { - handlers: { - POST: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, -}) +import {createFileRoute} from '@tanstack/react-router' +import {handleKodyControl} from '~/chat/server/kody-control-http.server' +export const Route=createFileRoute('/api/chat/kody/servers/$serverId/check')({server:{handlers:{POST:({request,params})=>handleKodyControl(request,'server-check',params.serverId)}}}) diff --git a/src/routes/api/chat/kody/servers/$serverId/enabled.ts b/src/routes/api/chat/kody/servers/$serverId/enabled.ts index 9bdf27cba..e42f2cc5e 100644 --- a/src/routes/api/chat/kody/servers/$serverId/enabled.ts +++ b/src/routes/api/chat/kody/servers/$serverId/enabled.ts @@ -1,12 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' - -export const Route = createFileRoute( - '/api/chat/kody/servers/$serverId/enabled', -)({ - server: { - handlers: { - POST: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, -}) +import {createFileRoute} from '@tanstack/react-router' +import {handleKodyControl} from '~/chat/server/kody-control-http.server' +export const Route=createFileRoute('/api/chat/kody/servers/$serverId/enabled')({server:{handlers:{POST:({request,params})=>handleKodyControl(request,'server-enabled',params.serverId)}}}) diff --git a/src/routes/api/chat/kody/servers/$serverId/reconnect.ts b/src/routes/api/chat/kody/servers/$serverId/reconnect.ts index 11bb4c398..59c11c125 100644 --- a/src/routes/api/chat/kody/servers/$serverId/reconnect.ts +++ b/src/routes/api/chat/kody/servers/$serverId/reconnect.ts @@ -1,12 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' - -export const Route = createFileRoute( - '/api/chat/kody/servers/$serverId/reconnect', -)({ - server: { - handlers: { - POST: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, -}) +import {createFileRoute} from '@tanstack/react-router' +import {handleKodyControl} from '~/chat/server/kody-control-http.server' +export const Route=createFileRoute('/api/chat/kody/servers/$serverId/reconnect')({server:{handlers:{POST:({request,params})=>handleKodyControl(request,'server-reconnect',params.serverId)}}}) diff --git a/src/routes/api/chat/kody/sync.ts b/src/routes/api/chat/kody/sync.ts index 446ebdf5e..141c4a497 100644 --- a/src/routes/api/chat/kody/sync.ts +++ b/src/routes/api/chat/kody/sync.ts @@ -1,10 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' - -export const Route = createFileRoute('/api/chat/kody/sync')({ - server: { - handlers: { - POST: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, -}) +import {createFileRoute} from '@tanstack/react-router' +import {handleKodyAccount} from '~/chat/server/kody-account-http.server' +export const Route=createFileRoute('/api/chat/kody/sync')({server:{handlers:{POST:({request})=>handleKodyAccount(request,'sync')}}}) diff --git a/src/routes/api/chat/kody/unlink.ts b/src/routes/api/chat/kody/unlink.ts index 6a2222e9f..1c078e31d 100644 --- a/src/routes/api/chat/kody/unlink.ts +++ b/src/routes/api/chat/kody/unlink.ts @@ -1,10 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' - -export const Route = createFileRoute('/api/chat/kody/unlink')({ - server: { - handlers: { - POST: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, -}) +import {createFileRoute} from '@tanstack/react-router' +import {handleKodyUnlink} from '~/chat/server/kody-unlink-http.server' +export const Route=createFileRoute('/api/chat/kody/unlink')({server:{handlers:{POST:({request})=>handleKodyUnlink(request)}}}) diff --git a/src/routes/api/chat/kody/usage.ts b/src/routes/api/chat/kody/usage.ts index 0672d7d27..4739fea73 100644 --- a/src/routes/api/chat/kody/usage.ts +++ b/src/routes/api/chat/kody/usage.ts @@ -1,10 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' - -export const Route = createFileRoute('/api/chat/kody/usage')({ - server: { - handlers: { - GET: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, -}) +import {createFileRoute} from '@tanstack/react-router' +import {handleKodyAccount} from '~/chat/server/kody-account-http.server' +export const Route=createFileRoute('/api/chat/kody/usage')({server:{handlers:{GET:({request})=>handleKodyAccount(request,'usage')}}}) diff --git a/src/routes/api/chat/mcp/$.ts b/src/routes/api/chat/mcp/$.ts index c27121fc9..8af1c5923 100644 --- a/src/routes/api/chat/mcp/$.ts +++ b/src/routes/api/chat/mcp/$.ts @@ -1,11 +1,32 @@ +import { hasChatAccess } from '~/chat/access.server' +import { z } from 'zod' import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' - -export const Route = createFileRoute('/api/chat/mcp/$')({ - server: { - handlers: { - GET: ({ request }) => forwardWorkerRequest('CHAT', request), - POST: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, -}) +import { getAuthService } from '~/auth/index.server' +import { jsonError, validateSameOriginRequest } from '~/utils/api-boundary.server' +import { readWorkspacePolicy, WorkspacePolicyError } from '~/chat/workspace-policy.server' +import { getMcpEnvironment, McpEnvironmentError } from '~/chat/server/mcp-environment.server' +import { mcpAccountApi } from '~/chat/server/mcp-account-api' +import { McpAccountError } from '~/chat/server/mcp-account-contract' +import { McpAuthorizationError } from '~/chat/server/mcp-auth-network' +export async function handleMcp(request: Request) { + if(request.method==='POST') { + const error=validateSameOriginRequest(request) + if(error) return jsonError(error.message,error.status) + } + const user=await getAuthService().getCurrentUser(request) + if(!user) return jsonError('Sign in to continue.',401) + if(!await hasChatAccess(user)) return jsonError('Chat access is unavailable.',403) + const url=new URL(request.url) + const workspace=z.string().min(1).max(1000).safeParse(url.searchParams.get('workspaceId')) + if(!workspace.success) return jsonError('Choose a workspace.',400) + try { + await readWorkspacePolicy(workspace.data,user.userId) + const path=url.pathname.slice('/api/chat/'.length) + return await mcpAccountApi(request,await getMcpEnvironment(),{workspaceId:workspace.data,userId:user.userId},path)??jsonError('Not found.',404) + } catch(error) { + if(error instanceof WorkspacePolicyError||error instanceof McpEnvironmentError||error instanceof McpAccountError||error instanceof McpAuthorizationError) return jsonError(error.message,error.status) + if(error instanceof z.ZodError) return jsonError('The connection request is invalid.',400) + throw error + } +} +export const Route=createFileRoute('/api/chat/mcp/$')({server:{handlers:{GET:({request})=>handleMcp(request),POST:({request})=>handleMcp(request)}}}) diff --git a/src/routes/api/chat/mcp/contract.ts b/src/routes/api/chat/mcp/contract.ts index 2af2763ea..b15a5b236 100644 --- a/src/routes/api/chat/mcp/contract.ts +++ b/src/routes/api/chat/mcp/contract.ts @@ -1,10 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' - -export const Route = createFileRoute('/api/chat/mcp/contract')({ - server: { - handlers: { - GET: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, -}) +import {createFileRoute} from '@tanstack/react-router' +import {handleReferenceCatalog} from '~/chat/server/reference-catalog-http.server' +export const Route=createFileRoute('/api/chat/mcp/contract')({server:{handlers:{GET:({request})=>handleReferenceCatalog(request,'mcp-contract')}}}) diff --git a/src/routes/api/chat/model-options.ts b/src/routes/api/chat/model-options.ts index eb46ee1e1..e1a370c4c 100644 --- a/src/routes/api/chat/model-options.ts +++ b/src/routes/api/chat/model-options.ts @@ -1,10 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' - -export const Route = createFileRoute('/api/chat/model-options')({ - server: { - handlers: { - GET: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, -}) +import {createFileRoute} from '@tanstack/react-router' +import {handleModelOptions} from '~/chat/server/model-options-http.server' +export const Route=createFileRoute('/api/chat/model-options')({server:{handlers:{GET:({request})=>handleModelOptions(request)}}}) diff --git a/src/routes/api/chat/models.ts b/src/routes/api/chat/models.ts index 15f227632..4af5f653c 100644 --- a/src/routes/api/chat/models.ts +++ b/src/routes/api/chat/models.ts @@ -1,10 +1,43 @@ +import { hasChatAccess } from '~/chat/access.server' +import { z } from 'zod' import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' - +import { getAuthService } from '~/auth/index.server' +import { jsonError, jsonResponse } from '~/utils/api-boundary.server' +import { + readWorkspacePolicy, + WorkspacePolicyError, +} from '~/chat/workspace-policy.server' +import { getModelEnvironment } from '~/chat/server/model-environment.server' +import { getRunModelCatalog, RunModelError } from '~/chat/server/run-models' +const workspaceIdSchema = z.string().min(1).max(1000) +export async function handleModelCatalog(request: Request) { + const user = await getAuthService().getCurrentUser(request) + if (!user) return jsonError('Sign in to continue.', 401) + if ( + !await hasChatAccess(user) + ) + return jsonError('Chat access is unavailable.', 403) + const parsed = workspaceIdSchema.safeParse( + new URL(request.url).searchParams.get('workspaceId'), + ) + if (!parsed.success) return jsonError('Choose a workspace.', 400) + try { + const policy = await readWorkspacePolicy(parsed.data, user.userId) + const env = await getModelEnvironment() + const catalog = await getRunModelCatalog(env, { + userId: user.userId, + policy, + fixture: false, + }) + return jsonResponse(catalog, { + headers: { 'Cache-Control': 'private, no-store' }, + }) + } catch (error) { + if (error instanceof WorkspacePolicyError || error instanceof RunModelError) + return jsonError(error.message, error.status) + throw error + } +} export const Route = createFileRoute('/api/chat/models')({ - server: { - handlers: { - GET: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, + server: { handlers: { GET: ({ request }) => handleModelCatalog(request) } }, }) diff --git a/src/routes/api/chat/openrouter/callback.ts b/src/routes/api/chat/openrouter/callback.ts index 592b81965..93936afcb 100644 --- a/src/routes/api/chat/openrouter/callback.ts +++ b/src/routes/api/chat/openrouter/callback.ts @@ -1,10 +1,36 @@ import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' export const Route = createFileRoute('/api/chat/openrouter/callback')({ - server: { - handlers: { - GET: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, + server: { handlers: { GET: () => openRouterCallbackResponse() } }, }) + +export function openRouterCallbackResponse() { + const nonce = crypto.randomUUID() + // Do not load the app, analytics, or third-party assets while the + // authorization code is in the URL. + return new Response(` +Connect OpenRouter | TanChat +

Return to Builder to finish connecting OpenRouter.

+`, { + headers: { + 'Content-Type': 'text/html; charset=utf-8', + 'Cache-Control': 'no-store', + 'Referrer-Policy': 'no-referrer', + 'Content-Security-Policy': `default-src 'none'; script-src 'nonce-${nonce}'; base-uri 'none'; frame-ancestors 'none'; form-action 'none'`, + 'X-Content-Type-Options': 'nosniff', + 'Cross-Origin-Opener-Policy': 'same-origin', + }, + }) +} diff --git a/src/routes/api/chat/plugins.ts b/src/routes/api/chat/plugins.ts index 9b30c22c2..7a3d81254 100644 --- a/src/routes/api/chat/plugins.ts +++ b/src/routes/api/chat/plugins.ts @@ -1,11 +1,28 @@ +import { hasChatAccess } from '~/chat/access.server' +import { z } from 'zod' import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' - -export const Route = createFileRoute('/api/chat/plugins')({ - server: { - handlers: { - GET: ({ request }) => forwardWorkerRequest('CHAT', request), - POST: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, -}) +import { getAuthService } from '~/auth/index.server' +import { jsonError,validateSameOriginRequest } from '~/utils/api-boundary.server' +import { readWorkspacePolicy,WorkspacePolicyError } from '~/chat/workspace-policy.server' +import { getKodyEnvironment,KodyEnvironmentError } from '~/chat/server/kody-environment.server' +import { pluginApi } from '~/chat/server/plugin-api' +export async function handlePlugins(request:Request, id?:string) { + if(request.method==='POST') { + const error=validateSameOriginRequest(request) + if(error) return jsonError(error.message,error.status) + } + const user=await getAuthService().getCurrentUser(request) + if(!user) return jsonError('Sign in to continue.',401) + if(!await hasChatAccess(user)) return jsonError('Chat access is unavailable.',403) + const url=new URL(request.url) + const parsed=z.string().min(1).max(1000).safeParse(url.searchParams.get('workspaceId')) + if(url.searchParams.getAll('workspaceId').length!==1||!parsed.success) return jsonError('Choose a workspace.',400) + try { + await readWorkspacePolicy(parsed.data,user.userId) + return await pluginApi(request,await getKodyEnvironment(),{workspaceId:parsed.data,userId:user.userId},id??url.searchParams.get('id')??undefined) + } catch(error) { + if(error instanceof WorkspacePolicyError||error instanceof KodyEnvironmentError) return jsonError(error.message,error.status) + throw error + } +} +export const Route=createFileRoute('/api/chat/plugins')({server:{handlers:{GET:({request})=>handlePlugins(request),POST:({request})=>handlePlugins(request)}}}) diff --git a/src/routes/api/chat/plugins/$id.ts b/src/routes/api/chat/plugins/$id.ts index 5223a7704..8846d3468 100644 --- a/src/routes/api/chat/plugins/$id.ts +++ b/src/routes/api/chat/plugins/$id.ts @@ -1,11 +1,11 @@ import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' +import { handlePlugins } from '../plugins' export const Route = createFileRoute('/api/chat/plugins/$id')({ server: { handlers: { - GET: ({ request }) => forwardWorkerRequest('CHAT', request), - POST: ({ request }) => forwardWorkerRequest('CHAT', request), + GET: ({ request, params }) => handlePlugins(request, params.id), + POST: ({ request, params }) => handlePlugins(request, params.id), }, }, }) diff --git a/src/routes/api/chat/policy.ts b/src/routes/api/chat/policy.ts index 4007290da..bac151812 100644 --- a/src/routes/api/chat/policy.ts +++ b/src/routes/api/chat/policy.ts @@ -1,10 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' - -export const Route = createFileRoute('/api/chat/policy')({ - server: { - handlers: { - POST: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, -}) +import {createFileRoute} from '@tanstack/react-router' +import {handleWorkspacePolicy} from '~/chat/server/workspace-policy-http.server' +export const Route=createFileRoute('/api/chat/policy')({server:{handlers:{POST:({request})=>handleWorkspacePolicy(request)}}}) diff --git a/src/routes/api/chat/project-snapshots.$hash.quarantine.ts b/src/routes/api/chat/project-snapshots.$hash.quarantine.ts index dd1509d61..f7ce51c99 100644 --- a/src/routes/api/chat/project-snapshots.$hash.quarantine.ts +++ b/src/routes/api/chat/project-snapshots.$hash.quarantine.ts @@ -1,12 +1,172 @@ import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' +import { + jsonError, + jsonResponse, + validateSameOriginRequest, +} from '~/utils/api-boundary.server' +import { + purgeHostingCacheTags, + type PurgeResult, +} from '~/utils/hosting-cache.server' +import { + getBuilderProjectSnapshotCacheTag, + isBuilderProjectSnapshotHash, + isBuilderProjectSnapshotQuarantined, + BuilderProjectSnapshotStorageUnavailableError, + quarantineBuilderProjectSnapshot, +} from '~/utils/builder-project-snapshot-storage.server' +import { + BuilderProjectStorageUnavailableError, + quarantineStoredBuilderProjectsBySnapshotHash, +} from '~/utils/builder-project-storage.server' +import { quarantineBuilderProjectsBySnapshotHash } from '~/utils/builder-project-events.server' + +type BuilderProjectQuarantineOperations = { + quarantineSnapshot: (hash: string, userId: string) => Promise + isSnapshotQuarantined: (hash: string) => Promise + purgeCacheTags: (tags: Array) => Promise + quarantineProjects: (input: { + snapshotHash: string + actorId: string + }) => Promise> + quarantineStableProjects: ( + snapshotHash: string, + actorId: string, + ) => Promise +} + +export class BuilderProjectQuarantineCleanupError extends Error { + constructor(readonly failures: Array) { + super('Builder project quarantine cleanup did not finish') + this.name = 'BuilderProjectQuarantineCleanupError' + } +} + +export async function quarantineBuilderProjectSnapshotForAdmin( + { + hash, + actorId, + }: { + hash: string + actorId: string + }, + operations: BuilderProjectQuarantineOperations = { + quarantineSnapshot: quarantineBuilderProjectSnapshot, + isSnapshotQuarantined: isBuilderProjectSnapshotQuarantined, + purgeCacheTags: purgeHostingCacheTags, + quarantineProjects: quarantineBuilderProjectsBySnapshotHash, + quarantineStableProjects: quarantineStoredBuilderProjectsBySnapshotHash, + }, +) { + const failures: Array = [] + let tombstoned = false + try { + await operations.quarantineSnapshot(hash, actorId) + tombstoned = true + } catch (error) { + failures.push(error) + } + + const purge = await operations.purgeCacheTags([ + getBuilderProjectSnapshotCacheTag(hash), + ]) + if (!purge.purged) failures.push(new Error('Cache purge failed')) + if (!tombstoned) { + try { + tombstoned = await operations.isSnapshotQuarantined(hash) + } catch (statusError) { + failures.push(statusError) + } + } + if (!tombstoned) { + throw new BuilderProjectQuarantineCleanupError(failures) + } + + let projectsQuarantined: Array = [] + try { + projectsQuarantined = await operations.quarantineProjects({ + snapshotHash: hash, + actorId, + }) + } catch (error) { + failures.push(error) + } + + let stableRecordsQuarantined = 0 + try { + stableRecordsQuarantined = + await operations.quarantineStableProjects(hash, actorId) + } catch (error) { + failures.push(error) + } + + if (failures.length > 0) { + throw new BuilderProjectQuarantineCleanupError(failures) + } + return { projectsQuarantined, purge, stableRecordsQuarantined } +} export const Route = createFileRoute( '/api/chat/project-snapshots/$hash/quarantine', )({ server: { handlers: { - POST: ({ request }) => forwardWorkerRequest('CHAT', request), + POST: async ({ + params, + request, + }: { + params: { hash: string } + request: Request + }) => { + const requestError = validateSameOriginRequest(request) + if (requestError) { + return jsonError(requestError.message, requestError.status) + } + if (!isBuilderProjectSnapshotHash(params.hash)) { + return jsonError('Builder project not found', 404) + } + + const { getAuthService } = await import('~/auth/index.server') + const user = await getAuthService().getCurrentUser(request) + if (!user) { + return jsonError('Not authenticated', 401) + } + if (!user.capabilities.includes('admin')) { + return jsonError('Not authorized', 403) + } + + try { + const { projectsQuarantined, purge, stableRecordsQuarantined } = + await quarantineBuilderProjectSnapshotForAdmin({ + hash: params.hash, + actorId: user.userId, + }) + return jsonResponse({ + purge, + quarantined: true, + projectsQuarantined: projectsQuarantined.length, + stableRecordsQuarantined, + }) + } catch (error) { + if (error instanceof BuilderProjectQuarantineCleanupError) { + for (const failure of error.failures) { + console.error( + 'Builder project quarantine cleanup failed:', + failure, + ) + } + return jsonError('Builder quarantine cleanup is unavailable', 503) + } + if ( + error instanceof BuilderProjectSnapshotStorageUnavailableError || + error instanceof BuilderProjectStorageUnavailableError + ) { + return jsonError('Builder storage is unavailable', 503) + } + console.error('Failed to quarantine builder project:', error) + return jsonError('Failed to quarantine builder project', 500) + } + }, }, }, }) diff --git a/src/routes/api/chat/project-snapshots.$hash.ts b/src/routes/api/chat/project-snapshots.$hash.ts index 7290b5eca..ddbf4e793 100644 --- a/src/routes/api/chat/project-snapshots.$hash.ts +++ b/src/routes/api/chat/project-snapshots.$hash.ts @@ -1,10 +1,45 @@ import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' +import { jsonError } from '~/utils/api-boundary.server' +import { + getBuilderProjectSnapshotCacheTag, + getBuilderProjectSnapshotObject, + isBuilderProjectSnapshotHash, + BuilderProjectSnapshotStorageUnavailableError, +} from '~/utils/builder-project-snapshot-storage.server' export const Route = createFileRoute('/api/chat/project-snapshots/$hash')({ server: { handlers: { - GET: ({ request }) => forwardWorkerRequest('CHAT', request), + GET: async ({ params }: { params: { hash: string } }) => { + if (!isBuilderProjectSnapshotHash(params.hash)) { + return jsonError('Project snapshot not found', 404) + } + + try { + const object = await getBuilderProjectSnapshotObject(params.hash) + if (!object) return jsonError('Project snapshot not found', 404) + + const body = new Blob([await object.arrayBuffer()]) + .stream() + .pipeThrough(new DecompressionStream('gzip')) + + return new Response(body, { + headers: { + 'Cache-Control': 'public, max-age=300, must-revalidate', + 'Cache-Tag': getBuilderProjectSnapshotCacheTag(params.hash), + 'Cloudflare-CDN-Cache-Control': + 'public, max-age=31536000, immutable', + 'Content-Type': 'application/json; charset=utf-8', + ETag: `"${params.hash}"`, + }, + }) + } catch (error) { + if (error instanceof BuilderProjectSnapshotStorageUnavailableError) { + return jsonError('Project snapshot storage is unavailable', 503) + } + throw error + } + }, }, }, }) diff --git a/src/routes/api/chat/project-snapshots.ts b/src/routes/api/chat/project-snapshots.ts index 831f4a5f2..43d44a337 100644 --- a/src/routes/api/chat/project-snapshots.ts +++ b/src/routes/api/chat/project-snapshots.ts @@ -1,10 +1,118 @@ import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' +import { + jsonError, + jsonResponse, + readJsonBody, + validateJsonRequest, +} from '~/utils/api-boundary.server' +import { + BuilderProjectSnapshotQuarantinedError, + BuilderProjectSnapshotStorageUnavailableError, + parseStoredBuilderProjectSnapshot, +} from '~/utils/builder-project-snapshot-storage.server' +import { + BuilderProjectSnapshotLimitError, + BuilderProjectSnapshotRegistryConflictError, + storeBuilderProjectSnapshotForOwner, +} from '~/utils/builder-project-snapshot-registry.server' +import { + checkIpRateLimit, + RATE_LIMITS, + rateLimitedResponse, +} from '~/utils/rateLimit.server' + +const maxRequestBytes = 2 * 1024 * 1024 export const Route = createFileRoute('/api/chat/project-snapshots')({ server: { handlers: { - POST: ({ request }) => forwardWorkerRequest('CHAT', request), + POST: async ({ request }: { request: Request }) => { + const requestError = validateJsonRequest(request, { + maxContentLength: maxRequestBytes, + }) + if (requestError) { + return jsonError(requestError.message, requestError.status) + } + + const rateLimit = await checkIpRateLimit( + request, + RATE_LIMITS.builderProjectWrite, + ) + if (!rateLimit.allowed) return rateLimitedResponse(rateLimit) + + const { getAuthService } = await import('~/auth/index.server') + const user = await getAuthService().getCurrentUser(request) + if (!user) { + return jsonError('Not authenticated', 401, rateLimit.headers) + } + + const body = await readJsonBody(request, { + maxContentLength: maxRequestBytes, + }) + if (!body.success) { + return jsonError( + body.error.message, + body.error.status, + rateLimit.headers, + ) + } + + let project + try { + project = parseStoredBuilderProjectSnapshot(body.body) + } catch (error) { + return jsonError( + error instanceof Error ? error.message : 'Invalid project snapshot', + 400, + rateLimit.headers, + ) + } + + try { + const result = await storeBuilderProjectSnapshotForOwner( + user.userId, + project, + ) + return jsonResponse( + { + hash: result.hash, + url: `/builder/p/${result.hash}`, + sourceUrl: `/api/chat/project-snapshots/${result.hash}`, + }, + { + status: result.created ? 201 : 200, + headers: rateLimit.headers, + }, + ) + } catch (error) { + if (error instanceof BuilderProjectSnapshotQuarantinedError) { + return jsonError( + 'Project snapshot is unavailable', + 410, + rateLimit.headers, + ) + } + if ( + error instanceof BuilderProjectSnapshotLimitError || + error instanceof BuilderProjectSnapshotRegistryConflictError + ) { + return jsonError(error.message, 409, rateLimit.headers) + } + if (error instanceof BuilderProjectSnapshotStorageUnavailableError) { + return jsonError( + 'Project snapshot storage is unavailable', + 503, + rateLimit.headers, + ) + } + console.error('Failed to store Builder project snapshot:', error) + return jsonError( + 'Failed to store project snapshot', + 500, + rateLimit.headers, + ) + } + }, }, }, }) diff --git a/src/routes/api/chat/projects.$id.sync.ts b/src/routes/api/chat/projects.$id.sync.ts index 8386345ab..f348a9d8b 100644 --- a/src/routes/api/chat/projects.$id.sync.ts +++ b/src/routes/api/chat/projects.$id.sync.ts @@ -1,11 +1,558 @@ import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' +import { + jsonError, + jsonResponse, + readJsonBody, + validateJsonRequest, + validateSameOriginRequest, +} from '~/utils/api-boundary.server' +import { + BuilderProjectConflictError, + BuilderProjectDeletedError, + BuilderProjectLeaseError, + BuilderProjectNotFoundError, + BuilderProjectOwnershipError, + BuilderProjectRevisionConflictError, + cancelPendingBuilderProjectRun, + claimBuilderProjectRun, + createBuilderProjectThread, + enqueueBuilderProjectRun, + finishBuilderProjectRun, + getBuilderProjectMutationRequestHash, + getBuilderProjectConversationSnapshotPage, + getBuilderProjectState, + heartbeatBuilderProjectRun, + importBuilderProjectTranscript, + interruptExpiredBuilderProjectRuns, + listBuilderProjectEvents, + updateBuilderProjectState, +} from '~/utils/builder-project-events.server' +import { isBuilderProjectId } from '~/utils/builder-project' +import { getOrImportBuilderProjectState } from '~/utils/builder-project-state.server' +import { + createBuilderProjectEventStreamResponse, + isBuilderProjectSyncStreamRequest, + parseBuilderProjectSyncCursor, +} from '~/utils/builder-project-sync-http.server' +import { + encodeBuilderProjectSyncSnapshotContinuation, + parseBuilderProjectSyncSnapshotContinuation, + parseBuilderProjectSyncSnapshotPage, + parseBuilderProjectSyncRequest, + type BuilderProjectSyncCommand, + type BuilderProjectSyncCommandOutcome, +} from '~/utils/builder-project-sync' +import { + BuilderProjectSnapshotQuarantinedError, + BuilderProjectSnapshotStorageUnavailableError, +} from '~/utils/builder-project-snapshot-storage.server' +import { + BuilderProjectSnapshotLimitError, + BuilderProjectSnapshotRegistryConflictError, + storeBuilderProjectSnapshotForOwner, +} from '~/utils/builder-project-snapshot-registry.server' +import { BuilderProjectStorageUnavailableError } from '~/utils/builder-project-storage.server' +import { + checkIpRateLimit, + checkUserRateLimit, + RATE_LIMITS, + rateLimitedResponse, +} from '~/utils/rateLimit.server' + +const maxRequestBytes = 2 * 1024 * 1024 export const Route = createFileRoute('/api/chat/projects/$id/sync')({ server: { handlers: { - GET: ({ request }) => forwardWorkerRequest('CHAT', request), - POST: ({ request }) => forwardWorkerRequest('CHAT', request), + GET: async ({ + params, + request, + }: { + params: { id: string } + request: Request + }) => { + const requestError = validateSameOriginRequest(request) + if (requestError) { + return jsonError(requestError.message, requestError.status) + } + if (!isBuilderProjectId(params.id)) { + return jsonError('Project not found', 404) + } + + const { getAuthService } = await import('~/auth/index.server') + const user = await getAuthService().getCurrentUser(request) + if (!user) return jsonError('Not authenticated', 401) + + const streamRequest = isBuilderProjectSyncStreamRequest(request) + const continuationValues = streamRequest + ? [] + : new URL(request.url).searchParams.getAll('continuation') + let continuation + try { + if (continuationValues.length > 1) throw new Error() + const value = continuationValues[0] + continuation = value + ? parseBuilderProjectSyncSnapshotContinuation(value) + : undefined + if (continuation && continuation.projectId !== params.id) { + throw new Error() + } + } catch { + return jsonError('Invalid Builder project sync continuation', 400) + } + const rateLimitConfig = continuation + ? RATE_LIMITS.builderProjectSyncSnapshotPage + : RATE_LIMITS.builderProjectSyncStream + const ipRateLimitConfig = continuation + ? RATE_LIMITS.builderProjectSyncSnapshotPageIp + : RATE_LIMITS.builderProjectSyncStreamIp + const rateLimit = await checkUserRateLimit( + `${user.userId}:${params.id}`, + rateLimitConfig, + ) + if (!rateLimit.allowed) return rateLimitedResponse(rateLimit) + const ipBackstop = await checkIpRateLimit(request, ipRateLimitConfig) + if (!ipBackstop.allowed) return rateLimitedResponse(ipBackstop) + + try { + if (streamRequest) { + let cursor + try { + cursor = parseBuilderProjectSyncCursor(request) + } catch { + return jsonError( + 'Invalid Builder project sync cursor', + 400, + rateLimit.headers, + ) + } + let project + try { + project = await getBuilderProjectState({ + projectId: params.id, + ownerId: user.userId, + includeDeleted: true, + }) + } catch (error) { + if (!(error instanceof BuilderProjectNotFoundError)) throw error + await getOrImportBuilderProjectState(params.id) + project = await getBuilderProjectState({ + projectId: params.id, + ownerId: user.userId, + includeDeleted: true, + }) + } + if (cursor > project.lastEventSequence) { + return jsonError( + 'Builder project sync cursor is ahead of the project', + 400, + rateLimit.headers, + ) + } + + return createBuilderProjectEventStreamResponse({ + cursor, + signal: request.signal, + headers: rateLimit.headers, + listEvents: (afterSequence) => + listBuilderProjectEvents({ + projectId: params.id, + ownerId: user.userId, + afterSequence, + limit: 25, + }), + interruptExpiredRuns: async () => { + await interruptExpiredBuilderProjectRuns({ + projectId: params.id, + ownerId: user.userId, + includeDeleted: true, + }) + }, + }) + } + + if (!continuation) await getOrImportBuilderProjectState(params.id) + const snapshot = await getBuilderProjectConversationSnapshotPage({ + projectId: params.id, + ownerId: user.userId, + ...(continuation ? { continuation } : {}), + }) + const page = parseBuilderProjectSyncSnapshotPage({ + project: snapshot.project, + cursor: snapshot.cursor, + headCursor: snapshot.headCursor, + threads: snapshot.threads, + messages: snapshot.messages, + runs: snapshot.runs, + continuation: snapshot.continuation + ? encodeBuilderProjectSyncSnapshotContinuation( + snapshot.continuation, + ) + : null, + }) + return jsonResponse(page, { headers: rateLimit.headers }) + } catch (error) { + return builderProjectSyncErrorResponse(error, rateLimit.headers) + } + }, + POST: async ({ + params, + request, + }: { + params: { id: string } + request: Request + }) => { + const requestError = validateJsonRequest(request, { + maxContentLength: maxRequestBytes, + }) + if (requestError) { + return jsonError(requestError.message, requestError.status) + } + if (!isBuilderProjectId(params.id)) { + return jsonError('Project not found', 404) + } + + const { getAuthService } = await import('~/auth/index.server') + const user = await getAuthService().getCurrentUser(request) + if (!user) return jsonError('Not authenticated', 401) + + const rateLimit = await checkUserRateLimit( + `${user.userId}:${params.id}`, + RATE_LIMITS.builderProjectSyncCommand, + ) + if (!rateLimit.allowed) return rateLimitedResponse(rateLimit) + const ipBackstop = await checkIpRateLimit( + request, + RATE_LIMITS.builderProjectSyncCommandIp, + ) + if (!ipBackstop.allowed) return rateLimitedResponse(ipBackstop) + + const body = await readJsonBody(request, { + maxContentLength: maxRequestBytes, + }) + if (!body.success) { + return jsonError( + body.error.message, + body.error.status, + rateLimit.headers, + ) + } + + let input + try { + input = parseBuilderProjectSyncRequest(body.body) + } catch { + return jsonError( + 'Invalid Builder project sync request', + 400, + rateLimit.headers, + ) + } + + try { + await getOrImportBuilderProjectState(params.id) + await getBuilderProjectState({ + projectId: params.id, + ownerId: user.userId, + }) + const results: Array = [] + for (const command of input.commands) { + try { + results.push( + await applyBuilderProjectSyncCommand({ + projectId: params.id, + ownerId: user.userId, + command, + }), + ) + } catch (error) { + if (error instanceof BuilderProjectLeaseError) { + results.push({ + clientMutationId: command.clientMutationId, + rejected: true, + code: 'run-lease-invalid', + message: error.message, + }) + continue + } + if ( + command.type === 'project.revise' && + error instanceof BuilderProjectConflictError + ) { + results.push({ + clientMutationId: command.clientMutationId, + rejected: true, + code: 'project-revision-conflict', + message: error.message, + }) + continue + } + if ( + command.type === 'run.finish' && + command.revision !== undefined && + error instanceof BuilderProjectRevisionConflictError + ) { + results.push({ + clientMutationId: command.clientMutationId, + rejected: true, + code: 'project-revision-conflict', + message: error.message, + ...(error.sequence === undefined + ? {} + : { sequence: error.sequence }), + }) + continue + } + throw error + } + } + return jsonResponse( + { + cursor: Math.max( + 0, + ...results.map((result) => result.sequence ?? 0), + ), + results, + }, + { headers: rateLimit.headers }, + ) + } catch (error) { + return builderProjectSyncErrorResponse(error, rateLimit.headers) + } + }, }, }, }) + +async function applyBuilderProjectSyncCommand({ + projectId, + ownerId, + command, +}: { + projectId: string + ownerId: string + command: BuilderProjectSyncCommand +}) { + const requestHash = await getBuilderProjectMutationRequestHash(command) + switch (command.type) { + case 'project.revise': { + const snapshot = await storeBuilderProjectSnapshotForOwner( + ownerId, + command.project, + ) + const project = await updateBuilderProjectState({ + projectId, + ownerId, + clientMutationId: command.clientMutationId, + requestHash, + revisionId: command.revisionId, + snapshotHash: snapshot.hash, + title: command.project.title, + description: command.project.description, + expectedRevisionNumber: command.expectedRevisionNumber, + }) + return { + clientMutationId: command.clientMutationId, + sequence: project.lastEventSequence, + events: [], + } + } + case 'thread.create': + return createBuilderProjectThread({ + projectId, + ownerId, + id: command.thread.id, + clientMutationId: command.clientMutationId, + requestHash, + title: command.thread.title, + ...(command.thread.createdAt + ? { createdAt: new Date(command.thread.createdAt) } + : {}), + }) + case 'run.enqueue': + return enqueueBuilderProjectRun({ + projectId, + ownerId, + runId: command.run.id, + threadId: command.run.threadId, + clientMutationId: command.clientMutationId, + requestHash, + queueKind: command.run.queueKind, + provider: command.run.provider, + model: command.run.model, + userMessage: { + id: command.userMessage.id, + clientMutationId: command.userMessage.clientMutationId, + content: command.userMessage.content, + parts: command.userMessage.parts, + }, + }) + case 'run.claim': + return claimBuilderProjectRun({ + projectId, + ownerId, + runId: command.runId, + clientMutationId: command.clientMutationId, + requestHash, + leaseOwnerId: command.leaseOwnerId, + }) + case 'run.cancel': + return cancelPendingBuilderProjectRun({ + projectId, + ownerId, + runId: command.runId, + clientMutationId: command.clientMutationId, + requestHash, + browserSessionId: command.browserSessionId, + }) + case 'run.heartbeat': + return heartbeatBuilderProjectRun({ + projectId, + ownerId, + runId: command.runId, + clientMutationId: command.clientMutationId, + leaseOwnerId: command.leaseOwnerId, + fencingToken: command.leaseFencingToken, + }) + case 'run.finish': + const finishResult = await finishBuilderProjectRun({ + projectId, + ownerId, + runId: command.runId, + clientMutationId: command.clientMutationId, + requestHash, + status: command.status, + leaseOwnerId: command.leaseOwnerId, + fencingToken: command.leaseFencingToken, + ...(command.revision ? { revision: command.revision } : {}), + ...(command.error ? { error: command.error } : {}), + ...(command.activity ? { activity: command.activity } : {}), + ...(command.revision && command.assistantMessage + ? { + revisionConflictFallback: { + clientMutationId: + command.assistantMessage.clientMutationId, + error: { + message: + 'The project changed before the assistant edit could be saved.', + }, + }, + } + : {}), + ...(command.assistantMessage + ? { + assistantMessage: { + id: command.assistantMessage.id, + clientMutationId: + command.assistantMessage.clientMutationId, + content: command.assistantMessage.content, + parts: command.assistantMessage.parts, + ...(command.assistantMessage.createdAt + ? { + createdAt: new Date( + command.assistantMessage.createdAt, + ), + } + : {}), + }, + } + : {}), + }) + if (finishResult.revisionConflict) { + throw new BuilderProjectRevisionConflictError( + undefined, + finishResult.sequence, + ) + } + return { + clientMutationId: finishResult.clientMutationId, + sequence: finishResult.sequence, + events: finishResult.events, + ...(finishResult.leaseFencingToken === undefined + ? {} + : { leaseFencingToken: finishResult.leaseFencingToken }), + } + case 'transcript.import': + return importBuilderProjectTranscript({ + projectId, + ownerId, + clientMutationId: command.clientMutationId, + requestHash, + threads: command.threads.map((thread) => ({ + id: thread.id, + title: thread.title, + createdAt: new Date(thread.createdAt), + updatedAt: new Date(thread.updatedAt), + ...(thread.archivedAt + ? { archivedAt: new Date(thread.archivedAt) } + : {}), + })), + messages: command.messages.map((message) => ({ + id: message.id, + threadId: message.threadId, + ...(message.runId ? { runId: message.runId } : {}), + role: message.role, + content: message.content, + parts: message.parts, + position: message.position, + createdAt: new Date(message.createdAt), + updatedAt: new Date(message.updatedAt), + })), + runs: command.runs.map((run) => ({ + id: run.id, + threadId: run.threadId, + status: run.status, + provider: run.provider, + model: run.model, + ...(run.error ? { error: run.error } : {}), + ...(run.activity ? { activity: run.activity } : {}), + ...(run.startedAt ? { startedAt: new Date(run.startedAt) } : {}), + completedAt: new Date(run.completedAt), + })), + }) + } +} + +function builderProjectSyncErrorResponse( + error: unknown, + headers: HeadersInit, +) { + if (error instanceof BuilderProjectNotFoundError) { + return jsonError('Project not found', 404, headers) + } + if (error instanceof BuilderProjectOwnershipError) { + return jsonError('Not authorized', 403, headers) + } + if (error instanceof BuilderProjectSnapshotRegistryConflictError) { + return jsonError( + 'Project snapshot must be uploaded before completing the run', + 409, + headers, + ) + } + if (error instanceof BuilderProjectSnapshotQuarantinedError) { + return jsonError('Builder project is unavailable', 410, headers) + } + if (error instanceof BuilderProjectSnapshotLimitError) { + return jsonError(error.message, 409, headers) + } + if (error instanceof BuilderProjectSnapshotStorageUnavailableError) { + return jsonError( + 'Builder project snapshot storage is unavailable', + 503, + headers, + ) + } + if (error instanceof BuilderProjectStorageUnavailableError) { + return jsonError('Builder project storage is unavailable', 503, headers) + } + if ( + error instanceof BuilderProjectConflictError || + error instanceof BuilderProjectDeletedError || + error instanceof BuilderProjectLeaseError + ) { + return jsonError(error.message, 409, headers) + } + console.error('Builder project sync failed:', error) + return jsonError('Failed to sync Builder project', 500, headers) +} diff --git a/src/routes/api/chat/projects.$id.ts b/src/routes/api/chat/projects.$id.ts index f2b56d95f..35d03fd69 100644 --- a/src/routes/api/chat/projects.$id.ts +++ b/src/routes/api/chat/projects.$id.ts @@ -1,12 +1,386 @@ import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' +import { + jsonError, + jsonResponse, + readJsonBody, + validateJsonRequest, +} from '~/utils/api-boundary.server' +import { isBuilderProjectId } from '~/utils/builder-project' +import { + BuilderProjectConflictError, + BuilderProjectDeletedError, + BuilderProjectNotFoundError, + BuilderProjectOwnershipError, + deleteBuilderProjectState, + getBuilderProjectMutationRequestHash, + updateBuilderProjectState, +} from '~/utils/builder-project-events.server' +import { + getOrImportBuilderProjectState, + toBuilderProject, +} from '~/utils/builder-project-state.server' +import { BuilderProjectStorageUnavailableError } from '~/utils/builder-project-storage.server' +import { + BuilderProjectSnapshotQuarantinedError, + BuilderProjectSnapshotStorageUnavailableError, + parseStoredBuilderProjectSnapshot, +} from '~/utils/builder-project-snapshot-storage.server' +import { + BuilderProjectSnapshotLimitError, + BuilderProjectSnapshotRegistryConflictError, + storeBuilderProjectSnapshotForOwner, +} from '~/utils/builder-project-snapshot-registry.server' +import { + checkIpRateLimit, + RATE_LIMITS, + rateLimitedResponse, +} from '~/utils/rateLimit.server' + +const maxRequestBytes = 2 * 1024 * 1024 export const Route = createFileRoute('/api/chat/projects/$id')({ server: { handlers: { - GET: ({ request }) => forwardWorkerRequest('CHAT', request), - PATCH: ({ request }) => forwardWorkerRequest('CHAT', request), - DELETE: ({ request }) => forwardWorkerRequest('CHAT', request), + GET: async ({ params }: { params: { id: string } }) => { + if (!isBuilderProjectId(params.id)) { + return jsonError('Project not found', 404) + } + + try { + const project = await getOrImportBuilderProjectState(params.id) + return jsonResponse({ project: toBuilderProject(project) }) + } catch (error) { + if (error instanceof BuilderProjectNotFoundError) { + return jsonError('Project not found', 404) + } + if (error instanceof BuilderProjectSnapshotQuarantinedError) { + return jsonError('Builder project is unavailable', 410) + } + if ( + error instanceof BuilderProjectSnapshotLimitError || + error instanceof BuilderProjectSnapshotRegistryConflictError + ) { + return jsonError(error.message, 409) + } + if ( + error instanceof BuilderProjectSnapshotStorageUnavailableError + ) { + return jsonError('Builder project storage is unavailable', 503) + } + if (error instanceof BuilderProjectStorageUnavailableError) { + return jsonError('Builder project storage is unavailable', 503) + } + console.error('Failed to load builder project:', error) + return jsonError('Failed to load builder project', 500) + } + }, + PATCH: async ({ + params, + request, + }: { + params: { id: string } + request: Request + }) => { + const requestError = validateJsonRequest(request, { + maxContentLength: maxRequestBytes, + }) + if (requestError) { + return jsonError(requestError.message, requestError.status) + } + if (!isBuilderProjectId(params.id)) { + return jsonError('Project not found', 404) + } + + const { getAuthService } = await import('~/auth/index.server') + const user = await getAuthService().getCurrentUser(request) + if (!user) return jsonError('Not authenticated', 401) + + const rateLimit = await checkIpRateLimit( + request, + RATE_LIMITS.builderProjectSave, + ) + if (!rateLimit.allowed) return rateLimitedResponse(rateLimit) + + let existing + try { + existing = await getOrImportBuilderProjectState(params.id) + } catch (error) { + if (error instanceof BuilderProjectNotFoundError) { + return jsonError('Project not found', 404, rateLimit.headers) + } + if (error instanceof BuilderProjectSnapshotQuarantinedError) { + return jsonError( + 'Builder project is unavailable', + 410, + rateLimit.headers, + ) + } + if ( + error instanceof BuilderProjectSnapshotLimitError || + error instanceof BuilderProjectSnapshotRegistryConflictError + ) { + return jsonError(error.message, 409, rateLimit.headers) + } + if ( + error instanceof BuilderProjectSnapshotStorageUnavailableError + ) { + return jsonError( + 'Builder project storage is unavailable', + 503, + rateLimit.headers, + ) + } + if (error instanceof BuilderProjectStorageUnavailableError) { + return jsonError( + 'Builder project storage is unavailable', + 503, + rateLimit.headers, + ) + } + console.error('Failed to load builder project for update:', error) + return jsonError( + 'Failed to load builder project', + 500, + rateLimit.headers, + ) + } + if (existing.ownerId !== user.userId) { + return jsonError('Not authorized', 403, rateLimit.headers) + } + + const body = await readJsonBody(request, { + maxContentLength: maxRequestBytes, + }) + if (!body.success) { + return jsonError( + body.error.message, + body.error.status, + rateLimit.headers, + ) + } + + let input + try { + input = parseBuilderProjectRequest(body.body) + } catch (error) { + return jsonError( + error instanceof Error ? error.message : 'Invalid builder project', + 400, + rateLimit.headers, + ) + } + + try { + const snapshot = input.project + const requestHash = await getBuilderProjectMutationRequestHash({ + type: 'project.revise', + ...input, + }) + const storedSnapshot = await storeBuilderProjectSnapshotForOwner( + user.userId, + snapshot, + ) + const project = await updateBuilderProjectState({ + clientMutationId: input.clientMutationId, + requestHash, + description: snapshot.description, + expectedRevisionNumber: input.expectedRevisionNumber, + projectId: existing.id, + revisionId: input.revisionId, + ownerId: user.userId, + snapshotHash: storedSnapshot.hash, + title: snapshot.title, + }) + return jsonResponse( + { project: toBuilderProject(project) }, + { headers: rateLimit.headers }, + ) + } catch (error) { + if ( + error instanceof BuilderProjectSnapshotLimitError || + error instanceof BuilderProjectSnapshotRegistryConflictError + ) { + return jsonError(error.message, 409, rateLimit.headers) + } + if (error instanceof BuilderProjectConflictError) { + return jsonError(error.message, 409, rateLimit.headers) + } + if (error instanceof BuilderProjectOwnershipError) { + return jsonError('Not authorized', 403, rateLimit.headers) + } + if ( + error instanceof BuilderProjectDeletedError || + error instanceof BuilderProjectSnapshotQuarantinedError + ) { + return jsonError( + 'Builder project is unavailable', + 410, + rateLimit.headers, + ) + } + if ( + error instanceof BuilderProjectStorageUnavailableError || + error instanceof BuilderProjectSnapshotStorageUnavailableError + ) { + return jsonError( + 'Builder storage is unavailable', + 503, + rateLimit.headers, + ) + } + console.error('Failed to update builder project:', error) + return jsonError( + 'Failed to update builder project', + 500, + rateLimit.headers, + ) + } + }, + DELETE: async ({ + params, + request, + }: { + params: { id: string } + request: Request + }) => { + const requestError = validateJsonRequest(request, { + maxContentLength: 1_024, + }) + if (requestError) { + return jsonError(requestError.message, requestError.status) + } + if (!isBuilderProjectId(params.id)) { + return jsonError('Project not found', 404) + } + + const { getAuthService } = await import('~/auth/index.server') + const user = await getAuthService().getCurrentUser(request) + if (!user) return jsonError('Not authenticated', 401) + + const rateLimit = await checkIpRateLimit( + request, + RATE_LIMITS.builderProjectWrite, + ) + if (!rateLimit.allowed) return rateLimitedResponse(rateLimit) + + const body = await readJsonBody(request, { maxContentLength: 1_024 }) + if (!body.success) { + return jsonError( + body.error.message, + body.error.status, + rateLimit.headers, + ) + } + let clientMutationId + try { + clientMutationId = parseDeleteBuilderProjectRequest(body.body) + } catch { + return jsonError( + 'Invalid Builder project delete request', + 400, + rateLimit.headers, + ) + } + + try { + await getOrImportBuilderProjectState(params.id) + await deleteBuilderProjectState({ + projectId: params.id, + ownerId: user.userId, + clientMutationId, + }) + return jsonResponse( + { deleted: true, id: params.id }, + { headers: rateLimit.headers }, + ) + } catch (error) { + if (error instanceof BuilderProjectNotFoundError) { + return jsonError('Project not found', 404, rateLimit.headers) + } + if (error instanceof BuilderProjectSnapshotQuarantinedError) { + return jsonError( + 'Builder project is unavailable', + 410, + rateLimit.headers, + ) + } + if ( + error instanceof BuilderProjectSnapshotLimitError || + error instanceof BuilderProjectSnapshotRegistryConflictError + ) { + return jsonError(error.message, 409, rateLimit.headers) + } + if (error instanceof BuilderProjectOwnershipError) { + return jsonError('Not authorized', 403, rateLimit.headers) + } + if ( + error instanceof BuilderProjectStorageUnavailableError || + error instanceof BuilderProjectSnapshotStorageUnavailableError + ) { + return jsonError( + 'Builder project storage is unavailable', + 503, + rateLimit.headers, + ) + } + console.error('Failed to delete builder project:', error) + return jsonError( + 'Failed to delete builder project', + 500, + rateLimit.headers, + ) + } + }, }, }, }) + +function parseBuilderProjectRequest(value: unknown) { + if ( + typeof value !== 'object' || + value === null || + Array.isArray(value) || + Object.keys(value).some( + (key) => + key !== 'clientMutationId' && + key !== 'expectedRevisionNumber' && + key !== 'project' && + key !== 'revisionId', + ) || + !('clientMutationId' in value) || + !('expectedRevisionNumber' in value) || + !('project' in value) || + !('revisionId' in value) || + typeof value.clientMutationId !== 'string' || + !isBuilderProjectId(value.clientMutationId) || + typeof value.expectedRevisionNumber !== 'number' || + !Number.isSafeInteger(value.expectedRevisionNumber) || + value.expectedRevisionNumber < 1 || + typeof value.revisionId !== 'string' || + !isBuilderProjectId(value.revisionId) + ) { + throw new Error('Invalid builder project request') + } + + return { + clientMutationId: value.clientMutationId, + expectedRevisionNumber: value.expectedRevisionNumber, + project: parseStoredBuilderProjectSnapshot(value.project), + revisionId: value.revisionId, + } +} + +function parseDeleteBuilderProjectRequest(value: unknown) { + if ( + typeof value !== 'object' || + value === null || + Array.isArray(value) || + Object.keys(value).some((key) => key !== 'clientMutationId') || + !('clientMutationId' in value) || + typeof value.clientMutationId !== 'string' || + !isBuilderProjectId(value.clientMutationId) + ) { + throw new Error('Invalid Builder project delete request') + } + return value.clientMutationId +} diff --git a/src/routes/api/chat/projects.ts b/src/routes/api/chat/projects.ts index 866b49235..5c409be82 100644 --- a/src/routes/api/chat/projects.ts +++ b/src/routes/api/chat/projects.ts @@ -1,11 +1,296 @@ import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' +import { + jsonError, + jsonResponse, + readJsonBody, + validateJsonRequest, +} from '~/utils/api-boundary.server' +import { + BuilderProjectLimitError, + BuilderProjectNotFoundError, + BuilderProjectConflictError, + createBuilderProjectState, + preflightBuilderProjectCreation, +} from '~/utils/builder-project-events.server' +import { + getOrImportBuilderProjectState, + listOrImportBuilderProjectStates, + reserveLegacyBuilderProjectId, + toBuilderProject, +} from '~/utils/builder-project-state.server' +import { + BuilderProjectStorageUnavailableError, +} from '~/utils/builder-project-storage.server' +import { isBuilderProjectId } from '~/utils/builder-project' +import { + BuilderProjectSnapshotQuarantinedError, + BuilderProjectSnapshotStorageUnavailableError, + getBuilderProjectSnapshotHash, + parseStoredBuilderProjectSnapshot, +} from '~/utils/builder-project-snapshot-storage.server' +import { + BuilderProjectSnapshotLimitError, + BuilderProjectSnapshotRegistryConflictError, + storeBuilderProjectSnapshotForOwner, +} from '~/utils/builder-project-snapshot-registry.server' +import { + checkIpRateLimit, + checkUserWindowRateLimit, + RATE_LIMITS, + rateLimitedResponse, +} from '~/utils/rateLimit.server' + +const maxRequestBytes = 2 * 1024 * 1024 export const Route = createFileRoute('/api/chat/projects')({ server: { handlers: { - GET: ({ request }) => forwardWorkerRequest('CHAT', request), - POST: ({ request }) => forwardWorkerRequest('CHAT', request), + GET: async ({ request }: { request: Request }) => { + const { getAuthService } = await import('~/auth/index.server') + const user = await getAuthService().getCurrentUser(request) + if (!user) return jsonError('Not authenticated', 401) + + const rateLimit = await checkIpRateLimit( + request, + RATE_LIMITS.builderProjectList, + ) + if (!rateLimit.allowed) return rateLimitedResponse(rateLimit) + + try { + const projects = await listOrImportBuilderProjectStates(user.userId) + return jsonResponse( + { projects: projects.map(toBuilderProject) }, + { headers: rateLimit.headers }, + ) + } catch (error) { + if (error instanceof BuilderProjectSnapshotQuarantinedError) { + return jsonError( + 'Builder project is unavailable', + 410, + rateLimit.headers, + ) + } + if ( + error instanceof BuilderProjectSnapshotLimitError || + error instanceof BuilderProjectSnapshotRegistryConflictError + ) { + return jsonError(error.message, 409, rateLimit.headers) + } + if ( + error instanceof BuilderProjectSnapshotStorageUnavailableError + ) { + return jsonError( + 'Builder project storage is unavailable', + 503, + rateLimit.headers, + ) + } + if (error instanceof BuilderProjectStorageUnavailableError) { + return jsonError( + 'Builder project storage is unavailable', + 503, + rateLimit.headers, + ) + } + console.error('Failed to list builder projects:', error) + return jsonError( + 'Failed to list builder projects', + 500, + rateLimit.headers, + ) + } + }, + POST: async ({ request }: { request: Request }) => { + const requestError = validateJsonRequest(request, { + maxContentLength: maxRequestBytes, + }) + if (requestError) { + return jsonError(requestError.message, requestError.status) + } + + const { getAuthService } = await import('~/auth/index.server') + const user = await getAuthService().getCurrentUser(request) + if (!user) return jsonError('Not authenticated', 401) + + const rateLimit = await checkIpRateLimit( + request, + RATE_LIMITS.builderProjectWrite, + ) + if (!rateLimit.allowed) return rateLimitedResponse(rateLimit) + + const body = await readJsonBody(request, { + maxContentLength: maxRequestBytes, + }) + if (!body.success) { + return jsonError( + body.error.message, + body.error.status, + rateLimit.headers, + ) + } + + let input + try { + input = parseBuilderProjectRequest(body.body) + } catch (error) { + return jsonError( + error instanceof Error ? error.message : 'Invalid builder project', + 400, + rateLimit.headers, + ) + } + + try { + await listOrImportBuilderProjectStates(user.userId) + const snapshotHash = await getBuilderProjectSnapshotHash( + input.project, + ) + const existing = await preflightBuilderProjectCreation({ + id: input.id, + ownerId: user.userId, + clientMutationId: input.clientMutationId, + revisionId: input.revisionId, + snapshotHash, + title: input.project.title, + description: input.project.description, + ...(input.forkedFromId + ? { forkedFromId: input.forkedFromId } + : {}), + }) + if (existing) { + return jsonResponse( + { project: toBuilderProject(existing) }, + { status: 201, headers: rateLimit.headers }, + ) + } + const creationLimit = await checkUserWindowRateLimit( + user.userId, + RATE_LIMITS.builderProjectCreateDaily, + ) + if (!creationLimit.allowed) { + return rateLimitedResponse(creationLimit) + } + await reserveLegacyBuilderProjectId(input.id) + + if (input.forkedFromId) { + try { + await getOrImportBuilderProjectState(input.forkedFromId) + } catch (error) { + if (error instanceof BuilderProjectNotFoundError) { + return jsonError( + 'Fork source builder was not found', + 400, + rateLimit.headers, + ) + } + throw error + } + } + + const snapshot = input.project + const storedSnapshot = await storeBuilderProjectSnapshotForOwner( + user.userId, + snapshot, + ) + const state = await createBuilderProjectState({ + id: input.id, + revisionId: input.revisionId, + clientMutationId: input.clientMutationId, + description: snapshot.description, + forkedFromId: input.forkedFromId, + ownerId: user.userId, + snapshotHash: storedSnapshot.hash, + title: snapshot.title, + }) + return jsonResponse( + { project: toBuilderProject(state) }, + { status: 201, headers: rateLimit.headers }, + ) + } catch (error) { + if (error instanceof BuilderProjectLimitError) { + return jsonError(error.message, 409, rateLimit.headers) + } + if ( + error instanceof BuilderProjectSnapshotLimitError || + error instanceof BuilderProjectSnapshotRegistryConflictError + ) { + return jsonError(error.message, 409, rateLimit.headers) + } + if (error instanceof BuilderProjectConflictError) { + return jsonError(error.message, 409, rateLimit.headers) + } + if ( + error instanceof BuilderProjectSnapshotQuarantinedError + ) { + return jsonError( + 'Builder project is unavailable', + 410, + rateLimit.headers, + ) + } + if ( + error instanceof BuilderProjectStorageUnavailableError || + error instanceof BuilderProjectSnapshotStorageUnavailableError + ) { + return jsonError( + 'Builder storage is unavailable', + 503, + rateLimit.headers, + ) + } + console.error('Failed to create builder project:', error) + return jsonError( + 'Failed to create builder project', + 500, + rateLimit.headers, + ) + } + }, }, }, }) + +function parseBuilderProjectRequest(value: unknown) { + if ( + typeof value !== 'object' || + value === null || + Array.isArray(value) || + Object.keys(value).some( + (key) => + key !== 'clientMutationId' && + key !== 'forkedFromId' && + key !== 'id' && + key !== 'project' && + key !== 'revisionId', + ) || + !('clientMutationId' in value) || + !('id' in value) || + !('project' in value) || + !('revisionId' in value) || + typeof value.clientMutationId !== 'string' || + !isBuilderProjectId(value.clientMutationId) || + typeof value.id !== 'string' || + !isBuilderProjectId(value.id) || + typeof value.revisionId !== 'string' || + !isBuilderProjectId(value.revisionId) + ) { + throw new Error('Invalid builder project request') + } + + const forkedFromId = + 'forkedFromId' in value ? value.forkedFromId : undefined + if ( + forkedFromId !== undefined && + (typeof forkedFromId !== 'string' || !isBuilderProjectId(forkedFromId)) + ) { + throw new Error('Invalid fork source builder ID') + } + + return { + clientMutationId: value.clientMutationId, + id: value.id, + project: parseStoredBuilderProjectSnapshot(value.project), + revisionId: value.revisionId, + ...(forkedFromId ? { forkedFromId } : {}), + } +} diff --git a/src/routes/api/chat/recipes.ts b/src/routes/api/chat/recipes.ts index 5bd18baf6..0ecf5c2e4 100644 --- a/src/routes/api/chat/recipes.ts +++ b/src/routes/api/chat/recipes.ts @@ -1,10 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' - -export const Route = createFileRoute('/api/chat/recipes')({ - server: { - handlers: { - POST: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, -}) +import {createFileRoute} from '@tanstack/react-router' +import {handleSavedActions} from '~/chat/server/saved-actions-http.server' +export const Route=createFileRoute('/api/chat/recipes')({server:{handlers:{POST:({request})=>handleSavedActions(request)}}}) diff --git a/src/routes/api/chat/recipes/$id.ts b/src/routes/api/chat/recipes/$id.ts index 6a4425610..3192e5d9d 100644 --- a/src/routes/api/chat/recipes/$id.ts +++ b/src/routes/api/chat/recipes/$id.ts @@ -1,10 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' - -export const Route = createFileRoute('/api/chat/recipes/$id')({ - server: { - handlers: { - DELETE: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, -}) +import {createFileRoute} from '@tanstack/react-router' +import {handleSavedActions} from '~/chat/server/saved-actions-http.server' +export const Route=createFileRoute('/api/chat/recipes/$id')({server:{handlers:{DELETE:({request,params})=>handleSavedActions(request,params.id)}}}) diff --git a/src/routes/api/chat/references.ts b/src/routes/api/chat/references.ts index 0673bd879..9e1448e71 100644 --- a/src/routes/api/chat/references.ts +++ b/src/routes/api/chat/references.ts @@ -1,10 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' - -export const Route = createFileRoute('/api/chat/references')({ - server: { - handlers: { - GET: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, -}) +import {createFileRoute} from '@tanstack/react-router' +import {handleReferences} from '~/chat/server/reference-http.server' +export const Route=createFileRoute('/api/chat/references')({server:{handlers:{GET:({request})=>handleReferences(request)}}}) diff --git a/src/routes/api/chat/references/kody/inspect.ts b/src/routes/api/chat/references/kody/inspect.ts index 04e8aeaed..20193572e 100644 --- a/src/routes/api/chat/references/kody/inspect.ts +++ b/src/routes/api/chat/references/kody/inspect.ts @@ -1,10 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' - -export const Route = createFileRoute('/api/chat/references/kody/inspect')({ - server: { - handlers: { - GET: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, -}) +import {createFileRoute} from '@tanstack/react-router' +import {handleReferenceCatalog} from '~/chat/server/reference-catalog-http.server' +export const Route=createFileRoute('/api/chat/references/kody/inspect')({server:{handlers:{GET:({request})=>handleReferenceCatalog(request,'kody-inspect')}}}) diff --git a/src/routes/api/chat/references/kody/refresh.ts b/src/routes/api/chat/references/kody/refresh.ts index 1c329b388..bc0082c46 100644 --- a/src/routes/api/chat/references/kody/refresh.ts +++ b/src/routes/api/chat/references/kody/refresh.ts @@ -1,10 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' - -export const Route = createFileRoute('/api/chat/references/kody/refresh')({ - server: { - handlers: { - POST: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, -}) +import {createFileRoute} from '@tanstack/react-router' +import {handleReferenceCatalog} from '~/chat/server/reference-catalog-http.server' +export const Route=createFileRoute('/api/chat/references/kody/refresh')({server:{handlers:{POST:({request})=>handleReferenceCatalog(request,'kody-refresh')}}}) diff --git a/src/routes/api/chat/references/tools/refresh.ts b/src/routes/api/chat/references/tools/refresh.ts index 9d6258b07..7d6a84be2 100644 --- a/src/routes/api/chat/references/tools/refresh.ts +++ b/src/routes/api/chat/references/tools/refresh.ts @@ -1,10 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' - -export const Route = createFileRoute('/api/chat/references/tools/refresh')({ - server: { - handlers: { - POST: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, -}) +import {createFileRoute} from '@tanstack/react-router' +import {handleReferenceCatalog} from '~/chat/server/reference-catalog-http.server' +export const Route=createFileRoute('/api/chat/references/tools/refresh')({server:{handlers:{POST:({request})=>handleReferenceCatalog(request,'tools-refresh')}}}) diff --git a/src/routes/api/chat/retries/$id.prepare.ts b/src/routes/api/chat/retries/$id.prepare.ts index 545cd5c0f..3c0b886af 100644 --- a/src/routes/api/chat/retries/$id.prepare.ts +++ b/src/routes/api/chat/retries/$id.prepare.ts @@ -1,10 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' - -export const Route = createFileRoute('/api/chat/retries/$id/prepare')({ - server: { - handlers: { - POST: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, -}) +import {createFileRoute} from '@tanstack/react-router' +import {handleConversationRetry} from '~/chat/server/conversation-retry-http.server' +export const Route=createFileRoute('/api/chat/retries/$id/prepare')({server:{handlers:{POST:({request,params})=>handleConversationRetry(request,params.id,'prepare')}}}) diff --git a/src/routes/api/chat/retries/$id.ts b/src/routes/api/chat/retries/$id.ts index b110765a6..4e94643bf 100644 --- a/src/routes/api/chat/retries/$id.ts +++ b/src/routes/api/chat/retries/$id.ts @@ -1,10 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' - -export const Route = createFileRoute('/api/chat/retries/$id')({ - server: { - handlers: { - GET: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, -}) +import {createFileRoute} from '@tanstack/react-router' +import {handleConversationRetry} from '~/chat/server/conversation-retry-http.server' +export const Route=createFileRoute('/api/chat/retries/$id')({server:{handlers:{GET:({request,params})=>handleConversationRetry(request,params.id,'get')}}}) diff --git a/src/routes/api/chat/sections.ts b/src/routes/api/chat/sections.ts index dc5cd086e..9a6a4ba76 100644 --- a/src/routes/api/chat/sections.ts +++ b/src/routes/api/chat/sections.ts @@ -1,10 +1,3 @@ import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' - -export const Route = createFileRoute('/api/chat/sections')({ - server: { - handlers: { - POST: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, -}) +import { handleWorkspaceSections } from '~/chat/server/workspace-sections-http.server' +export const Route=createFileRoute('/api/chat/sections')({server:{handlers:{POST:({request})=>handleWorkspaceSections(request)}}}) diff --git a/src/routes/api/chat/sections/$id.ts b/src/routes/api/chat/sections/$id.ts index 27daa91c1..f35a13dfc 100644 --- a/src/routes/api/chat/sections/$id.ts +++ b/src/routes/api/chat/sections/$id.ts @@ -1,11 +1,3 @@ import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' - -export const Route = createFileRoute('/api/chat/sections/$id')({ - server: { - handlers: { - PATCH: ({ request }) => forwardWorkerRequest('CHAT', request), - DELETE: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, -}) +import { handleWorkspaceSections } from '~/chat/server/workspace-sections-http.server' +export const Route=createFileRoute('/api/chat/sections/$id')({server:{handlers:{PATCH:({request,params})=>handleWorkspaceSections(request,params.id),DELETE:({request,params})=>handleWorkspaceSections(request,params.id)}}}) diff --git a/src/routes/api/chat/skills.ts b/src/routes/api/chat/skills.ts index 4358c8cf2..99e804384 100644 --- a/src/routes/api/chat/skills.ts +++ b/src/routes/api/chat/skills.ts @@ -1,11 +1,28 @@ +import { hasChatAccess } from '~/chat/access.server' +import { z } from 'zod' import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' - -export const Route = createFileRoute('/api/chat/skills')({ - server: { - handlers: { - GET: ({ request }) => forwardWorkerRequest('CHAT', request), - POST: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, -}) +import { getAuthService } from '~/auth/index.server' +import { jsonError,validateSameOriginRequest } from '~/utils/api-boundary.server' +import { readWorkspacePolicy,WorkspacePolicyError } from '~/chat/workspace-policy.server' +import { getKodyEnvironment,KodyEnvironmentError } from '~/chat/server/kody-environment.server' +import { skillApi } from '~/chat/server/skill-api' +export async function handleSkills(request:Request, id?:string) { + if(request.method==='POST') { + const error=validateSameOriginRequest(request) + if(error) return jsonError(error.message,error.status) + } + const user=await getAuthService().getCurrentUser(request) + if(!user) return jsonError('Sign in to continue.',401) + if(!await hasChatAccess(user)) return jsonError('Chat access is unavailable.',403) + const url=new URL(request.url) + const parsed=z.string().min(1).max(1000).safeParse(url.searchParams.get('workspaceId')) + if(url.searchParams.getAll('workspaceId').length!==1||!parsed.success) return jsonError('Choose a workspace.',400) + try { + await readWorkspacePolicy(parsed.data,user.userId) + return await skillApi(request,await getKodyEnvironment(),{workspaceId:parsed.data,userId:user.userId},id??url.searchParams.get('id')??undefined) + } catch(error) { + if(error instanceof WorkspacePolicyError||error instanceof KodyEnvironmentError) return jsonError(error.message,error.status) + throw error + } +} +export const Route=createFileRoute('/api/chat/skills')({server:{handlers:{GET:({request})=>handleSkills(request),POST:({request})=>handleSkills(request)}}}) diff --git a/src/routes/api/chat/skills/$id.ts b/src/routes/api/chat/skills/$id.ts index e2d60032f..86f245dcb 100644 --- a/src/routes/api/chat/skills/$id.ts +++ b/src/routes/api/chat/skills/$id.ts @@ -1,11 +1,11 @@ import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' +import { handleSkills } from '../skills' export const Route = createFileRoute('/api/chat/skills/$id')({ server: { handlers: { - GET: ({ request }) => forwardWorkerRequest('CHAT', request), - POST: ({ request }) => forwardWorkerRequest('CHAT', request), + GET: ({ request, params }) => handleSkills(request, params.id), + POST: ({ request, params }) => handleSkills(request, params.id), }, }, }) diff --git a/src/routes/api/chat/workspace-history.ts b/src/routes/api/chat/workspace-history.ts index 180f4ca43..33fa26dd9 100644 --- a/src/routes/api/chat/workspace-history.ts +++ b/src/routes/api/chat/workspace-history.ts @@ -1,10 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' - -export const Route = createFileRoute('/api/chat/workspace-history')({ - server: { - handlers: { - POST: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, -}) +import {createFileRoute} from '@tanstack/react-router' +import {handleBotMutation} from '~/chat/server/bot-mutation-http.server' +export const Route=createFileRoute('/api/chat/workspace-history')({server:{handlers:{POST:({request})=>handleBotMutation(request,undefined,undefined,'history')}}}) diff --git a/src/routes/api/chat/workspace-index.activity.ts b/src/routes/api/chat/workspace-index.activity.ts index 741887d80..9ed2c2ba8 100644 --- a/src/routes/api/chat/workspace-index.activity.ts +++ b/src/routes/api/chat/workspace-index.activity.ts @@ -1,10 +1,3 @@ -import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' - -export const Route = createFileRoute('/api/chat/workspace-index/activity')({ - server: { - handlers: { - GET: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, -}) +import {createFileRoute} from '@tanstack/react-router' +import {handleWorkspaceActivity} from '~/chat/server/workspace-activity-http.server' +export const Route=createFileRoute('/api/chat/workspace-index/activity')({server:{handlers:{GET:({request})=>handleWorkspaceActivity(request,true)}}}) diff --git a/src/routes/api/chat/workspace-index.ts b/src/routes/api/chat/workspace-index.ts index 51c2daacf..342e65115 100644 --- a/src/routes/api/chat/workspace-index.ts +++ b/src/routes/api/chat/workspace-index.ts @@ -1,10 +1,5 @@ import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' - +import { handleWorkspaceIndex } from '~/chat/server/workspace-index-http.server' export const Route = createFileRoute('/api/chat/workspace-index')({ - server: { - handlers: { - GET: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, + server: { handlers: { GET: ({request}) => handleWorkspaceIndex(request) } }, }) diff --git a/src/routes/api/chat/workspace-sync/$operation.ts b/src/routes/api/chat/workspace-sync/$operation.ts index e3ddee49d..bb0f363d9 100644 --- a/src/routes/api/chat/workspace-sync/$operation.ts +++ b/src/routes/api/chat/workspace-sync/$operation.ts @@ -1,10 +1,5 @@ import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' - +import { handleWorkspaceSync } from '~/chat/server/workspace-sync-http.server' export const Route = createFileRoute('/api/chat/workspace-sync/$operation')({ - server: { - handlers: { - GET: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, + server: {handlers: {GET: ({request,params}) => handleWorkspaceSync(request,params.operation)}}, }) diff --git a/src/routes/api/chat/workspace.ts b/src/routes/api/chat/workspace.ts index fd135a489..a86f84914 100644 --- a/src/routes/api/chat/workspace.ts +++ b/src/routes/api/chat/workspace.ts @@ -1,10 +1,22 @@ +import { hasChatAccess } from '~/chat/access.server' import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' +import { getAuthService } from '~/auth/index.server' +import { openPersonalChatWorkspace } from '~/chat/workspace.server' +import { jsonError, jsonResponse, validateSameOriginRequest } from '~/utils/api-boundary.server' export const Route = createFileRoute('/api/chat/workspace')({ server: { handlers: { - POST: ({ request }) => forwardWorkerRequest('CHAT', request), + POST: async ({ request }) => { + const boundaryError = validateSameOriginRequest(request) + if (boundaryError) return jsonError(boundaryError.message, boundaryError.status) + const user = await getAuthService().getCurrentUser(request) + if (!user) return jsonError('Sign in to TanStack.', 401) + if (!await hasChatAccess(user)) + return jsonError('Chat access is not enabled for this account.', 403) + const workspace = await openPersonalChatWorkspace(user.userId) + return jsonResponse(workspace) + }, }, }, }) diff --git a/src/routes/api/og/{$}[.]png.ts b/src/routes/api/og/{$}[.]png.ts index 1a54b3e8d..f399f2d0b 100644 --- a/src/routes/api/og/{$}[.]png.ts +++ b/src/routes/api/og/{$}[.]png.ts @@ -1,8 +1,64 @@ import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' + +type GenerateOgImageResponse = typeof import( + '~/server/og/generate.server' +)['generateOgImageResponse'] + +const CACHE_HEADERS = { + 'Cache-Control': 'public, max-age=3600', + 'Cloudflare-CDN-Cache-Control': + 'public, max-age=86400, stale-while-revalidate=604800', +} as const export const Route = createFileRoute('/api/og/{$}.png')({ server: { - handlers: { GET: ({ request }) => forwardWorkerRequest('OG', request) }, + handlers: { + GET: async ({ + request, + params, + }: { + request: Request + params: { _splat: string } + }) => { + const rawParam = params._splat + const libraryId = rawParam.replace(/\.png$/, '') + + const url = new URL(request.url) + let result: Awaited> + try { + const { generateOgImageResponse } = await import( + '~/server/og/generate.server' + ) + result = await generateOgImageResponse( + { + libraryId, + requestUrl: request.url, + title: url.searchParams.get('title') ?? undefined, + description: url.searchParams.get('description') ?? undefined, + }, + { headers: CACHE_HEADERS }, + ) + } catch (error) { + console.error('Failed to construct OG response', error) + return new Response('Failed to generate OG image', { status: 500 }) + } + + if ('kind' in result) { + return new Response(`Unknown library: ${libraryId}`, { status: 404 }) + } + + // ImageResponse builds the Response synchronously and renders inside + // a ReadableStream. Await the ready promise so render errors surface + // as 500s instead of an empty 200 cached at the edge. + try { + await result.ready + } catch (error) { + console.error('Failed to generate OG image', error) + return new Response('Failed to generate OG image', { status: 500 }) + } + + return result + }, + }, }, }) diff --git a/src/routes/api/readme/{$}[.]png.ts b/src/routes/api/readme/{$}[.]png.ts index e70ca7210..b6298392d 100644 --- a/src/routes/api/readme/{$}[.]png.ts +++ b/src/routes/api/readme/{$}[.]png.ts @@ -1,8 +1,101 @@ import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' +import { findLibrary } from '~/libraries' +import type { Framework } from '~/libraries/types' +import { OG_THEMES, isOgTheme } from '~/server/og/colors' + +type GenerateReadmeHeaderResponse = typeof import( + '~/server/og/generate.server' +)['generateReadmeHeaderResponse'] + +const CACHE_HEADERS = { + 'Cache-Control': 'public, max-age=3600', + 'Cloudflare-CDN-Cache-Control': + 'public, max-age=86400, stale-while-revalidate=604800', +} as const export const Route = createFileRoute('/api/readme/{$}.png')({ server: { - handlers: { GET: ({ request }) => forwardWorkerRequest('OG', request) }, + handlers: { + GET: async ({ + request, + params, + }: { + request: Request + params: { _splat: string } + }) => { + const libraryId = params._splat.replace(/\.png$/, '') + const library = findLibrary(libraryId) + if (!library) { + return new Response(`Unknown library: ${libraryId}`, { status: 404 }) + } + + const url = new URL(request.url) + + // Validated rather than ignored: a typo'd framework in a README should + // surface as a broken image, not as a banner naming the wrong package. + // An omitted param means "no framework"; a present-but-blank one + // (`?framework=`) is a malformed URL, not a request for the default. + const framework = url.searchParams.get('framework') ?? undefined + if ( + framework !== undefined && + !library.frameworks.includes(framework as Framework) + ) { + return new Response( + `Unknown framework "${framework}" for ${library.name}. Expected one of: ${library.frameworks.join(', ')}`, + { status: 400 }, + ) + } + + // Same contract as `framework`: supplied means it must be valid. + const themeParam = url.searchParams.get('theme') ?? undefined + if (themeParam !== undefined && !isOgTheme(themeParam)) { + return new Response( + `Unknown theme "${themeParam}". Expected one of: ${OG_THEMES.join(', ')}`, + { status: 400 }, + ) + } + + let result: Awaited> + try { + const { generateReadmeHeaderResponse } = await import( + '~/server/og/generate.server' + ) + result = await generateReadmeHeaderResponse( + { + libraryId, + requestUrl: request.url, + framework: framework as Framework | undefined, + title: url.searchParams.get('title') ?? undefined, + subtitle: url.searchParams.get('subtitle') ?? undefined, + theme: themeParam, + }, + { headers: CACHE_HEADERS }, + ) + } catch (error) { + console.error('Failed to construct README header response', error) + return new Response('Failed to generate README header', { + status: 500, + }) + } + + if ('kind' in result) { + return new Response(`Unknown library: ${libraryId}`, { status: 404 }) + } + + // ImageResponse builds the Response synchronously and renders inside + // a ReadableStream. Await the ready promise so render errors surface + // as 500s instead of an empty 200 cached at the edge. + try { + await result.ready + } catch (error) { + console.error('Failed to generate README header', error) + return new Response('Failed to generate README header', { + status: 500, + }) + } + + return result + }, + }, }, }) diff --git a/src/routes/auth/mcp/callback.ts b/src/routes/auth/mcp/callback.ts index ec203b520..b6d9c4eac 100644 --- a/src/routes/auth/mcp/callback.ts +++ b/src/routes/auth/mcp/callback.ts @@ -1,10 +1,5 @@ import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' - +import { handleMcpOAuth } from '~/chat/server/mcp-oauth-route.server' export const Route = createFileRoute('/auth/mcp/callback')({ - server: { - handlers: { - GET: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, + server: { handlers: { GET: ({ request }) => handleMcpOAuth(request) } }, }) diff --git a/src/routes/auth/mcp/client-metadata.ts b/src/routes/auth/mcp/client-metadata.ts index 3be5d8b85..fb133bc0e 100644 --- a/src/routes/auth/mcp/client-metadata.ts +++ b/src/routes/auth/mcp/client-metadata.ts @@ -1,10 +1,5 @@ import { createFileRoute } from '@tanstack/react-router' -import { forwardWorkerRequest } from '~/server/runtime/worker-service.server' - +import { handleMcpOAuth } from '~/chat/server/mcp-oauth-route.server' export const Route = createFileRoute('/auth/mcp/client-metadata')({ - server: { - handlers: { - GET: ({ request }) => forwardWorkerRequest('CHAT', request), - }, - }, + server: { handlers: { GET: ({ request }) => handleMcpOAuth(request) } }, }) diff --git a/src/routes/chat.c.$conversationId.tsx b/src/routes/chat.c.$conversationId.tsx index 9f0b8ff3d..19c1e3718 100644 --- a/src/routes/chat.c.$conversationId.tsx +++ b/src/routes/chat.c.$conversationId.tsx @@ -1,5 +1,5 @@ import { createFileRoute, stripSearchParams } from '@tanstack/react-router' -import { AppRoute } from '~/chat/components/AppRoute' +import { App } from '~/chat/components/App' import { defaultWorkspaceSearch, validateWorkspaceSearch, @@ -8,5 +8,5 @@ import { export const Route = createFileRoute('/chat/c/$conversationId')({ validateSearch: validateWorkspaceSearch, search: { middlewares: [stripSearchParams(defaultWorkspaceSearch)] }, - component: AppRoute, + component: App, }) diff --git a/src/routes/chat.charts.tsx b/src/routes/chat.charts.tsx index 365dcae8c..3fc691889 100644 --- a/src/routes/chat.charts.tsx +++ b/src/routes/chat.charts.tsx @@ -1,5 +1,4 @@ import * as React from 'react' -import { createClientOnlyFn } from '@tanstack/react-start' import { ClientOnly, createFileRoute } from '@tanstack/react-router' import { BuilderEmbeddedSkeleton, @@ -8,12 +7,10 @@ import { import { seo } from '~/utils/seo' import { webContainerHeaders } from '~/utils/stackblitz-embed' -const LazyChartsBuilderPage = React.lazy( - createClientOnlyFn(() => - import('~/components/charts/ChartsBuilderPage.client').then((module) => ({ - default: module.ChartsBuilderPage, - })), - ), +const LazyChartsBuilderPage = React.lazy(() => + import('~/components/charts/ChartsBuilderPage.client').then((module) => ({ + default: module.ChartsBuilderPage, + })), ) export const Route = createFileRoute('/chat/charts')({ diff --git a/src/routes/chat.new-project.tsx b/src/routes/chat.new-project.tsx index 89fe8c6e3..a68aa1513 100644 --- a/src/routes/chat.new-project.tsx +++ b/src/routes/chat.new-project.tsx @@ -1,6 +1,7 @@ import { createFileRoute, redirect } from '@tanstack/react-router' import * as v from 'valibot' import { getCurrentUser } from '~/utils/auth.functions' +import { loadChatWorkspace } from '~/chat/workspace.functions' import { defaultWorkspaceSearch } from '~/chat/core/navigation' export const Route = createFileRoute('/chat/new-project')({ @@ -8,7 +9,6 @@ export const Route = createFileRoute('/chat/new-project')({ template: v.optional(v.pipe(v.string(), v.minLength(1), v.maxLength(200))), }), beforeLoad: async ({ search }) => { - const { loadChatWorkspace } = await import('~/chat/workspace.functions') const user = await getCurrentUser() if (!user) { const query = search.template diff --git a/src/routes/chat.p.$hash.tsx b/src/routes/chat.p.$hash.tsx index 7cb3a4495..68ef23a68 100644 --- a/src/routes/chat.p.$hash.tsx +++ b/src/routes/chat.p.$hash.tsx @@ -1,5 +1,4 @@ import * as React from 'react' -import { createClientOnlyFn } from '@tanstack/react-start' import { ClientOnly, createFileRoute } from '@tanstack/react-router' import { BuilderEmbeddedSkeleton, @@ -8,12 +7,10 @@ import { import { seo } from '~/utils/seo' import { webContainerHeaders } from '~/utils/stackblitz-embed' -const LazySharedExamplePage = React.lazy( - createClientOnlyFn(() => - import('~/components/examples/SharedExamplePage.client').then((module) => ({ - default: module.SharedExamplePage, - })), - ), +const LazySharedExamplePage = React.lazy(() => + import('~/components/examples/SharedExamplePage.client').then((module) => ({ + default: module.SharedExamplePage, + })), ) export const Route = createFileRoute('/chat/p/$hash')({ diff --git a/src/routes/chat.project.$projectId.tsx b/src/routes/chat.project.$projectId.tsx index 6dee7a108..1597815fd 100644 --- a/src/routes/chat.project.$projectId.tsx +++ b/src/routes/chat.project.$projectId.tsx @@ -1,11 +1,11 @@ import { createFileRoute, notFound, redirect } from '@tanstack/react-router' import * as v from 'valibot' import { getCurrentUser } from '~/utils/auth.functions' +import { loadChatWorkspace } from '~/chat/workspace.functions' import { defaultWorkspaceSearch } from '~/chat/core/navigation' export const Route = createFileRoute('/chat/project/$projectId')({ beforeLoad: async ({ params }) => { - const { loadChatWorkspace } = await import('~/chat/workspace.functions') const parsed = v.safeParse(v.pipe(v.string(), v.uuid()), params.projectId) if (!parsed.success) throw notFound() const user = await getCurrentUser() diff --git a/src/routes/chat.shared.tsx b/src/routes/chat.shared.tsx index 878a78313..d8aafd0bd 100644 --- a/src/routes/chat.shared.tsx +++ b/src/routes/chat.shared.tsx @@ -1,5 +1,4 @@ import * as React from 'react' -import { createClientOnlyFn } from '@tanstack/react-start' import { ClientOnly, createFileRoute } from '@tanstack/react-router' import { BuilderEmbeddedSkeleton, @@ -8,12 +7,10 @@ import { import { seo } from '~/utils/seo' import { webContainerHeaders } from '~/utils/stackblitz-embed' -const LazySharedExamplePage = React.lazy( - createClientOnlyFn(() => - import('~/components/examples/SharedExamplePage.client').then((module) => ({ - default: module.SharedExamplePage, - })), - ), +const LazySharedExamplePage = React.lazy(() => + import('~/components/examples/SharedExamplePage.client').then((module) => ({ + default: module.SharedExamplePage, + })), ) export const Route = createFileRoute('/chat/shared')({ diff --git a/src/routes/chat.tsx b/src/routes/chat.tsx index 242e9f220..eade2280a 100644 --- a/src/routes/chat.tsx +++ b/src/routes/chat.tsx @@ -1,6 +1,9 @@ +import { getChatAccess } from '~/chat/access.functions' import { createServerFn } from '@tanstack/react-start' +import { appearanceScript } from '~/chat/core/appearance-bootstrap' import { createFileRoute, redirect } from '@tanstack/react-router' -import { ChatShellRoute } from '~/chat/components/ChatShellRoute' +import { ChatShell } from '~/chat/components/ChatShell' +import chatStyles from '~/chat/styles.css?url' import { webContainerHeaders } from '~/utils/stackblitz-embed' const initialAppearance = createServerFn({ method: 'GET' }).handler( @@ -15,20 +18,11 @@ export const Route = createFileRoute('/chat')({ staticData: { showNavbar: false }, beforeLoad: async ({ cause }) => { if (cause === 'stay') return - const { getChatAccess } = await import('~/chat/access.functions') const access = await getChatAccess() if (!access?.unlocked) throw redirect({ to: '/chat-access', search: { invite: undefined } }) }, - loader: async () => { - const [{ appearanceScript }, { default: chatStyles }, appearance] = - await Promise.all([ - import('~/chat/core/appearance-bootstrap'), - import('~/chat/styles.css?url'), - typeof window === 'undefined' ? initialAppearance() : null, - ]) - return { appearanceScript, chatStyles, appearance } - }, + loader: () => (typeof window === 'undefined' ? initialAppearance() : null), staleTime: Infinity, shouldReload: false, headers: () => ({ @@ -37,12 +31,12 @@ export const Route = createFileRoute('/chat')({ 'Cloudflare-CDN-Cache-Control': 'no-store', }), head: ({ loaderData }) => ({ - links: [{ rel: 'stylesheet', href: loaderData?.chatStyles }], + links: [{ rel: 'stylesheet', href: chatStyles }], scripts: [ { - children: `${loaderData?.appearance ? `document.documentElement.setAttribute('data-gum-ssr-appearance',${JSON.stringify(loaderData.appearance).replace(/ { - const { resolveChatRoute } = await import('~/chat/workspace.functions') const identity = await resolveChatRoute({ data: { ...params, conversationId: search.conversation }, }) diff --git a/src/routes/chat.w.$workspaceId.tsx b/src/routes/chat.w.$workspaceId.tsx index faa4e170b..4877fa94f 100644 --- a/src/routes/chat.w.$workspaceId.tsx +++ b/src/routes/chat.w.$workspaceId.tsx @@ -1,5 +1,5 @@ import { createFileRoute, stripSearchParams } from '@tanstack/react-router' -import { AppRoute } from '~/chat/components/AppRoute' +import { App } from '~/chat/components/App' import { validateWorkspaceSearch, defaultWorkspaceSearch, @@ -8,5 +8,5 @@ import { export const Route = createFileRoute('/chat/w/$workspaceId')({ validateSearch: validateWorkspaceSearch, search: { middlewares: [stripSearchParams(defaultWorkspaceSearch)] }, - component: AppRoute, + component: App, }) diff --git a/src/routes/ds.iconography.lazy.tsx b/src/routes/ds.iconography.lazy.tsx index 85a2c678f..5f810d914 100644 --- a/src/routes/ds.iconography.lazy.tsx +++ b/src/routes/ds.iconography.lazy.tsx @@ -1,21 +1,224 @@ import * as React from 'react' -import { createClientOnlyFn } from '@tanstack/react-start' -import { ClientOnly, createLazyFileRoute } from '@tanstack/react-router' - -const IconographyPage = React.lazy( - createClientOnlyFn(() => - import('~/components/ds/IconographyPage.client').then((module) => ({ - default: module.IconographyPage, - })), - ), -) +import { twMerge } from 'tailwind-merge' +import { createLazyFileRoute } from '@tanstack/react-router' +import { + CaretDownIcon, + CheckIcon, + MagnifyingGlassIcon, + StarIcon, +} from '@phosphor-icons/react' +import type { IconWeight } from '@phosphor-icons/react' +import { copyTextToClipboard } from '~/utils/browser-effects' +import { DsPage, DsSection } from '~/components/ds/DsKit' +import { phosphorIconRegistry } from '~/components/ds/phosphor-icons.generated' +import { + Dropdown, + DropdownContent, + DropdownItem, + DropdownTrigger, +} from '~/components/ds/ui' export const Route = createLazyFileRoute('/ds/iconography')({ - component: () => ( - - - - - - ), + component: IconographyPage, }) + +const WEIGHTS: Array = [ + 'thin', + 'light', + 'regular', + 'bold', + 'fill', + 'duotone', +] +const SIZES = [16, 20, 24, 32, 48] +const PAGE_SIZE = 120 + +const triggerClass = + 'inline-flex h-10 items-center gap-2 rounded-lg border border-border-default bg-background-surface px-3 text-sm text-text-primary transition-colors hover:bg-background-subtle' + +// A small square that scales with the icon size — the visual size cue. +function SizeGlyph({ px }: { px: number }) { + const box = Math.max(8, Math.min(22, Math.round(px * 0.5))) + return ( + + ) +} + +function IconographyPage() { + const [weight, setWeight] = React.useState('regular') + const [size, setSize] = React.useState(24) + const [query, setQuery] = React.useState('') + const [searchOpen, setSearchOpen] = React.useState(false) + const [copied, setCopied] = React.useState(null) + const [visible, setVisible] = React.useState(PAGE_SIZE) + const searchInputRef = React.useRef(null) + + React.useEffect(() => { + if (searchOpen) searchInputRef.current?.focus() + }, [searchOpen]) + + const closeSearch = React.useCallback(() => { + setQuery('') + setSearchOpen(false) + }, []) + + const filtered = React.useMemo(() => { + const q = query.trim().toLowerCase() + if (!q) return phosphorIconRegistry + return phosphorIconRegistry.filter((icon) => + icon.name.toLowerCase().includes(q), + ) + }, [query]) + + // Reset paging when the result set changes. + React.useEffect(() => { + setVisible(PAGE_SIZE) + }, [query]) + + const shown = filtered.slice(0, visible) + + // The registry keys icons by their bare name, but `NameIcon` is the export + // callers actually import — copy and advertise that one. + const handleCopy = React.useCallback(async (name: string) => { + await copyTextToClipboard(`<${name}Icon />`) + setCopied(name) + window.setTimeout(() => setCopied(null), 1200) + }, []) + + return ( + + +
+ {/* Style (weight) — dropdown with a live preview per weight */} + + + + + + {WEIGHTS.map((w) => ( + setWeight(w)}> + + {w} + {w === weight ? ( + + ) : null} + + ))} + + + + {/* Size — dropdown with a scaling size glyph per option */} + + + + + + {SIZES.map((s) => ( + setSize(s)}> + + + + {s}px + {s === size ? ( + + ) : null} + + ))} + + + + {/* Expanding search — icon grows on hover, opens into a field */} +
+ + setQuery(e.target.value)} + onKeyDown={(e) => e.key === 'Escape' && closeSearch()} + placeholder="Search icons…" + className={twMerge( + 'min-w-0 flex-1 bg-transparent pr-3 text-sm text-text-primary placeholder-text-muted outline-none transition-opacity duration-200', + searchOpen ? 'opacity-100' : 'pointer-events-none opacity-0', + )} + /> +
+ + + {filtered.length.toLocaleString()} icons + +
+ +
+ {shown.map(({ name, Cmp }) => ( + + ))} +
+ + {shown.length < filtered.length ? ( +
+ +
+ ) : null} +
+
+ ) +} diff --git a/src/server.ts b/src/server.ts index 6b751cd17..a802998f6 100644 --- a/src/server.ts +++ b/src/server.ts @@ -1,13 +1,14 @@ -import { - timeRequestWork, - withDocsRequestTimings, -} from './utils/request-timing.server' -import { finalizeDocsHtmlHeaders } from './utils/docs-html-headers.server' import './instrument.server.mjs' +export { StreamObject } from '@durable-streams/server-cloudflare' +export { WorkspaceSync } from './chat/server/workspace-sync-object' +export { Conversation } from './chat/server/conversation' +export { TanChatWorkflow } from './chat/server/workflow-driver' + import { wrapFetchWithSentry } from '@sentry/tanstackstart-react' import handler, { createServerEntry } from '@tanstack/react-start/server-entry' import { runWithDatabaseContext, runWithDatabaseRequest } from '~/db/client' +import { runScheduledTasks } from '~/server/scheduled.server' import { runWithHostRuntimeContext, runWithHostRuntimeEnv, @@ -25,6 +26,7 @@ import { redirectInsecureSiteRequest, } from '~/utils/http' import { isFrameEmbeddingAllowed } from '~/utils/frame-embedding' +import { redirectChatOrigin } from './chat/server/origin-redirect' const SECURITY_HEADERS = { 'X-Frame-Options': 'DENY', @@ -259,11 +261,9 @@ const server = createServerEntry( return applyHostingHeaders(markdownResponse, url) } - const response = await timeRequestWork('start_handler', () => - handler.fetch(request, { - responseLinkHeader: STATIC_RESPONSE_LINK_HEADERS, - }), - ) + const response = await handler.fetch(request, { + responseLinkHeader: STATIC_RESPONSE_LINK_HEADERS, + }) const hostedResponse = applyHostingHeaders(response, url) logRequestEnd(context, response.status) @@ -279,21 +279,13 @@ const server = createServerEntry( ) export default { - async fetch(request: Request, env: unknown, context: unknown) { + fetch(request: Request, env: unknown, context: unknown) { const secureSite = redirectInsecureSiteRequest(request) if (secureSite) return secureSite - if (new URL(request.url).hostname === 'chat.tanstack.com') { - const { redirectChatOrigin } = - await import('./chat/server/origin-redirect') - const canonicalChat = redirectChatOrigin(request) - if (canonicalChat) return canonicalChat - } + const canonicalChat = redirectChatOrigin(request) + if (canonicalChat) return canonicalChat return runWithHostRuntimeEnv(env, () => - runWithHostRuntimeContext(context, () => - withDocsRequestTimings(request, async () => - finalizeDocsHtmlHeaders(request, await server.fetch(request)), - ), - ), + runWithHostRuntimeContext(context, () => server.fetch(request)), ) }, scheduled( @@ -304,11 +296,9 @@ export default { context.waitUntil( runWithHostRuntimeEnv(env, () => runWithHostRuntimeContext(context, () => - runWithDatabaseContext(async () => { - const { runScheduledTasks } = - await import('~/server/scheduled.server') - return runScheduledTasks(controller.cron, controller.scheduledTime) - }), + runWithDatabaseContext(() => + runScheduledTasks(controller.cron, controller.scheduledTime), + ), ), ), ) diff --git a/src/server/og/og-http.server.ts b/src/server/og/og-http.server.ts deleted file mode 100644 index 8337b2919..000000000 --- a/src/server/og/og-http.server.ts +++ /dev/null @@ -1,56 +0,0 @@ -type GenerateOgImageResponse = - (typeof import('~/server/og/generate.server'))['generateOgImageResponse'] - -const CACHE_HEADERS = { - 'Cache-Control': 'public, max-age=3600', - 'Cloudflare-CDN-Cache-Control': - 'public, max-age=86400, stale-while-revalidate=604800', -} as const - -export const handlers = { - GET: async ({ - request, - params, - }: { - request: Request - params: { _splat: string } - }) => { - const rawParam = params._splat - const libraryId = rawParam.replace(/\.png$/, '') - - const url = new URL(request.url) - let result: Awaited> - try { - const { generateOgImageResponse } = - await import('~/server/og/generate.server') - result = await generateOgImageResponse( - { - libraryId, - requestUrl: request.url, - title: url.searchParams.get('title') ?? undefined, - description: url.searchParams.get('description') ?? undefined, - }, - { headers: CACHE_HEADERS }, - ) - } catch (error) { - console.error('Failed to construct OG response', error) - return new Response('Failed to generate OG image', { status: 500 }) - } - - if ('kind' in result) { - return new Response(`Unknown library: ${libraryId}`, { status: 404 }) - } - - // ImageResponse builds the Response synchronously and renders inside - // a ReadableStream. Await the ready promise so render errors surface - // as 500s instead of an empty 200 cached at the edge. - try { - await result.ready - } catch (error) { - console.error('Failed to generate OG image', error) - return new Response('Failed to generate OG image', { status: 500 }) - } - - return result - }, -} diff --git a/src/server/og/readme-http.server.ts b/src/server/og/readme-http.server.ts deleted file mode 100644 index c4f8df0b0..000000000 --- a/src/server/og/readme-http.server.ts +++ /dev/null @@ -1,92 +0,0 @@ -import { findLibrary } from '~/libraries' -import { OG_THEMES, isOgTheme } from '~/server/og/colors' -type GenerateReadmeHeaderResponse = - (typeof import('~/server/og/generate.server'))['generateReadmeHeaderResponse'] - -const CACHE_HEADERS = { - 'Cache-Control': 'public, max-age=3600', - 'Cloudflare-CDN-Cache-Control': - 'public, max-age=86400, stale-while-revalidate=604800', -} as const - -export const handlers = { - GET: async ({ - request, - params, - }: { - request: Request - params: { _splat: string } - }) => { - const libraryId = params._splat.replace(/\.png$/, '') - const library = findLibrary(libraryId) - if (!library) { - return new Response(`Unknown library: ${libraryId}`, { status: 404 }) - } - - const url = new URL(request.url) - - // Validated rather than ignored: a typo'd framework in a README should - // surface as a broken image, not as a banner naming the wrong package. - // An omitted param means "no framework"; a present-but-blank one - // (`?framework=`) is a malformed URL, not a request for the default. - const frameworkParam = url.searchParams.get('framework') ?? undefined - const framework = library.frameworks.find( - (value) => value === frameworkParam, - ) - if (frameworkParam !== undefined && framework === undefined) { - return new Response( - `Unknown framework "${frameworkParam}" for ${library.name}. Expected one of: ${library.frameworks.join(', ')}`, - { status: 400 }, - ) - } - - // Same contract as `framework`: supplied means it must be valid. - const themeParam = url.searchParams.get('theme') ?? undefined - if (themeParam !== undefined && !isOgTheme(themeParam)) { - return new Response( - `Unknown theme "${themeParam}". Expected one of: ${OG_THEMES.join(', ')}`, - { status: 400 }, - ) - } - - let result: Awaited> - try { - const { generateReadmeHeaderResponse } = - await import('~/server/og/generate.server') - result = await generateReadmeHeaderResponse( - { - libraryId, - requestUrl: request.url, - framework, - title: url.searchParams.get('title') ?? undefined, - subtitle: url.searchParams.get('subtitle') ?? undefined, - theme: themeParam, - }, - { headers: CACHE_HEADERS }, - ) - } catch (error) { - console.error('Failed to construct README header response', error) - return new Response('Failed to generate README header', { - status: 500, - }) - } - - if ('kind' in result) { - return new Response(`Unknown library: ${libraryId}`, { status: 404 }) - } - - // ImageResponse builds the Response synchronously and renders inside - // a ReadableStream. Await the ready promise so render errors surface - // as 500s instead of an empty 200 cached at the edge. - try { - await result.ready - } catch (error) { - console.error('Failed to generate README header', error) - return new Response('Failed to generate README header', { - status: 500, - }) - } - - return result - }, -} diff --git a/src/server/runtime/http-route.server.ts b/src/server/runtime/http-route.server.ts deleted file mode 100644 index 7144aa93f..000000000 --- a/src/server/runtime/http-route.server.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { z } from 'zod' - -// URLPattern is native in workerd, including local development and preview. -declare const URLPattern: typeof import('@cloudflare/workers-types').URLPattern - -type HttpContext = { request: Request; params: TParams } -type HttpHandler = ( - context: HttpContext, -) => Response | Promise - -export function defineHttpRoute>( - path: string, - paramsSchema: z.ZodType, - handlers: Record>, -) { - const pattern = new URLPattern({ - pathname: path - .split('/') - .map((segment) => - segment === '$' - ? ':_splat*' - : segment.startsWith('$') - ? `:${segment.slice(1)}` - : segment, - ) - .join('/'), - }) - return { - path, - match(request: Request) { - const url = new URL(request.url) - const match = pattern.exec({ - pathname: url.pathname.replace(/\/+$/, '') || '/', - }) - if (!match) return - const params: Record = {} - for (const [key, value] of Object.entries(match.pathname.groups)) { - params[key] = decodeURIComponent(value ?? '') - } - const method = request.method === 'HEAD' ? 'GET' : request.method - const handler = handlers[method] - const context = { request, params: paramsSchema.parse(params) } - return { - handler: handler ? () => handler(context) : undefined, - context, - allow: Object.keys(handlers).join(', '), - } - }, - } -} diff --git a/src/server/runtime/worker-service.server.ts b/src/server/runtime/worker-service.server.ts deleted file mode 100644 index a917b76e5..000000000 --- a/src/server/runtime/worker-service.server.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { getHostRuntimeEnv } from './host.server' - -type WorkerService = { - fetch(request: Request): Promise -} - -function isWorkerService(value: unknown): value is WorkerService { - return ( - typeof value === 'object' && - value !== null && - 'fetch' in value && - typeof value.fetch === 'function' - ) -} - -export async function forwardWorkerRequest( - name: 'OG' | 'CHAT' | 'STARTER', - request: Request, -) { - const env = await getHostRuntimeEnv() - const service = env?.[name] - if (!isWorkerService(service)) - throw new Error(`${name} Worker binding is missing`) - return service.fetch(request) -} diff --git a/src/server/scheduled.server.ts b/src/server/scheduled.server.ts index 6d7526154..960a04c8e 100644 --- a/src/server/scheduled.server.ts +++ b/src/server/scheduled.server.ts @@ -1,3 +1,4 @@ +import { recoverChatWorkspaceSync } from '~/chat/server/scheduled.server' import { materializeWorkflowSchedules } from '@tanstack/workflow-runtime' import { pruneStaleCacheRows } from '~/utils/github-content-cache.server' import { refreshHomepageNpmStatsSummary } from '~/utils/homepage-npm-stats.server' @@ -33,7 +34,10 @@ export async function runScheduledTasks(cron: string, scheduledTime: number) { ]) return case WORKFLOW_SWEEP_CRON: - await runWorkflowSweep(cron, scheduledTime) + await Promise.all([ + recoverChatWorkspaceSync(), + runWorkflowSweep(cron, scheduledTime), + ]) return default: console.warn(`[scheduled] No task registered for cron: ${cron}`) diff --git a/src/types/durable-streams.d.ts b/src/types/durable-streams.d.ts deleted file mode 100644 index 5793f4874..000000000 --- a/src/types/durable-streams.d.ts +++ /dev/null @@ -1,10 +0,0 @@ -import type { Request, Response } from '@cloudflare/workers-types' -import '@durable-streams/server-cloudflare' - -declare module '@durable-streams/server-cloudflare' { - // The package emits DOM Request types, but this entrypoint runs in workerd - // and accepts the platform's Request, including its Cloudflare properties. - interface StreamObject { - fetch(request: Request): Promise - } -} diff --git a/src/utils/docs-cache-headers.ts b/src/utils/docs-cache-headers.ts index 22b50a99e..e684afdca 100644 --- a/src/utils/docs-cache-headers.ts +++ b/src/utils/docs-cache-headers.ts @@ -21,14 +21,7 @@ export function getDocsCacheHeaders({ version === library.latestVersion || version === library.latestBranch) const cacheTags = library - ? [ - 'docs:all', - `docs:${library.id}`, - `docs:${library.id}:branch:${branch}`, - 'docs-config:all', - `docs-config:${library.repo}`, - `docs-config:${library.repo}:${branch}`, - ] + ? ['docs:all', `docs:${library.id}`, `docs:${library.id}:branch:${branch}`] : ['docs:all'] return { diff --git a/src/utils/docs-html-headers.server.ts b/src/utils/docs-html-headers.server.ts deleted file mode 100644 index 60947f351..000000000 --- a/src/utils/docs-html-headers.server.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { getDocsCacheHeaders } from './docs-cache-headers' - -// Called after loaders finish, so data-fetching functions cannot overwrite -// the page's cache policy or its document and sidebar invalidation tags. -export function finalizeDocsHtmlHeaders(request: Request, response: Response) { - if (!response.headers.has('X-Docs-Html')) return response - const headers = new Headers(response.headers) - headers.delete('X-Docs-Html') - if ( - response.status === 200 && - response.headers.get('X-Docs-Html') === '1' && - !headers.has('set-cookie') && - !/no-store|private/i.test(headers.get('cache-control') ?? '') - ) { - const [, libraryId, version] = new URL(request.url).pathname.split('/') - for (const [key, value] of Object.entries( - getDocsCacheHeaders({ libraryId, version }), - )) { - headers.set(key, value) - } - } else { - headers.set('Cache-Control', 'private, no-store') - headers.set('Cloudflare-CDN-Cache-Control', 'no-store') - } - // Keep complete HTML responses out of every shared cache during profiling. - headers.set('Cache-Control', 'private, no-store') - headers.set('Cloudflare-CDN-Cache-Control', 'no-store') - headers.set( - 'Vary', - [headers.get('Vary'), 'Cookie', 'Authorization'].filter(Boolean).join(', '), - ) - return new Response(response.body, { - status: response.status, - statusText: response.statusText, - headers, - }) -} diff --git a/src/utils/docs.functions.ts b/src/utils/docs.functions.ts index 25e88633e..b0f40250e 100644 --- a/src/utils/docs.functions.ts +++ b/src/utils/docs.functions.ts @@ -449,7 +449,6 @@ export const fetchDocs = createServerFn({ method: 'GET' }) return { content: frontMatter.content, - isFallback: result.isFallback, title: frontMatter.data?.title ?? 'Content temporarily unavailable', description, keywords, diff --git a/src/utils/docs.ts b/src/utils/docs.ts index 9c20f4921..f69b5c586 100644 --- a/src/utils/docs.ts +++ b/src/utils/docs.ts @@ -1,6 +1,4 @@ import { isNotFound, notFound } from '@tanstack/react-router' -import type { QueryClient } from '@tanstack/react-query' -import { docsPathManifestQueryOptions } from '~/queries/docsManifest' import { fetchDocs, fetchDocsManifest, @@ -84,7 +82,6 @@ export async function getDocsManifest(opts: { } export async function resolveDocsRoutePath(opts: { - queryClient?: QueryClient branch: string defaultDocs: string docsPath: string @@ -98,14 +95,13 @@ export async function resolveDocsRoutePath(opts: { return defaultDocsResolution } - const request = { - repo: opts.repo, - branch: opts.branch, - docsRoot: opts.docsRoot, - } - const manifest = opts.queryClient - ? await opts.queryClient.fetchQuery(docsPathManifestQueryOptions(request)) - : await fetchDocsPathManifest({ data: request }) + const manifest = await fetchDocsPathManifest({ + data: { + repo: opts.repo, + branch: opts.branch, + docsRoot: opts.docsRoot, + }, + }) if (manifest.paths.length === 0) { return { type: 'render', docsPath: opts.docsPath } @@ -179,7 +175,6 @@ export type LoadDocsRouteResult = } export async function loadDocsRoute(opts: { - queryClient?: QueryClient branch: string defaultDocs: string docsPath: string @@ -237,7 +232,6 @@ export async function loadDocsRoute(opts: { */ async function findLatestDocsPath( opts: { - queryClient?: QueryClient branch: string docsRoot: string latestBranch?: string @@ -250,14 +244,13 @@ async function findLatestDocsPath( } try { - const request = { - repo: opts.repo, - branch: opts.latestBranch, - docsRoot: opts.docsRoot, - } - const manifest = opts.queryClient - ? await opts.queryClient.fetchQuery(docsPathManifestQueryOptions(request)) - : await fetchDocsPathManifest({ data: request }) + const manifest = await fetchDocsPathManifest({ + data: { + repo: opts.repo, + branch: opts.latestBranch, + docsRoot: opts.docsRoot, + }, + }) return docsManifestHasPath(manifest, docsPath) ? docsPath : null } catch { @@ -266,7 +259,6 @@ async function findLatestDocsPath( } async function resolveDocsRoutePathWithRedirects(opts: { - queryClient?: QueryClient branch: string defaultDocs: string docsPath: string diff --git a/src/utils/github-content-cache.server.ts b/src/utils/github-content-cache.server.ts index 051cf3912..7fc248527 100644 --- a/src/utils/github-content-cache.server.ts +++ b/src/utils/github-content-cache.server.ts @@ -1,4 +1,3 @@ -import { timeRequestWork } from './request-timing.server' import { getBlobStorage, getBlobStorageCache, @@ -562,9 +561,7 @@ async function readBlob( cache: BlobStorageCache | undefined, key: string, ) { - const cached = await timeRequestWork('content_edge_read', async () => - cache?.get(key), - ) + const cached = await cache?.get(key) const cachedBlob = cached ? getStoredBlob({ key, metadata: cached.metadata, text: cached.text }) : undefined @@ -573,15 +570,13 @@ async function readBlob( return cachedBlob } - const object = await timeRequestWork('content_r2_read', () => - storage.get(key), - ) + const object = await storage.get(key) if (!object) { return undefined } - const text = await timeRequestWork('content_r2_body', () => object.text()) + const text = await object.text() const stored = getStoredBlob({ key, metadata: object.metadata, @@ -593,12 +588,10 @@ async function readBlob( return undefined } - await timeRequestWork('content_edge_write', () => - writeBlobCache(cache, key, { - metadata: stored.metadata, - text: stored.text, - }), - ) + await writeBlobCache(cache, key, { + metadata: stored.metadata, + text: stored.text, + }) return stored } @@ -1294,52 +1287,34 @@ async function getCachedGitHubContent(opts: { } } - const refresh = () => - withPendingRefresh(opts.cacheKey, async () => { - const latestRow = await readRow() - const latestValue = opts.readStoredValue(latestRow) - const latestForciblyStale = - !!latestRow && isForciblyStale(latestRow.staleAt) + return withPendingRefresh(opts.cacheKey, async () => { + const latestRow = await readRow() + const latestValue = opts.readStoredValue(latestRow) + const latestForciblyStale = + !!latestRow && isForciblyStale(latestRow.staleAt) - if ( - canUseStoredGithubContentValue(opts.contentKind, latestValue) && - latestRow && - !latestForciblyStale && - isFresh(latestRow.staleAt) - ) { - return latestValue - } - - try { - const value = await timeRequestWork('content_origin', opts.origin) - await timeRequestWork('content_persist', () => persist(value)) - return value - } catch (error) { - if (latestValue !== undefined && latestValue !== null) { - console.warn(`[GitHub Cache] Serving stale value ${opts.cacheKey}`) - return latestValue - } - - throw error - } - }) - // Explicit invalidations and negative entries still refresh before returning. - if (storedValue !== undefined && storedValue !== null && !forciblyStale) { if ( - scheduleHostRuntimeTask(() => - refresh().catch((error) => { - console.warn( - `[GitHub Cache] Background content refresh failed ${opts.cacheKey}`, - error, - ) - }), - ) + canUseStoredGithubContentValue(opts.contentKind, latestValue) && + latestRow && + !latestForciblyStale && + isFresh(latestRow.staleAt) ) { - return storedValue + return latestValue } - } - return refresh() + try { + const value = await opts.origin() + await persist(value) + return value + } catch (error) { + if (latestValue !== undefined && latestValue !== null) { + console.warn(`[GitHub Cache] Serving stale value ${opts.cacheKey}`) + return latestValue + } + + throw error + } + }) } async function upsertDocsArtifact(opts: { @@ -1449,7 +1424,7 @@ export async function getCachedDocsArtifact(opts: { } try { - const payload = await timeRequestWork('artifact_build', opts.build) + const payload = await opts.build() await upsertDocsArtifact({ ...opts, payload }) return payload } catch (error) { diff --git a/src/utils/request-timing.server.ts b/src/utils/request-timing.server.ts deleted file mode 100644 index c44ebf56a..000000000 --- a/src/utils/request-timing.server.ts +++ /dev/null @@ -1,136 +0,0 @@ -import { AsyncLocalStorage } from 'node:async_hooks' -import * as Sentry from '@sentry/tanstackstart-react' - -// On deployed Workers this clock advances only on I/O. These spans locate -// waits; platform CPU/wall metrics are required to measure CPU-only work. -// https://developers.cloudflare.com/workers/runtime-apis/performance/ -type Timing = { name: string; startMs: number; durationMs: number } -type Timings = { - startedAt: number - entries: Array - databaseUsed: boolean -} -const storage = new AsyncLocalStorage() -let instanceId: string | undefined -let docsRequests = 0 - -export function markRequestDatabaseUse() { - const timings = storage.getStore() - if (timings) timings.databaseUsed = true -} - -export async function timeRequestWork( - name: string, - work: () => T | Promise, -): Promise { - const timings = storage.getStore() - if (!timings) return work() - const startedAt = performance.now() - try { - return await Sentry.startSpan({ name, op: 'docs.server' }, work) - } finally { - timings.entries.push({ - name, - startMs: startedAt - timings.startedAt, - durationMs: performance.now() - startedAt, - }) - } -} - -export async function withDocsRequestTimings( - request: Request, - work: () => Promise, -) { - if (!/^\/[^/]+\/[^/]+\/docs\//.test(new URL(request.url).pathname)) - return work() - instanceId ??= crypto.randomUUID() - const workerInstance = instanceId - const docsRequest = ++docsRequests - const timings: Timings = { - startedAt: performance.now(), - entries: [], - databaseUsed: false, - } - return storage.run(timings, async () => { - const response = await work() - const durationMs = performance.now() - timings.startedAt - const totals = new Map() - for (const entry of timings.entries) - totals.set(entry.name, (totals.get(entry.name) ?? 0) + entry.durationMs) - const headers = new Headers(response.headers) - headers.set( - 'Server-Timing', - [ - `app_headers;dur=${durationMs.toFixed(1)}`, - ...Array.from( - totals, - ([name, duration]) => `${name};dur=${duration.toFixed(1)}`, - ), - `db_used;desc="${timings.databaseUsed}"`, - `docs_request;desc="${docsRequest}"`, - ].join(', '), - ) - console.log( - JSON.stringify({ - logType: 'docs_timing', - workerInstance, - docsRequest, - phase: 'headers_ready', - pathname: new URL(request.url).pathname, - ray: request.headers.get('cf-ray'), - status: response.status, - headersReadyMs: durationMs, - databaseUsed: timings.databaseUsed, - phases: timings.entries, - }), - ) - // This measures work through response creation, not streamed body completion. - const reader = response.body?.getReader() - let firstByte = true - const logBodyPhase = (phase: string) => - console.log( - JSON.stringify({ - logType: 'docs_timing', - workerInstance, - docsRequest, - phase, - pathname: new URL(request.url).pathname, - ray: request.headers.get('cf-ray'), - elapsedMs: performance.now() - timings.startedAt, - databaseUsed: timings.databaseUsed, - phases: timings.entries, - }), - ) - const body = reader - ? new ReadableStream({ - async pull(controller) { - try { - const result = await reader.read() - if (result.done) { - logBodyPhase('body_complete') - controller.close() - } else { - if (firstByte) { - firstByte = false - logBodyPhase('first_body_byte') - } - controller.enqueue(result.value) - } - } catch (error) { - logBodyPhase('body_error') - controller.error(error) - } - }, - async cancel(reason) { - logBodyPhase('body_cancelled') - await reader.cancel(reason) - }, - }) - : null - return new Response(body, { - status: response.status, - statusText: response.statusText, - headers, - }) - }) -} diff --git a/src/workers/chat.ts b/src/workers/chat.ts deleted file mode 100644 index bc4796709..000000000 --- a/src/workers/chat.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { chatHttpRoutes } from '~/chat/server/http/routes' -import { recoverChatWorkspaceSync } from '~/chat/server/scheduled.server' -import { runWithDatabaseContext, runWithDatabaseRequest } from '~/db/client' -import { - runWithHostRuntimeContext, - runWithHostRuntimeEnv, -} from '~/server/runtime/host.server' - -export { - StreamObject, - WorkspaceSync, - Conversation, - TanChatWorkflow, -} from '~/chat/server/entries' - -export default { - fetch(request: Request, env: unknown, context: unknown) { - return runWithHostRuntimeEnv(env, () => - runWithHostRuntimeContext(context, () => - runWithDatabaseRequest(async () => { - for (const route of chatHttpRoutes) { - const match = route.match(request) - if (!match) continue - if (!match.handler) - return new Response('Method not allowed', { - status: 405, - headers: { Allow: match.allow }, - }) - return match.handler() - } - return new Response('Not found', { status: 404 }) - }), - ), - ) - }, - scheduled( - _controller: unknown, - env: unknown, - context: { waitUntil(promise: Promise): void }, - ) { - context.waitUntil( - runWithHostRuntimeEnv(env, () => - runWithHostRuntimeContext(context, () => - runWithDatabaseContext(() => recoverChatWorkspaceSync()), - ), - ), - ) - }, -} diff --git a/src/workers/og.ts b/src/workers/og.ts deleted file mode 100644 index 10c6e37dd..000000000 --- a/src/workers/og.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { handlers as og } from '~/server/og/og-http.server' -import { handlers as readme } from '~/server/og/readme-http.server' -import { runWithHostRuntimeEnv } from '~/server/runtime/host.server' - -export default { - fetch(request: Request, env: unknown) { - return runWithHostRuntimeEnv(env, () => { - const match = /^\/api\/(og|readme)\/(.+)\.png$/.exec( - new URL(request.url).pathname, - ) - if (!match) return new Response('Not found', { status: 404 }) - if (request.method !== 'GET' && request.method !== 'HEAD') { - return new Response('Method not allowed', { - status: 405, - headers: { Allow: 'GET, HEAD' }, - }) - } - const handler = match[1] === 'og' ? og.GET : readme.GET - return handler({ - request, - params: { _splat: decodeURIComponent(match[2]) }, - }) - }) - }, -} diff --git a/src/workers/starter.ts b/src/workers/starter.ts deleted file mode 100644 index 9ac0be75b..000000000 --- a/src/workers/starter.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { starterHttpRoutes } from '~/application-starter/api/http/routes' -import { runWithDatabaseRequest } from '~/db/client' -import { - runWithHostRuntimeContext, - runWithHostRuntimeEnv, -} from '~/server/runtime/host.server' - -export default { - fetch(request: Request, env: unknown, context: unknown) { - return runWithHostRuntimeEnv(env, () => - runWithHostRuntimeContext(context, () => - runWithDatabaseRequest(async () => { - for (const route of starterHttpRoutes) { - const match = route.match(request) - if (!match) continue - if (!match.handler) - return new Response('Method not allowed', { - status: 405, - headers: { Allow: match.allow }, - }) - return match.handler() - } - return new Response('Not found', { status: 404 }) - }), - ), - ) - }, -} diff --git a/tests/builder-openrouter.test.ts b/tests/builder-openrouter.test.ts index a6df14c3e..c0939359f 100644 --- a/tests/builder-openrouter.test.ts +++ b/tests/builder-openrouter.test.ts @@ -9,7 +9,7 @@ import { startBuilderOpenRouterLogin, isOpenRouterCallback, } from '../src/utils/builder-openrouter-login.client' -import { openRouterCallbackResponse } from '../src/chat/server/routes/openrouter/callback' +import { openRouterCallbackResponse } from '../src/routes/api/chat/openrouter/callback' import { createBuilderAiByokConnection } from '../src/utils/builder-ai-api-key-storage.client' import { streamBuilderAiResponse } from '../src/utils/builder-ai' import { createExampleWorkspace } from '../src/utils/example-workspace' diff --git a/tests/builder-project-quarantine.test.ts b/tests/builder-project-quarantine.test.ts index 3b0d15c56..867ddb939 100644 --- a/tests/builder-project-quarantine.test.ts +++ b/tests/builder-project-quarantine.test.ts @@ -3,7 +3,7 @@ import test from 'node:test' import { BuilderProjectQuarantineCleanupError, quarantineBuilderProjectSnapshotForAdmin, -} from '../src/chat/server/routes/project-snapshots.$hash.quarantine' +} from '../src/routes/api/chat/project-snapshots.$hash.quarantine' const hash = 'a'.repeat(64) const actorId = '00000000-0000-4000-8000-000000000001' diff --git a/tests/chat-entrypoints.test.ts b/tests/chat-entrypoints.test.ts deleted file mode 100644 index e25b7bae4..000000000 --- a/tests/chat-entrypoints.test.ts +++ /dev/null @@ -1,51 +0,0 @@ -import assert from 'node:assert/strict' -import { readFileSync } from 'node:fs' -import test from 'node:test' -import ts from 'typescript' - -function publicMethods(path: string, name: string) { - const source = ts.createSourceFile( - path, - readFileSync(path, 'utf8'), - ts.ScriptTarget.Latest, - true, - ) - const declaration = source.statements.find( - (node): node is ts.ClassDeclaration => - ts.isClassDeclaration(node) && node.name?.text === name, - ) - assert.ok(declaration, `${name} must exist`) - return declaration.members - .filter((node): node is ts.MethodDeclaration => - ts.isMethodDeclaration(node), - ) - .filter( - (node) => - !node.modifiers?.some( - (modifier) => - modifier.kind === ts.SyntaxKind.PrivateKeyword || - modifier.kind === ts.SyntaxKind.ProtectedKeyword || - modifier.kind === ts.SyntaxKind.StaticKeyword, - ), - ) - .map((node) => node.name.getText(source)) - .sort() -} - -// A missing method here would silently remove a deployed RPC endpoint. -for (const [name, implementation] of [ - ['Conversation', 'src/chat/server/conversation.ts'], - ['WorkspaceSync', 'src/chat/server/workspace-sync-object.ts'], - [ - 'StreamObject', - 'node_modules/@durable-streams/server-cloudflare/dist/index.d.ts', - ], - ['TanChatWorkflow', 'src/chat/server/workflow-driver.ts'], -]) { - test(`lazy ${name} preserves every public RPC and lifecycle method`, () => { - assert.deepEqual( - publicMethods('src/chat/server/entries.ts', name), - publicMethods(implementation, name), - ) - }) -} diff --git a/tests/docs-html-headers.test.ts b/tests/docs-html-headers.test.ts deleted file mode 100644 index 85cb5ebe9..000000000 --- a/tests/docs-html-headers.test.ts +++ /dev/null @@ -1,48 +0,0 @@ -import assert from 'node:assert/strict' -import { test } from 'node:test' -import { finalizeDocsHtmlHeaders } from '../src/utils/docs-html-headers.server' - -const url = 'https://tanstack.com/router/latest/docs/routing/routing-concepts' -test('HTML headers override loader headers without enabling page caching', () => { - const response = finalizeDocsHtmlHeaders( - new Request(url, { headers: { Accept: 'text/html' } }), - new Response('docs', { - headers: { - 'X-Docs-Html': '1', - 'Cache-Control': 'public, max-age=0', - 'Cache-Tag': 'docs-config:all', - }, - }), - ) - assert.equal(response.headers.has('X-Docs-Html'), false) - assert.equal(response.headers.get('Cache-Control'), 'private, no-store') - assert.equal(response.headers.get('Cloudflare-CDN-Cache-Control'), 'no-store') - assert.match( - response.headers.get('Cache-Tag') ?? '', - /docs:router:branch:main/, - ) - assert.match( - response.headers.get('Cache-Tag') ?? '', - /docs-config:tanstack\/router:main/, - ) -}) -test('fallback and authenticated HTML stay uncacheable even with conflicting loader headers', () => { - for (const marker of ['1', 'no-store']) { - const response = finalizeDocsHtmlHeaders( - new Request(url, { - headers: { Cookie: 'session_token=x', Accept: 'text/html' }, - }), - new Response('docs', { - headers: { - 'X-Docs-Html': marker, - 'Cache-Control': 'public, max-age=3600', - }, - }), - ) - assert.equal(response.headers.get('Cache-Control'), 'private, no-store') - assert.equal( - response.headers.get('Cloudflare-CDN-Cache-Control'), - 'no-store', - ) - } -}) diff --git a/tests/docs-manifest-cache.test.ts b/tests/docs-manifest-cache.test.ts deleted file mode 100644 index 503c6f89a..000000000 --- a/tests/docs-manifest-cache.test.ts +++ /dev/null @@ -1,92 +0,0 @@ -import assert from 'node:assert/strict' -import test from 'node:test' -import { dehydrate, hydrate, QueryClient } from '@tanstack/react-query' -import { docsPathManifestQueryOptions } from '../src/queries/docsManifest' -import { resolveDocsRoutePath } from '../src/utils/docs' - -const request = { - repo: 'tanstack/router', - branch: 'main', - docsRoot: 'docs/router', -} - -test('docs navigation reuses the manifest hydrated by the server', async () => { - const serverClient = new QueryClient() - serverClient.setQueryData(docsPathManifestQueryOptions(request).queryKey, { - paths: ['routing/routing-concepts', 'routing/route-trees'], - redirects: {}, - }) - const browserClient = new QueryClient() - hydrate(browserClient, dehydrate(serverClient)) - - try { - // These resolve entirely from hydrated data, without a server request. - for (const docsPath of [ - 'routing/routing-concepts', - 'routing/route-trees', - ]) { - assert.deepEqual( - await resolveDocsRoutePath({ - ...request, - queryClient: browserClient, - defaultDocs: 'overview', - frameworks: ['react', 'solid'], - docsPath, - }), - { type: 'render', docsPath }, - ) - } - - assert.deepEqual( - await resolveDocsRoutePath({ - ...request, - queryClient: browserClient, - defaultDocs: 'overview', - frameworks: ['react', 'solid'], - docsPath: 'framework/react/routing/route-trees', - }), - { type: 'redirect', docsPath: 'routing/route-trees' }, - ) - } finally { - serverClient.clear() - browserClient.clear() - } -}) - -test('cached manifests stay separate for each repository, branch, and docs root', async () => { - const queryClient = new QueryClient() - const requests = [ - request, - { ...request, repo: 'tanstack/query' }, - { ...request, branch: 'v0' }, - { ...request, docsRoot: 'docs/start' }, - ] - - try { - for (const [index, data] of requests.entries()) { - queryClient.setQueryData(docsPathManifestQueryOptions(data).queryKey, { - paths: [`page-${index}`], - redirects: {}, - }) - } - - for (const [index, data] of requests.entries()) { - const opts = { - ...data, - queryClient, - defaultDocs: 'overview', - frameworks: ['react'], - } - assert.deepEqual( - await resolveDocsRoutePath({ ...opts, docsPath: `page-${index}` }), - { type: 'render', docsPath: `page-${index}` }, - ) - assert.deepEqual( - await resolveDocsRoutePath({ ...opts, docsPath: 'missing' }), - { type: 'not-found' }, - ) - } - } finally { - queryClient.clear() - } -}) diff --git a/tests/github-content-cache.test.ts b/tests/github-content-cache.test.ts index a5c6590f9..f2a85b455 100644 --- a/tests/github-content-cache.test.ts +++ b/tests/github-content-cache.test.ts @@ -425,63 +425,6 @@ async function testStaleArtifactRefreshesInWaitUntil() { assert.deepEqual(freshResult, { paths: ['new'] }) } -async function testExpiredContentRefreshesWithoutBlocking() { - resetGitHubContentCacheForTest() - const mockR2 = createMockR2Bucket() - const pending: Array> = [] - let finish: ((value: string) => void) | undefined - const refresh = new Promise((resolve) => { - finish = resolve - }) - await runWithHostRuntimeEnv( - { GITHUB_CONTENT_CACHE: mockR2.bucket }, - async () => { - const opts = { repo, gitRef, path: 'docs/expired.md' } - await getCachedGitHubTextFile({ ...opts, origin: async () => 'old' }) - for (const object of mockR2.objects.values()) { - if (object.customMetadata) - object.customMetadata.staleAt = new Date( - Date.now() - 1000, - ).toISOString() - } - const value = await runWithHostRuntimeContext( - { - waitUntil: (task: Promise) => { - pending.push(task) - }, - }, - () => getCachedGitHubTextFile({ ...opts, origin: () => refresh }), - ) - assert.equal(value, 'old') - assert.equal(pending.length, 1) - finish?.('new') - await Promise.all(pending) - assert.equal( - await getCachedGitHubTextFile({ - ...opts, - origin: async () => { - throw new Error('should be fresh') - }, - }), - 'new', - ) - await markGitHubContentStale({ repo, gitRef }) - const forced = await runWithHostRuntimeContext( - { - waitUntil: () => { - assert.fail('forced invalidation must block') - }, - }, - () => - getCachedGitHubTextFile({ ...opts, origin: async () => 'forced' }), - ) - assert.equal(forced, 'forced') - }, - ) -} - -await testExpiredContentRefreshesWithoutBlocking() - await testMissStoresContent() await testFreshHitSkipsOrigin() await testWorkerEnvUsesBlobStorage() diff --git a/tests/request-timing.test.ts b/tests/request-timing.test.ts deleted file mode 100644 index 2bb1b7f8d..000000000 --- a/tests/request-timing.test.ts +++ /dev/null @@ -1,51 +0,0 @@ -import assert from 'node:assert/strict' -import { test } from 'node:test' -import { - markRequestDatabaseUse, - timeRequestWork, - withDocsRequestTimings, -} from '../src/utils/request-timing.server' - -const request = new Request('https://tanstack.com/router/latest/docs/overview') -test('timings are request-local and preserve streamed responses', async () => { - const [used, unused] = await Promise.all([ - withDocsRequestTimings(request, async () => { - await timeRequestWork('content_r2_read', async () => { - markRequestDatabaseUse() - }) - return new Response('first', { status: 201 }) - }), - withDocsRequestTimings(request, async () => new Response('second')), - ]) - assert.match(used.headers.get('Server-Timing') ?? '', /content_r2_read;dur=/) - assert.match(used.headers.get('Server-Timing') ?? '', /db_used;desc="true"/) - assert.match( - unused.headers.get('Server-Timing') ?? '', - /db_used;desc="false"/, - ) - assert.equal(used.status, 201) - assert.equal(await used.text(), 'first') - assert.equal(await unused.text(), 'second') -}) -test('failed work is timed without swallowing the error', async () => { - const response = await withDocsRequestTimings(request, async () => { - await assert.rejects( - timeRequestWork('content_origin', async () => { - throw new Error('origin failed') - }), - /origin failed/, - ) - return new Response('fallback') - }) - assert.match( - response.headers.get('Server-Timing') ?? '', - /content_origin;dur=/, - ) -}) -test('non-docs requests have no profiling headers', async () => { - const response = await withDocsRequestTimings( - new Request('https://tanstack.com/account'), - async () => new Response('account'), - ) - assert.equal(response.headers.has('Server-Timing'), false) -}) diff --git a/tests/worker-boundaries.test.ts b/tests/worker-boundaries.test.ts deleted file mode 100644 index 20c2a14e6..000000000 --- a/tests/worker-boundaries.test.ts +++ /dev/null @@ -1,172 +0,0 @@ -import { z } from 'zod' -import assert from 'node:assert/strict' -import { readFileSync, readdirSync } from 'node:fs' -import path from 'node:path' -import test from 'node:test' -import ts from 'typescript' -import { defineHttpRoute } from '../src/server/runtime/http-route.server' -import { chatHttpRoutes } from '../src/chat/server/http/routes' -import { starterHttpRoutes } from '../src/application-starter/api/http/routes' -import { runWithHostRuntimeEnv } from '../src/server/runtime/host.server' -import { forwardWorkerRequest } from '../src/server/runtime/worker-service.server' - -function routeFiles(directory: string): string[] { - return readdirSync(directory, { withFileTypes: true }) - .flatMap((entry) => - entry.isDirectory() - ? routeFiles(path.join(directory, entry.name)) - : [path.join(directory, entry.name)], - ) - .filter((file) => file.endsWith('.ts')) -} - -for (const group of [ - { - name: 'chat', - directories: ['src/routes/api/chat', 'src/routes/auth/mcp'], - routes: chatHttpRoutes, - }, - { - name: 'starter', - directories: ['src/routes/api/application-starter'], - routes: starterHttpRoutes, - }, -]) { - test(`every public ${group.name} route has the same methods in its Worker`, () => { - const files = group.directories.flatMap(routeFiles) - const routes = group.routes - assert.equal(routes.length, files.length) - for (const file of files) { - const source = ts.createSourceFile( - file, - readFileSync(file, 'utf8'), - ts.ScriptTarget.Latest, - true, - ) - let routePath = '' - const methods: string[] = [] - function visit(node: ts.Node) { - if ( - ts.isCallExpression(node) && - ts.isIdentifier(node.expression) && - node.expression.text === 'createFileRoute' - ) { - const argument = node.arguments[0] - assert.ok(ts.isStringLiteral(argument)) - routePath = argument.text - } - if ( - ts.isPropertyAssignment(node) && - node.name.getText(source) === 'handlers' - ) { - assert.ok(ts.isObjectLiteralExpression(node.initializer)) - methods.push( - ...node.initializer.properties.map( - (property) => property.name?.getText(source) ?? '', - ), - ) - } - ts.forEachChild(node, visit) - } - visit(source) - const route = routes.find((route) => route.path === routePath) - assert.ok(route, routePath) - const url = - 'https://tanstack.com' + - routePath.replace(/\$([^/]*)/g, (_, name) => - name ? 'example' : 'account/example', - ) - for (const method of methods) { - const match = route.match(new Request(url, { method })) - assert.ok(match?.handler, `${method} ${routePath}`) - } - } - }) -} - -test('specific chat routes win over parameters and the MCP splat', () => { - for (const pathname of [ - '/api/chat/mcp/contract', - '/api/chat/bots/bulk', - '/api/chat/bots/move', - ]) { - const request = new Request('https://tanstack.com' + pathname) - assert.equal( - chatHttpRoutes.find((route) => route.match(request))?.path, - pathname, - ) - } -}) - -test('Worker routing decodes parameters, accepts trailing slashes and preserves splats', () => { - const route = defineHttpRoute( - '/api/chat/projects/$id', - z.object({ id: z.string() }), - { - GET: () => new Response(), - }, - ) - const match = route.match( - new Request('https://tanstack.com/api/chat/projects/a%20b/'), - ) - assert.equal(match?.context.params.id, 'a b') - const splat = defineHttpRoute( - '/api/chat/mcp/$', - z.object({ _splat: z.string() }), - { - GET: () => new Response(), - }, - ) - assert.equal( - splat.match(new Request('https://tanstack.com/api/chat/mcp/account/one')) - ?.context.params._splat, - 'account/one', - ) - assert.ok( - route.match( - new Request('https://tanstack.com/api/chat/projects/one', { - method: 'HEAD', - }), - )?.handler, - ) - assert.equal( - route.match( - new Request('https://tanstack.com/api/chat/projects/one', { - method: 'DELETE', - }), - )?.handler, - undefined, - ) -}) - -test('service forwarding preserves the original request and streamed response', async () => { - const request = new Request('https://tanstack.com/api/chat/draft?scope=one', { - method: 'POST', - headers: { - Cookie: 'session=example', - Origin: 'https://tanstack.com', - 'Content-Type': 'application/json', - }, - body: '{"text":"hello"}', - }) - const response = new Response('event: update\ndata: hello\n\n', { - headers: { 'Content-Type': 'text/event-stream', 'Set-Cookie': 'example=1' }, - }) - const actual = await runWithHostRuntimeEnv( - { - CHAT: { - async fetch(forwarded: Request) { - assert.equal(forwarded, request) - assert.equal(forwarded.headers.get('Cookie'), 'session=example') - assert.equal(forwarded.headers.get('Origin'), 'https://tanstack.com') - assert.equal(await forwarded.text(), '{"text":"hello"}') - return response - }, - }, - }, - () => forwardWorkerRequest('CHAT', request), - ) - assert.equal(actual, response) - assert.equal(actual.headers.get('Set-Cookie'), 'example=1') - assert.match(await actual.text(), /event: update/) -}) diff --git a/tests/worker-deployment.test.ts b/tests/worker-deployment.test.ts deleted file mode 100644 index 25a94f914..000000000 --- a/tests/worker-deployment.test.ts +++ /dev/null @@ -1,156 +0,0 @@ -import assert from 'node:assert/strict' -import { - mkdtempSync, - mkdirSync, - writeFileSync, - readFileSync, - rmSync, - existsSync, -} from 'node:fs' -import { tmpdir } from 'node:os' -import path from 'node:path' -import { spawnSync } from 'node:child_process' -import test from 'node:test' - -function deploymentFixture(owner: string, missingSecret = false) { - const directory = mkdtempSync(path.join(tmpdir(), 'worker-deployment-')) - const binaryDirectory = path.join(directory, 'bin') - mkdirSync(binaryDirectory) - const base = { name: 'site' } - const chat = { - name: 'chat', - secrets: { required: ['SESSION_SECRET'] }, - exports: { Conversation: { type: 'durable-object', storage: 'sqlite' } }, - durable_objects: { - bindings: [{ name: 'CONVERSATIONS', class_name: 'Conversation' }], - }, - workflows: [ - { - name: 'existing-workflow', - binding: 'WORKFLOW_RUNS', - class_name: 'ChatWorkflow', - }, - ], - triggers: { crons: ['* * * * *'] }, - } - for (const [name, config] of Object.entries({ - server: base, - chat, - og: { name: 'og' }, - starter: { name: 'starter', secrets: { required: ['SESSION_SECRET'] } }, - })) { - mkdirSync(path.join(directory, 'dist', name), { recursive: true }) - writeFileSync( - path.join(directory, 'dist', name, 'wrangler.json'), - JSON.stringify(config), - ) - } - writeFileSync( - path.join(binaryDirectory, 'pnpm'), - `#!/usr/bin/env node -const fs = require('node:fs') -const args = process.argv.slice(2) -if (args.includes('secret')) console.log(JSON.stringify(${missingSecret ? '[]' : "[{name:'SESSION_SECRET'}]"})) -else if (args.includes('workflows')) console.log(JSON.stringify([{name:'existing-workflow',script_name:${JSON.stringify(owner)}}])) -else if (args.includes('deploy')) { - const config = JSON.parse(fs.readFileSync(args[args.indexOf('--config') + 1], 'utf8')) - fs.appendFileSync('deployments.jsonl',JSON.stringify(config)+'\\n') - if (!args.includes('--keep-vars')) process.exit(1) -} -`, - { mode: 0o755 }, - ) - const result = spawnSync( - process.execPath, - [path.resolve('scripts/deploy-cloudflare.mjs')], - { - cwd: directory, - env: { - ...process.env, - PATH: binaryDirectory + path.delimiter + process.env.PATH, - }, - encoding: 'utf8', - }, - ) - const log = path.join(directory, 'deployments.jsonl') - const deployments = existsSync(log) - ? readFileSync(log, 'utf8') - .trim() - .split('\n') - .map((line) => JSON.parse(line)) - : [] - return { - directory, - result, - deployments, - cleanup: () => rmSync(directory, { recursive: true, force: true }), - } -} - -test('first deployment prepares existing namespaces before transfer and workflow reassignment', () => { - const fixture = deploymentFixture('site') - try { - assert.equal(fixture.result.status, 0, fixture.result.stderr) - const [, , preparing, committing, chat, site] = fixture.deployments - assert.equal(preparing.exports.Conversation.state, 'expecting-transfer') - assert.equal(preparing.exports.Conversation.transfer_from, 'site') - assert.equal(preparing.exports.Conversation.storage, 'sqlite') - assert.equal(preparing.durable_objects.bindings[0].script_name, 'site') - assert.equal(preparing.workflows[0].script_name, 'site') - assert.deepEqual(preparing.triggers.crons, []) - assert.deepEqual(committing.exports.Conversation, { - type: 'durable-object', - state: 'transferred', - transferred_to: 'chat', - }) - assert.deepEqual(chat.exports.Conversation, { - type: 'durable-object', - storage: 'sqlite', - }) - assert.equal(chat.durable_objects.bindings[0].script_name, undefined) - assert.equal(chat.workflows[0].name, 'existing-workflow') - assert.equal(chat.workflows[0].script_name, undefined) - assert.equal(site.exports, undefined) - assert.equal(fixture.deployments.length, 6) - assert.equal( - existsSync( - path.join( - fixture.directory, - 'dist/chat/wrangler.prepare-transfer.json', - ), - ), - false, - ) - } finally { - fixture.cleanup() - } -}) - -test('subsequent deployments keep the existing owner and deploy dependencies before the site', () => { - const fixture = deploymentFixture('chat') - try { - assert.equal(fixture.result.status, 0, fixture.result.stderr) - assert.deepEqual( - fixture.deployments.map((config) => config.name), - ['og', 'starter', 'chat', 'site'], - ) - assert.equal(fixture.deployments[2].exports.Conversation.state, undefined) - } finally { - fixture.cleanup() - } -}) - -test('missing credentials or an unexpected workflow owner stop deployment before any changes', () => { - for (const [owner, missingSecret] of [ - ['site', true], - ['unexpected', false], - ]) { - const fixture = deploymentFixture(String(owner), Boolean(missingSecret)) - try { - assert.notEqual(fixture.result.status, 0) - assert.deepEqual(fixture.deployments, []) - } finally { - fixture.cleanup() - } - } -}) diff --git a/vite.config.ts b/vite.config.ts index dddc53243..1a9a09c98 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -22,8 +22,6 @@ import { } from './src/utils/local-repo-path.server' import { startLocalMcpEgress } from './scripts/local-mcp-egress' import { localBuilderAi } from './scripts/local-builder-ai-vite' -import { chatIsolation } from './scripts/chat-isolation-vite' -import { workerIsolation } from './scripts/worker-isolation-vite' const isDev = process.env.NODE_ENV !== 'production' const shouldUseRedact = process.env.DISABLE_REDACT !== 'true' @@ -368,43 +366,6 @@ export default defineConfig(async ({ command, mode }) => { cloudflare({ viteEnvironment: { name: 'ssr' }, remoteBindings: useRemoteAi, - auxiliaryWorkers: [ - { - configPath: 'workers/og/wrangler.jsonc', - viteEnvironment: { name: 'og' }, - }, - { - configPath: 'workers/starter/wrangler.jsonc', - viteEnvironment: { name: 'starter' }, - config: (config) => { - if (command !== 'serve') return - config.hyperdrive = [] - config.vars = { ...config.vars, APP_MODE: 'development' } - }, - }, - { - configPath: 'workers/chat/wrangler.jsonc', - viteEnvironment: { name: 'chat' }, - config: (config) => { - if (command !== 'serve') return - config.hyperdrive = [] - if (!useRemoteAi) delete config.ai - config.vars = { - ...config.vars, - ...egress?.vars, - APP_MODE: 'development', - } - for (const name of [ - 'GUM_DEV_EXECUTION', - 'UNLIMITED_USAGE_EMAILS', - 'USAGE_RATES_JSON', - ]) { - const value = localEnv[name] - if (typeof value === 'string') config.vars[name] = value - } - }, - }, - ], config: (config) => { if (command !== 'serve') return config.hyperdrive = [] @@ -484,8 +445,6 @@ export default defineConfig(async ({ command, mode }) => { }, }), viteReact(), - chatIsolation(), - workerIsolation(), ...(shouldUseSentryPlugin ? [ diff --git a/workers/chat/wrangler.jsonc b/workers/chat/wrangler.jsonc deleted file mode 100644 index 0b8c9e236..000000000 --- a/workers/chat/wrangler.jsonc +++ /dev/null @@ -1,83 +0,0 @@ -{ - "account_id": "8da95258a9c70b54c3e2b374a0079106", - "compatibility_date": "2026-06-19", - "compatibility_flags": ["nodejs_compat"], - "observability": { - "enabled": true, - }, - "limits": { - "cpu_ms": 300000, - }, - "name": "tanstack-chat", - "main": "../../src/workers/chat.ts", - "workers_dev": false, - "preview_urls": false, - "vars": { - "APP_MODE": "production", - "MCP_EGRESS_MODE": "cloudflare-public", - "KODY_ORIGIN": "https://kody.codes", - "INCLUDED_MODEL": "@cf/moonshotai/kimi-k2.6", - }, - "durable_objects": { - "bindings": [ - { - "name": "STREAMS", - "class_name": "StreamObject", - }, - { - "name": "WORKSPACE_SYNC", - "class_name": "WorkspaceSync", - }, - { - "name": "CONVERSATIONS", - "class_name": "Conversation", - }, - ], - }, - "workflows": [ - { - "name": "tanstack-chat-workflows", - "binding": "WORKFLOW_RUNS", - "class_name": "TanChatWorkflow", - }, - ], - "triggers": { - "crons": ["* * * * *"], - }, - "ai": { - "binding": "AI", - }, - "r2_buckets": [ - { - "binding": "BUILDER_PROJECTS", - "bucket_name": "tanstack-notebook-projects", - }, - { - "binding": "FILES", - "bucket_name": "tanstack-notebook-projects", - }, - ], - "hyperdrive": [ - { - "binding": "HYPERDRIVE", - "id": "6ec1513b87bb47e9897e5502727b0388", - }, - ], - "secrets": { - "required": ["SESSION_SECRET", "ENCRYPTION_KEY", "DATABASE_URL"], - }, - "exports": { - "StreamObject": { - "type": "durable-object", - "storage": "sqlite", - }, - "WorkspaceSync": { - "type": "durable-object", - "storage": "sqlite", - }, - "Conversation": { - "type": "durable-object", - "storage": "sqlite", - }, - }, -} diff --git a/workers/og/wrangler.jsonc b/workers/og/wrangler.jsonc deleted file mode 100644 index c364e78b5..000000000 --- a/workers/og/wrangler.jsonc +++ /dev/null @@ -1,21 +0,0 @@ -{ - "account_id": "8da95258a9c70b54c3e2b374a0079106", - "compatibility_date": "2026-06-19", - "compatibility_flags": ["nodejs_compat"], - "observability": { - "enabled": true, - }, - "limits": { - "cpu_ms": 300000, - }, - "name": "tanstack-og", - "main": "../../src/workers/og.ts", - "workers_dev": false, - "preview_urls": false, - "services": [ - { - "binding": "ASSETS", - "service": "tanstack-com", - }, - ], -} diff --git a/workers/starter/wrangler.jsonc b/workers/starter/wrangler.jsonc deleted file mode 100644 index d7cf255ce..000000000 --- a/workers/starter/wrangler.jsonc +++ /dev/null @@ -1,32 +0,0 @@ -{ - "account_id": "8da95258a9c70b54c3e2b374a0079106", - "compatibility_date": "2026-06-19", - "compatibility_flags": ["nodejs_compat"], - "observability": { - "enabled": true, - }, - "limits": { - "cpu_ms": 300000, - }, - "workers_dev": false, - "preview_urls": false, - "hyperdrive": [ - { - "binding": "HYPERDRIVE", - "id": "6ec1513b87bb47e9897e5502727b0388", - }, - ], - "name": "tanstack-starter", - "main": "../../src/workers/starter.ts", - "vars": { - "APP_MODE": "production", - }, - "secrets": { - "required": [ - "SESSION_SECRET", - "ENCRYPTION_KEY", - "GITHUB_AUTH_TOKEN", - "DATABASE_URL", - ], - }, -} diff --git a/wrangler.jsonc b/wrangler.jsonc index 179cb13c1..e6072a2a5 100644 --- a/wrangler.jsonc +++ b/wrangler.jsonc @@ -20,15 +20,45 @@ "limits": { "cpu_ms": 300000, }, + "durable_objects": { + "bindings": [ + { + "name": "STREAMS", + "class_name": "StreamObject", + "script_name": "tanstack-chat", + }, + { + "name": "WORKSPACE_SYNC", + "class_name": "WorkspaceSync", + "script_name": "tanstack-chat", + }, + { + "name": "CONVERSATIONS", + "class_name": "Conversation", + "script_name": "tanstack-chat", + }, + ], + }, + "exports": { + "StreamObject": { "type": "durable-object", "storage": "sqlite" }, + "WorkspaceSync": { "type": "durable-object", "storage": "sqlite" }, + "Conversation": { "type": "durable-object", "storage": "sqlite" }, + }, + "workflows": [ + { + "name": "tanstack-chat-workflows", + "binding": "WORKFLOW_RUNS", + "class_name": "TanChatWorkflow", + "script_name": "tanstack-chat", + }, + ], "triggers": { "crons": ["* * * * *", "0 9 * * *", "0 */6 * * *"], }, "assets": { "binding": "ASSETS", }, - "ai": { - "binding": "AI", - }, + "ai": { "binding": "AI" }, "r2_buckets": [ { "binding": "GITHUB_CONTENT_CACHE", @@ -53,18 +83,4 @@ "id": "6ec1513b87bb47e9897e5502727b0388", }, ], - "services": [ - { - "binding": "OG", - "service": "tanstack-og", - }, - { - "binding": "CHAT", - "service": "tanstack-chat", - }, - { - "binding": "STARTER", - "service": "tanstack-starter", - }, - ], }