Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughLarge documentation overhaul: adds a centralized .agents docs file, many new docs pages and UI components under Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
✨ Finishing Touches🧪 Generate unit tests (beta)
|
There was a problem hiding this comment.
Actionable comments posted: 18
Note
Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
docs/1.docs/7.cache.md (1)
333-365:⚠️ Potential issue | 🟡 MinorClarify whether this section is showing the full key or the mount-relative key.
The pattern includes
${options.base}:..., but the invalidation example usesuseStorage('cache').removeItem('nitro/functions:...'). Those are different key forms, so readers copying both literally will remove the wrong entry.Suggested doc fix
-When using the `defineCachedFunction` or `defineCachedHandler` functions, the cache key is generated using the following pattern: +When using `useStorage(options.base)`, the mount-relative cache key is generated using the following pattern: ```ts -`${options.base}:${options.group}:${options.name}:${options.getKey(...args)}.json` +`${options.group}:${options.name}:${options.getKey(...args)}.json`</details> <details> <summary>🤖 Prompt for AI Agents</summary>Verify each finding against the current code and only fix it if needed.
In
@docs/1.docs/7.cache.mdaround lines 333 - 365, The docs show an inconsistent
cache key form: the pattern includes${options.base}:...but the invalidation
example omits it; update the text for clarity and make examples consistent by
either (A) documenting the full storage key format used by
defineCachedFunction/defineCachedHandler (referencing options.base,
options.group, options.name, options.getKey) and changing the invalidation call
to include${options.base}:...OR (B) explicitly state that the displayed key
is mount-relative (omit options.base) and change the pattern to
${options.group}:${options.name}:${options.getKey(...args)}.jsonso the
removeItem example usingnitro/functions:...matches; ensure the doc mentions
which form (full vs mount-relative) is being shown and update the getAccessToken
invalidation example to match that form.</details> </blockquote></details> </blockquote></details>🟡 Minor comments (14)
docs/4.examples/vite-rsc.md-283-286 (1)
283-286:⚠️ Potential issue | 🟡 MinorFix the HMR file paths in the walkthrough.
The example tree uses
app/client.tsxandapp/root.tsx, so pointing readers tosrc/client.tsx/src/root.tsxsends them to files that do not exist in this example.Proposed fix
- Edit <code>src/client.tsx</code> to test client HMR. + Edit <code>app/client.tsx</code> to test client HMR. ... - Edit <code>src/root.tsx</code> to test server HMR. + Edit <code>app/root.tsx</code> to test server HMR.Based on learnings: Update documentation in
docs/for user-facing changes.Also applies to: 1014-1017
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/4.examples/vite-rsc.md` around lines 283 - 286, The walkthrough incorrectly references src/client.tsx and src/root.tsx; update those references to app/client.tsx and app/root.tsx in the docs file so they match the example tree (replace "src/client.tsx" -> "app/client.tsx" and "src/root.tsx" -> "app/root.tsx"), and also scan the same document for any other occurrences of the wrong paths (the other HMR/example blocks) and replace them similarly.docs/4.examples/websocket.md-183-185 (1)
183-185:⚠️ Potential issue | 🟡 MinorRemove the stray backtick from the
index.htmlsnippet.Line 184 leaves a literal
`inside the HTML example, so users copying this block will end up with invalid markup.💡 Suggested change
</html> -`</details> <details> <summary>🤖 Prompt for AI Agents</summary>Verify each finding against the current code and only fix it if needed.
In
@docs/4.examples/websocket.mdaround lines 183 - 185, Remove the stray
backtick from the end of the index.html example in the docs/websocket snippet so
the HTML block ends with just (and the closing code fence) rather than
containing a literal "`"; edit the example around the closing tags in the
index.html snippet to delete the extra backtick so copied markup is valid.</details> </blockquote></details> <details> <summary>docs/2.deploy/20.providers/render.md-14-14 (1)</summary><blockquote> `14-14`: _⚠️ Potential issue_ | _🟡 Minor_ **Keep the Blueprint example aligned with the manual setup.** If `NODE_VERSION=20` is needed for Render builds to succeed, the `render.yaml` snippet below should expose the same env var too. Right now the two setup paths can drift, and IaC users may still hit the failure you're warning about here. <details> <summary>🤖 Prompt for AI Agents</summary>Verify each finding against the current code and only fix it if needed.
In
@docs/2.deploy/20.providers/render.mdat line 14, The Blueprint render.yaml
example must match the manual instructions by adding NODE_VERSION=20 alongside
NITRO_PRESET=render_com in the environment section; update the render.yaml
snippet (the environment block that currently shows NITRO_PRESET) to also
include NODE_VERSION: "20" so IaC deployments get the same build env as the
manual steps.</details> </blockquote></details> <details> <summary>docs/4.examples/mono-jsx.md-34-39 (1)</summary><blockquote> `34-39`: _⚠️ Potential issue_ | _🟡 Minor_ **Typo: "mongo-jsx" should be "mono-jsx".** The h1 text incorrectly says "mongo-jsx" instead of "mono-jsx". This typo appears in two places in this file. <details> <summary>✏️ Proposed fix</summary> ```diff ```tsx [server.tsx] export default () => ( <html> - <h1>Nitro + mongo-jsx works!</h1> + <h1>Nitro + mono-jsx works!</h1> </html> );Also fix line 70: ```diff - <h1>Nitro + mongo-jsx works!</h1> + <h1>Nitro + mono-jsx works!</h1>🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/4.examples/mono-jsx.md` around lines 34 - 39, The h1 text in the default exported JSX component (the arrow function exported as export default in the server.tsx snippet) mistakenly says "mongo-jsx"; update both occurrences of that heading to "mono-jsx" so the component reads <h1>Nitro + mono-jsx works!</h1> (also apply the same fix referenced at line ~70 in the file where the same typo appears).docs/4.examples/express.md-36-36 (1)
36-36:⚠️ Potential issue | 🟡 MinorChange
Expressto lowercaseexpressto match Express v5 conventions.The import should use lowercase
expressas shown in Express documentation and type definitions for v5, not the capitalizedExpress. Although esModuleInterop in the tsconfig allows both syntaxes to work, the standard convention is lowercase.import express from "express"; const app = express();🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/4.examples/express.md` at line 36, The import currently uses a capitalized identifier ("Express") which should be the lowercase default export name; change the import statement from "Express" to "express" so the module import matches Express v5 conventions and the common usage in code where you call express() to create the app (refer to the import line and the use of express() when creating the app instance).docs/4.examples/vite-ssr-vue-router.md-307-310 (1)
307-310:⚠️ Potential issue | 🟡 MinorUpdate the demo copy to match this Nitro example.
Line 309 still says “Vite Plugin Fullstack”, and Line 330 calls the app a “Custom Framework”. Those read like leftovers from a different example and will confuse readers copying this Nitro/Vite SSR setup.
Suggested doc fix
- <p>This is a simple Vue Router demo app built with Vite Plugin Fullstack.</p> + <p>This is a simple Vue Router demo app built with Nitro and Vite.</p>- <h1>Vue Router Custom Framework</h1> + <h1>Vue Router SSR with Nitro</h1>Also applies to: 330-331
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/4.examples/vite-ssr-vue-router.md` around lines 307 - 310, Update the demo text strings that incorrectly reference another example: replace the paragraph containing "Vite Plugin Fullstack" (the <p> that currently reads "This is a simple Vue Router demo app built with Vite Plugin Fullstack.") with copy matching the Nitro example (e.g., reference Nitro/Vite SSR instead of Vite Plugin Fullstack), and change the later occurrence "Custom Framework" (the <p> around lines 330-331) to the appropriate Nitro-specific phrasing; ensure both replaced strings consistently describe this as the Nitro Vite SSR Vue Router demo.docs/4.examples/auto-imports.md-36-40 (1)
36-40:⚠️ Potential issue | 🟡 MinorRemove the explicit
makeGreetingimport from the auto-import example.Line 38 and Line 97 still import the utility manually, so the page never actually demonstrates the “auto imports” behavior it describes.
Suggested doc fix
import { defineHandler } from "nitro/h3"; -import { makeGreeting } from "./server/utils/hello.ts"; export default defineHandler(() => `<h1>${makeGreeting("Nitro")}</h1>`);Also applies to: 95-99
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/4.examples/auto-imports.md` around lines 36 - 40, Remove the explicit import of makeGreeting from the example server.ts snippet so the example demonstrates auto-imports: delete the import line that references makeGreeting from "./server/utils/hello.ts" (keep the existing defineHandler import from "nitro/h3"), leaving the handler that calls makeGreeting("<...>") without a manual import; apply the same removal to the second occurrence of the example (the block that also imports makeGreeting) so both examples rely on auto-import behavior.docs/4.examples/vite-ssr-tsr-react.md-60-60 (1)
60-60:⚠️ Potential issue | 🟡 MinorFix typo in TypeScript path mapping.
The path mapping appears to have a typo:
"@/*": ["sec/*"]should likely be"@/*": ["src/*"]to correctly map the@alias to thesrcdirectory.🔧 Proposed fix
"paths": { - "@/*": ["sec/*"] + "@/*": ["src/*"] }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/4.examples/vite-ssr-tsr-react.md` at line 60, The TypeScript path mapping has a typo: the alias string "@/*": ["sec/*"] incorrectly maps to "sec" instead of the source directory; update the mapping to "@/*": ["src/*"] so imports using "@" resolve to the project's src folder (adjust the path mapping entry in the tsconfig/vite config where "@/*": ["sec/*"] appears).docs/1.docs/7.cache.md-271-280 (1)
271-280:⚠️ Potential issue | 🟡 MinorMake the shared hook descriptions match the signatures.
shouldInvalidateCache()andshouldBypassCache()are now typed asboolean | Promise<boolean>, but the prose still says they return aboolean, andonError()is described as function-only even though this section is shared with handlers too.Suggested doc fix
::field{name="shouldInvalidateCache()" type="(...args) => boolean | Promise<boolean>"} - A function that returns a `boolean` to invalidate the current cache and create a new one. + A function that returns or resolves to a `boolean` to invalidate the current cache and create a new one. :: ::field{name="shouldBypassCache()" type="(...args) => boolean | Promise<boolean>"} - A function that returns a `boolean` to bypass the current cache without invalidating the existing entry. + A function that returns or resolves to a `boolean` to bypass the current cache without invalidating the existing entry. :: ::field{name="onError()" type="(error: unknown) => void"} - A custom error handler called when the cached function throws. :br + A custom error handler called when the cached handler/function throws. :br🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/1.docs/7.cache.md` around lines 271 - 280, Update the documentation text for the shared hooks to match their TypeScript signatures: change the prose for shouldInvalidateCache() and shouldBypassCache() to state they may return either a boolean or a Promise<boolean> (i.e., may be async), and update onError() to indicate it can be synchronous or asynchronous (e.g., may return void or Promise<void>) and that this description is shared with handlers; keep the existing behavior note that by default errors are logged to the console and passed to the Nitro error handler.docs/4.examples/plugins.md-60-62 (1)
60-62:⚠️ Potential issue | 🟡 MinorInvalid MIME type in example code.
The
Content-Typeheader is set tohtml; charset=utf-8, which is not a valid MIME type. The correct format should betext/html; charset=utf-8.📝 Proposed fix
hooks.hook("response", (event) => { - event.headers.set("content-type", "html; charset=utf-8"); + event.headers.set("content-type", "text/html; charset=utf-8"); });This same fix should be applied to the duplicate example at lines 82-84.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/4.examples/plugins.md` around lines 60 - 62, The example sets an invalid MIME type "html; charset=utf-8" in the response hook; update the Content-Type value to the correct "text/html; charset=utf-8" in the hooks.hook("response", (event) => { event.headers.set(...); }) example and apply the same correction to the duplicate example later (the other hooks.hook("response") block).docs/.docs/components/HeroFeatures.vue-25-25 (1)
25-25:⚠️ Potential issue | 🟡 MinorPotential SSR/hydration mismatch with random values in computed property.
featureLinesis a computed property that callsrandomLines(), which usesMath.random(). Since computed properties run during SSR and again during hydration, the random values will differ between server and client, potentially causing hydration mismatches.🛡️ Proposed fix: Initialize random lines on mount
-const featureLines = computed(() => props.features.map(() => randomLines())) +const featureLines = ref<{ width: string; delay: number }[][]>([]) onMounted(() => { prefersReducedMotion.value = window.matchMedia('(prefers-reduced-motion: reduce)').matches + featureLines.value = props.features.map(() => randomLines()) }) + +// Initialize with empty arrays to prevent template errors during SSR +watch(() => props.features, (newFeatures) => { + if (import.meta.client) { + featureLines.value = newFeatures.map(() => randomLines()) + } +}, { immediate: false })🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/.docs/components/HeroFeatures.vue` at line 25, featureLines uses randomLines() (which calls Math.random()) inside a computed property causing SSR/client hydration mismatches; change to compute deterministic data on the server and generate randomLines only on the client by replacing the computed featureLines with a client-initialized ref (e.g., featureLinesRef) and populate it inside a mounted/onMounted lifecycle hook (or use a client-only lazy initializer) using props.features.length to call randomLines() per feature; keep the symbol names featureLines and randomLines referenced so you update their usages (e.g., where featureLines is consumed) to read from the new ref to avoid server/client divergence.docs/index.md-49-50 (1)
49-50:⚠️ Potential issue | 🟡 MinorSync the SEO metadata with the new homepage positioning.
The hero now leads with “Build Servers”, but the page frontmatter still advertises “Ship Full-Stack Vite Apps”. Search/social previews will keep the old message unless the metadata is updated alongside this title.
Based on learnings: Update documentation in
docs/for user-facing changes.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/index.md` around lines 49 - 50, Update the page frontmatter in docs/index.md so the SEO metadata matches the new hero title "Build Servers" (replace the old "Ship Full-Stack Vite Apps" text); adjust frontmatter keys such as title, description, og:title and twitter:title (and any meta description) to reflect the new positioning and ensure social/search previews show "Build Servers" and a matching short description.docs/index.md-67-69 (1)
67-69:⚠️ Potential issue | 🟡 Minor“locked-in” says the opposite of the intended value prop.
Line 68 currently reads as if Nitro causes vendor lock-in. This should be “no lock-in” or equivalent.
Suggested copy fix
- description: Deploy the same codebase to any deployment provider with zero config and locked-in. + description: Deploy the same codebase to any deployment provider with zero config and no lock-in.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/index.md` around lines 67 - 69, The description for the "Agnostic" section incorrectly uses "locked-in"; update the description field tied to the frontmatter keys (title: Agnostic, description) to convey the opposite meaning—e.g., change "Deploy the same codebase to any deployment provider with zero config and locked-in." to "Deploy the same codebase to any deployment provider with zero config and no lock‑in." Ensure the phrase "no lock‑in" (or equivalent) replaces "locked-in" in the description.docs/1.docs/50.plugins.md-63-68 (1)
63-68:⚠️ Potential issue | 🟡 MinorUpdate hook type signatures to allow async handlers for
errorandclosehooks.The runtime implementation explicitly expects promises from the
errorandclosehooks (via.catch()chaining andPromise.resolve()wrapping), and the documentation correctly shows async examples for both. Updatesrc/types/runtime/nitro.tsto reflect actual behavior:export interface NitroRuntimeHooks { close: () => void | Promise<void>; error: (error: Error, context: CapturedErrorContext) => void | Promise<void>; request: (event: HTTPEvent) => void | Promise<void>; response: (res: Response, event: HTTPEvent) => void | Promise<void>; }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/1.docs/50.plugins.md` around lines 63 - 68, The NitroRuntimeHooks interface in src/types/runtime/nitro.ts needs to allow async handlers for error and close: update the NitroRuntimeHooks type so close returns void | Promise<void> and error returns void | Promise<void> (keeping the existing parameters, e.g., error: Error, context: CapturedErrorContext); leave request and response as-is. Ensure you reference the NitroRuntimeHooks interface and the CapturedErrorContext type when making the signature changes.🧹 Nitpick comments (13)
docs/1.docs/50.tasks.md (1)
48-76: Consider documenting referenced types.The
TaskandTaskEventinterfaces are well-documented, but they referenceTaskPayloadandTaskContexttypes that aren't defined in this section. Consider adding a brief note about where these types are defined or what they contain (e.g., "TaskPayloadisRecord<string, unknown>").Also, the generic type
RTin theTaskinterface could use a brief explanation (e.g., "result type").📝 Suggested enhancement
### Task interface -The `defineTask` helper accepts an object with the following properties: +The `defineTask` helper accepts an object with the following properties (optionally typed with a generic result type): - **`meta`** (optional): An object with optional `name` and `description` string fields used for display in the dev server and CLI. - **`run`** (required): A function that receives a [`TaskEvent`](`#taskevent`) and returns (or resolves to) an object with an optional `result` property. ```ts -interface Task<RT = unknown> { +interface Task<RT = unknown> { // RT = result type meta?: { name?: string; description?: string }; run(event: TaskEvent): { result?: RT } | Promise<{ result?: RT }>; }And for TaskEvent:
### `TaskEvent` The `run` function receives a `TaskEvent` object with the following properties: - **`name`**: The name of the task being executed. -- **`payload`**: An object (`Record<string, unknown>`) containing any data passed to the task. +- **`payload`**: A `TaskPayload` object (`Record<string, unknown>`) containing any data passed to the task. - **`context`**: A `TaskContext` object (may include `waitUntil` depending on the runtime).🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/1.docs/50.tasks.md` around lines 48 - 76, Add brief documentation for the referenced types and the generic RT: state that TaskPayload is Record<string, unknown> and TaskContext may include waitUntil (or link to its definition), and annotate the Task interface's generic RT as "result type"; update the Task and TaskEvent sections to mention TaskPayload and TaskContext definitions/locations and add a one-line comment/parenthetical describing RT so readers know what it represents (referencing the Task, TaskEvent, TaskPayload, TaskContext, and RT symbols).AGENTS.md (1)
155-157: Make the H3 reference self-contained.The new note only points to an installed
node_modulespath, which is not available from GitHub and gives little context on when to use it. Folding this into the.agents/docs.mdbullet with a short purpose statement, plus an upstream reference or an explicitpnpm installprerequisite, would make the section much easier to discover and follow.Based on learnings, "Maintain centralized agent documentation in AGENTS.md for easy reference and discovery" and "Document agent implementations with clear descriptions of purpose, inputs, outputs, and example usage in AGENTS.md".
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@AGENTS.md` around lines 155 - 157, Update the AGENTS.md entry to make the H3 v2 reference self-contained: merge the note about the H3 docs into the `.agents/docs.md` bullet, add a one-line purpose statement (e.g., "Reference for H3 v2 API patterns and examples used by agents"), and include an upstream reference path `node_modules/h3/skills/h3/docs/TOC.md` plus a prerequisite note to run `pnpm install` to access it; ensure the `.agents/docs.md` bullet now contains the merged purpose, the local docs link `.agents/docs.md`, and the upstream/path + install hint for discoverability.docs/4.examples/cached-handler.md (1)
45-45: Consider usinggetQueryfor more robust query parameter parsing.The current implementation uses
req.url.includes("skipCache=true")which is fragile—it would incorrectly match URLs like/path?param=skipCache=trueor/skipCache=true.🔍 Proposed improvement
+import { getQuery } from "nitro/h3"; + export default defineCachedHandler( async () => { await new Promise((resolve) => setTimeout(resolve, 500)); return html` Response generated at ${new Date().toISOString()} (took 500ms) <br />(<a href="?skipCache=true">skip cache</a>) `; }, - { shouldBypassCache: ({ req }) => req.url.includes("skipCache=true") } + { shouldBypassCache: (event) => getQuery(event).skipCache === "true" } );🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/4.examples/cached-handler.md` at line 45, The shouldBypassCache predicate currently checks req.url.includes("skipCache=true") which is brittle; update the implementation of shouldBypassCache (the object field named shouldBypassCache that receives ({ req })) to parse query parameters robustly—use the project's getQuery helper (or URLSearchParams on new URL(req.url, origin)) to read the skipCache query param and return true only when its value is exactly "true". Ensure you reference the same ({ req }) signature so behavior and types remain consistent.docs/4.examples/nano-jsx.md (1)
34-41: Import from"h3"instead of"nitro/h3".The server.tsx examples import
defineHandlerandhtmlfrom"h3"(lines 35 and 69), while other documentation examples consistently use"nitro/h3". Consider aligning with the convention used in other examples for consistency.📝 Suggested fix
```tsx [server.tsx] -import { defineHandler, html } from "h3"; +import { defineHandler, html } from "nitro/h3"; import { renderSSR } from "nano-jsx";Also applies to: 68-75
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/4.examples/nano-jsx.md` around lines 34 - 41, The example imports defineHandler and html from "h3" but other docs use "nitro/h3"; update the import source to "nitro/h3" for the examples that call defineHandler and html (the same file where renderSSR from "nano-jsx" is used) so the statement becomes import { defineHandler, html } from "nitro/h3"; — ensure you update both occurrences of that import in the server.tsx examples.docs/4.examples/vite-ssr-tss-react.md (1)
130-217: Auto-generated file included in documentation.The
src/routeTree.gen.tsfile is auto-generated by TanStack Router (as noted in the file comments). Including it in documentation may confuse readers who might think they need to create this file manually. Consider adding a note that this file is automatically generated by running TanStack Router's codegen, or exclude it from the code-tree display.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/4.examples/vite-ssr-tss-react.md` around lines 130 - 217, The docs include an auto-generated file (src/routeTree.gen.ts) which can confuse readers; update the documentation to either exclude routeTree.gen.ts from the displayed code tree or add a clear note above the file snippet explaining it is generated by TanStack Router (codegen) and should not be created manually—reference the file name (routeTree.gen.ts) and key symbols like rootRouteImport, IndexRouteImport, ApiTestRouteImport, and the routeTree export to make the note specific and help readers understand which file is generated.docs/4.examples/api-routes.md (1)
79-89: Inconsistent import source in POST handler examples.The POST handler examples import
defineHandlerfrom"h3"(lines 80 and 144), while all other examples consistently import from"nitro/h3". This inconsistency may confuse readers about which import path to use.📝 Suggested fix for consistency
```ts [api/test.post.ts] -import { defineHandler } from "h3"; +import { defineHandler } from "nitro/h3"; export default defineHandler(async (event) => {Apply the same fix to the repeated example in the "POST Handler" section (line 144).
Also applies to: 143-153
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/4.examples/api-routes.md` around lines 79 - 89, Replace the inconsistent import source for the POST handler examples: change the import that reads import { defineHandler } from "h3" to import { defineHandler } from "nitro/h3" for the example that defines defineHandler (the api/test.post.ts example) and the repeated POST Handler example further down so both use "nitro/h3" consistently.docs/1.docs/50.assets.md (1)
136-138: Minor wording improvements.Consider simplifying the phrasing for conciseness:
📝 Suggested rewording
-In order to add assets from a custom directory, you will need to define a path in your nitro config. This allows you to add assets from a directory outside of the `assets/` directory. +To add assets from a custom directory, define a path in your nitro config. This allows you to add assets from a directory outside the `assets/` directory.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/1.docs/50.assets.md` around lines 136 - 138, Simplify the two sentences that explain adding assets from a custom directory by replacing the verbose phrasing with a concise version: change "In order to add assets from a custom directory, you will need to define a path in your nitro config. This allows you to add assets from a directory outside of the `assets/` directory." to a shorter sentence such as "To add assets from a custom directory, define its path in your Nitro config — this lets you include directories outside the `assets/` directory." Update the paragraph containing that sentence accordingly to improve clarity and conciseness.docs/1.docs/8.storage.md (1)
163-172: Add language identifier to code block.The code block showing the directory structure is missing a language identifier. Consider adding
txtor another appropriate identifier for consistency.📝 Proposed fix
-``` +```txt my-project/ assets/ data.json🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/1.docs/8.storage.md` around lines 163 - 172, Update the fenced code block that contains the directory tree (the block starting with "my-project/") to include a language identifier (e.g., ```txt) so the directory structure is rendered consistently; replace the opening triple backticks with ```txt and keep the block contents unchanged.docs/4.examples/server-fetch.md (1)
14-27: Call out when to useserverFetch()vsfetch().The first example uses
serverFetch()from a Nitro hook, while the narrative below tells readers to use Nitro'sfetch()inside routes. A short note mapping each helper to its intended context would prevent copy-paste confusion.Suggested doc tweak
-When you need one route to call another, use Nitro's `fetch` function instead of the global fetch. +Nitro exposes two in-process request helpers: + +- Use `fetch()` from `"nitro"` inside route handlers. +- Use `serverFetch()` from `"nitro"` in Nitro config/hooks and other non-request contexts. + +When you need one route to call another from a handler, use Nitro's `fetch` function instead of the global fetch.Also applies to: 74-85
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/4.examples/server-fetch.md` around lines 14 - 27, Add a short clarifying note distinguishing serverFetch() versus fetch(): indicate that serverFetch() is the Nitro helper intended for use in Nitro modules/hooks (e.g., the "dev:start" hook where serverFetch("/hello") is shown) while the runtime fetch() should be used inside route handlers/SSR code; update the text around the first example and the later block (the section around lines showing serverFetch usage and the section mentioning fetch()) to explicitly map each helper to its intended context to avoid copy/paste confusion.docs/.docs/components/AppHero.vue (1)
20-27: Hardcoded language may not match all file types.The
language="ts"is hardcoded for all code groups, butcodeGroupsmay include files like.jsonor.yaml. Consider either inferring the language from the filename extension or adding alanguageproperty to thecodeGroupstype.♻️ Option 1: Extend the codeGroups type
codeGroups: { filename: string code: string + language?: string }[]<ProsePre v-for="group in codeGroups" :key="group.filename" :filename="group.filename" - language="ts" + :language="group.language || 'ts'" >🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/.docs/components/AppHero.vue` around lines 20 - 27, The ProsePre component is being passed a hardcoded language="ts" which will mislabel non-TypeScript files; update the rendering to determine the language per group by either adding a language field to the codeGroups items (e.g., group.language) and pass that to <ProsePre> or derive the language from group.filename's extension (inspect group.filename, map .ts/.js/.json/.yaml/.yml/etc. to the correct language string) and pass the computed value as the language prop; update the template usage around ProsePre, group.filename, and group.code accordingly so each file shows the correct language.docs/.docs/components/FeatureCard.vue (1)
18-22: Reduced motion handling may be incomplete.When
prefersReducedMotionis true, the initial state is set to{ opacity: 1 }, butwhile-in-viewstill triggers an animation to{ opacity: 1, y: 0 }. For users who prefer reduced motion, consider also conditionally disabling or simplifying thewhile-in-viewtransition.♻️ Proposed fix to fully respect reduced motion
<Motion - :initial="prefersReducedMotion ? { opacity: 1 } : { opacity: 0, y: 20 }" - :while-in-view="{ opacity: 1, y: 0 }" + :initial="prefersReducedMotion ? { opacity: 1, y: 0 } : { opacity: 0, y: 20 }" + :while-in-view="prefersReducedMotion ? undefined : { opacity: 1, y: 0 }" :transition="{ duration: 0.5 }" :in-view-options="{ once: true }" >🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/.docs/components/FeatureCard.vue` around lines 18 - 22, The Motion component currently sets initial to a reduced-motion-friendly value but still applies a positional animation via :while-in-view and :transition; update the Motion usage so when prefersReducedMotion is true you also set :while-in-view to a static state (e.g., { opacity: 1, y: 0 } without animating) and/or disable the positional transition by providing a simplified or no-op :transition (or skip the y property) to fully respect reduced motion; adjust the binding around :while-in-view and :transition (the props on the Motion element) to branch on prefersReducedMotion so no movement is triggered for users who prefer reduced motion.docs/.docs/assets/css/main.css (1)
1-18: Consider documenting the rationale for!importantoverrides.The stylesheet uses multiple
!importantdeclarations to override default styles. While this is common for documentation sites that need to customize UI library defaults, a brief comment explaining why these overrides are necessary would improve maintainability for future contributors.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/.docs/assets/css/main.css` around lines 1 - 18, Add a short top-of-file comment explaining why the stylesheet uses multiple !important overrides (e.g., to override the UI library/third-party docs theme defaults and ensure specific font and background colors for selectors like :root variables (--font-sans, --font-mono), h1[data-slot="title"], .landing-code and .landing-code pre[style]); place the comment above these rules, state what is being overridden and any constraints (why specificity or !important is required) and include guidance for future contributors about when to avoid or refactor these overrides.docs/.docs/components/HeroFeatures.vue (1)
59-68: Inner line animations don't respect reduced motion preference.The inner
Motioncomponents for line animations always animate regardless of theprefersReducedMotionflag. For consistency with the outer feature card animation, these should also be conditionally disabled.♻️ Proposed fix
<Motion v-for="(line, j) in featureLines[i]" :key="j" - :initial="{ width: '0%', opacity: 0 }" - :while-in-view="{ width: line.width, opacity: 1 }" + :initial="prefersReducedMotion ? { width: line.width, opacity: 1 } : { width: '0%', opacity: 0 }" + :while-in-view="prefersReducedMotion ? undefined : { width: line.width, opacity: 1 }" :transition="{ duration: 0.8, delay: 0.3 + line.delay + i * 0.1 }" :in-view-options="{ once: true }" >🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/.docs/components/HeroFeatures.vue` around lines 59 - 68, The inner Motion v-for block (the Motion component rendering the progress lines) ignores the prefersReducedMotion setting; update the Motion instances used inside the loop (the Motion rendering each line in featureLines) to disable animations when prefersReducedMotion is true by conditionally setting props: when prefersReducedMotion is true, provide static state (e.g., skip :initial and :while-in-view or set them equal so no transition runs) and avoid :transition/:in-view-options that trigger motion; when false, keep the existing :initial, :while-in-view, :transition and :in-view-options values so animations run as before.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID:
2f4901bc-be77-4692-bae2-9f3a6b175a11⛔ Files ignored due to path filters (2)
docs/.docs/assets/fonts/GeistPixel-Square.woff2is excluded by!**/*.woff2docs/pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml📒 Files selected for processing (131)
.agents/docs.mdAGENTS.mddocs/.config/docs.yamldocs/.docs/app.config.tsdocs/.docs/assets/css/main.cssdocs/.docs/components/AppHero.vuedocs/.docs/components/AppHeroLinks.vuedocs/.docs/components/FeatureCard.vuedocs/.docs/components/HeroBackground.client.vuedocs/.docs/components/HeroFeatures.vuedocs/.docs/components/LandingFeatures.vuedocs/.docs/components/PerformanceShowcase.vuedocs/.docs/content.config.tsdocs/.docs/layouts/examples.vuedocs/.docs/nuxt.config.tsdocs/.docs/pages/examples/[...slug].vuedocs/.docs/pages/examples/index.vuedocs/.docs/server/routes/raw/examples/[...slug].md.get.tsdocs/1.docs/2.quick-start.mddocs/1.docs/4.renderer.mddocs/1.docs/5.routing.mddocs/1.docs/50.assets.mddocs/1.docs/50.configuration.mddocs/1.docs/50.database.mddocs/1.docs/50.lifecycle.mddocs/1.docs/50.plugins.mddocs/1.docs/50.tasks.mddocs/1.docs/6.server-entry.mddocs/1.docs/7.cache.mddocs/1.docs/8.storage.mddocs/1.docs/99.migration.mddocs/2.deploy/0.index.mddocs/2.deploy/10.runtimes/1.node.mddocs/2.deploy/20.providers/alwaysdata.mddocs/2.deploy/20.providers/cloudflare.mddocs/2.deploy/20.providers/digitalocean.mddocs/2.deploy/20.providers/platform-sh.mddocs/2.deploy/20.providers/render.mddocs/2.deploy/20.providers/zerops.mddocs/3.config/0.index.mddocs/4.examples/api-routes.mddocs/4.examples/auto-imports.mddocs/4.examples/cached-handler.mddocs/4.examples/custom-error-handler.mddocs/4.examples/database.mddocs/4.examples/elysia.mddocs/4.examples/express.mddocs/4.examples/fastify.mddocs/4.examples/hello-world.mddocs/4.examples/hono.mddocs/4.examples/import-alias.mddocs/4.examples/middleware.mddocs/4.examples/mono-jsx.mddocs/4.examples/nano-jsx.mddocs/4.examples/plugins.mddocs/4.examples/renderer.mddocs/4.examples/runtime-config.mddocs/4.examples/server-fetch.mddocs/4.examples/shiki.mddocs/4.examples/virtual-routes.mddocs/4.examples/vite-nitro-plugin.mddocs/4.examples/vite-rsc.mddocs/4.examples/vite-ssr-html.mddocs/4.examples/vite-ssr-preact.mddocs/4.examples/vite-ssr-react.mddocs/4.examples/vite-ssr-solid.mddocs/4.examples/vite-ssr-tsr-react.mddocs/4.examples/vite-ssr-tss-react.mddocs/4.examples/vite-ssr-vue-router.mddocs/4.examples/vite-trpc.mddocs/4.examples/websocket.mddocs/index.mddocs/package.jsonexamples/api-routes/GUIDE.mdexamples/api-routes/README.mdexamples/auto-imports/GUIDE.mdexamples/auto-imports/README.mdexamples/cached-handler/GUIDE.mdexamples/cached-handler/README.mdexamples/custom-error-handler/GUIDE.mdexamples/custom-error-handler/README.mdexamples/database/GUIDE.mdexamples/database/README.mdexamples/elysia/GUIDE.mdexamples/elysia/README.mdexamples/express/GUIDE.mdexamples/express/README.mdexamples/fastify/GUIDE.mdexamples/fastify/README.mdexamples/hello-world/GUIDE.mdexamples/hello-world/README.mdexamples/hono/GUIDE.mdexamples/hono/README.mdexamples/import-alias/GUIDE.mdexamples/import-alias/README.mdexamples/middleware/GUIDE.mdexamples/middleware/README.mdexamples/mono-jsx/GUIDE.mdexamples/mono-jsx/README.mdexamples/nano-jsx/GUIDE.mdexamples/nano-jsx/README.mdexamples/plugins/GUIDE.mdexamples/plugins/README.mdexamples/renderer/GUIDE.mdexamples/renderer/README.mdexamples/runtime-config/GUIDE.mdexamples/runtime-config/README.mdexamples/server-fetch/GUIDE.mdexamples/server-fetch/README.mdexamples/shiki/GUIDE.mdexamples/shiki/README.mdexamples/virtual-routes/GUIDE.mdexamples/virtual-routes/README.mdexamples/vite-nitro-plugin/GUIDE.mdexamples/vite-nitro-plugin/README.mdexamples/vite-rsc/GUIDE.mdexamples/vite-rsc/README.mdexamples/vite-ssr-html/GUIDE.mdexamples/vite-ssr-html/README.mdexamples/vite-ssr-preact/README.mdexamples/vite-ssr-react/README.mdexamples/vite-ssr-solid/README.mdexamples/vite-ssr-tsr-react/GUIDE.mdexamples/vite-ssr-tsr-react/README.mdexamples/vite-ssr-tss-react/GUIDE.mdexamples/vite-ssr-tss-react/README.mdexamples/vite-ssr-vue-router/GUIDE.mdexamples/vite-ssr-vue-router/README.mdexamples/vite-trpc/README.mdexamples/websocket/GUIDE.mdexamples/websocket/README.md💤 Files with no reviewable changes (57)
- examples/api-routes/GUIDE.md
- examples/vite-nitro-plugin/GUIDE.md
- examples/vite-ssr-html/README.md
- examples/mono-jsx/GUIDE.md
- examples/elysia/GUIDE.md
- examples/websocket/GUIDE.md
- examples/plugins/README.md
- examples/server-fetch/GUIDE.md
- examples/custom-error-handler/GUIDE.md
- examples/hono/GUIDE.md
- examples/database/GUIDE.md
- examples/hello-world/GUIDE.md
- examples/import-alias/GUIDE.md
- examples/renderer/GUIDE.md
- examples/vite-ssr-tsr-react/GUIDE.md
- examples/vite-ssr-vue-router/GUIDE.md
- examples/runtime-config/GUIDE.md
- examples/plugins/GUIDE.md
- examples/hono/README.md
- docs/.docs/server/routes/raw/examples/[...slug].md.get.ts
- examples/middleware/GUIDE.md
- examples/mono-jsx/README.md
- examples/nano-jsx/GUIDE.md
- examples/vite-ssr-tss-react/GUIDE.md
- examples/renderer/README.md
- examples/virtual-routes/GUIDE.md
- examples/custom-error-handler/README.md
- examples/cached-handler/GUIDE.md
- examples/auto-imports/GUIDE.md
- examples/fastify/GUIDE.md
- examples/vite-nitro-plugin/README.md
- examples/vite-rsc/GUIDE.md
- docs/.docs/content.config.ts
- examples/runtime-config/README.md
- examples/import-alias/README.md
- examples/express/README.md
- docs/1.docs/2.quick-start.md
- examples/cached-handler/README.md
- examples/shiki/README.md
- examples/express/GUIDE.md
- examples/vite-ssr-html/GUIDE.md
- examples/shiki/GUIDE.md
- examples/api-routes/README.md
- examples/virtual-routes/README.md
- examples/middleware/README.md
- examples/vite-trpc/README.md
- examples/vite-ssr-react/README.md
- examples/server-fetch/README.md
- examples/vite-ssr-tsr-react/README.md
- examples/websocket/README.md
- examples/fastify/README.md
- examples/hello-world/README.md
- examples/vite-ssr-solid/README.md
- examples/elysia/README.md
- examples/nano-jsx/README.md
- examples/auto-imports/README.md
- examples/vite-ssr-preact/README.md
| When a scheduled task runs, it automatically receives a `payload` with `scheduledTime` set to the current timestamp (`Date.now()`). | ||
|
|
||
| ### Platform support | ||
|
|
||
| - **`dev`**, **`node_server`**, **`node_cluster`**, **`node_middleware`**, **`bun`** and **`deno_server`** presets are supported with the [croner](https://croner.56k.guru/) engine. | ||
| - **`cloudflare_module`** and **`cloudflare_pages`** presets have native integration with [Cron Triggers](https://developers.cloudflare.com/workers/configuration/cron-triggers/). Nitro automatically generates the cron triggers in the wrangler config at build time - no manual wrangler setup required. | ||
| - **`vercel`** preset has native integration with [Vercel Cron Jobs](https://vercel.com/docs/cron-jobs). Nitro automatically generates the cron job configuration at build time - no manual `vercel.json` setup required. You can secure cron endpoints by setting the `CRON_SECRET` environment variable. | ||
| - More presets (with native primitives support) are planned to be supported! |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify platform preset files exist and contain cron-related logic
echo "=== Checking for Cloudflare cron integration ==="
fd -e ts -e js . src/presets | rg -l cloudflare | head -5
echo -e "\n=== Checking for Vercel cron integration ==="
fd -e ts -e js . src/presets | rg -l vercel | head -5
echo -e "\n=== Searching for cron/scheduled task logic in presets ==="
rg -n "cron|scheduled" src/presets --type ts --type js -C 2 | head -40Repository: nitrojs/nitro
Length of output: 2439
🏁 Script executed:
#!/bin/bash
echo "=== Vercel cron handler implementation ==="
find src/presets/vercel -name "*.ts" -o -name "*.js" | xargs grep -l "cron" | head -5
echo -e "\n=== Content of Vercel cron handler ==="
find src/presets/vercel -path "*runtime*" -name "*cron*" -type f
echo -e "\n=== CRON_SECRET usage ==="
rg "CRON_SECRET" src/presets/vercel/ -A 2 -B 2
echo -e "\n=== Scheduled task payload construction ==="
rg "scheduledTime|payload" src/ -C 2 --type ts --max-count 15
echo -e "\n=== Cloudflare cron integration ==="
find src/presets -name "*cloudflare*" -type f | head -10Repository: nitrojs/nitro
Length of output: 9150
🏁 Script executed:
#!/bin/bash
echo "=== Vercel cron handler full content ==="
cat -n src/presets/vercel/runtime/cron-handler.ts
echo -e "\n=== Cloudflare module cron handler ==="
sed -n '1,100p' src/presets/cloudflare/runtime/cloudflare-module.ts | cat -n
echo -e "\n=== Cloudflare pages cron handler ==="
sed -n '1,100p' src/presets/cloudflare/runtime/cloudflare-pages.ts | cat -n
echo -e "\n=== Check for x-vercel-cron-schedule header usage ==="
rg "x-vercel-cron-schedule" src/ -iRepository: nitrojs/nitro
Length of output: 5265
🏁 Script executed:
#!/bin/bash
echo "=== Check dev server cron implementation ==="
rg "runCronTasks|scheduledTime" src/dev/ -A 3 -B 1
echo -e "\n=== Check bun preset cron/scheduled implementation ==="
find src/presets/bun -type f -name "*.ts" -o -name "*.js" | xargs grep -l "cron\|scheduled" 2>/dev/null || echo "No cron files found"
echo -e "\n=== Check deno_server preset cron implementation ==="
find src/presets/deno_server -type f -name "*.ts" -o -name "*.js" | xargs grep -l "cron\|scheduled" 2>/dev/null || echo "No cron files found"
echo -e "\n=== Task runtime internals for payload ==="
sed -n '100,200p' src/runtime/internal/task.ts | cat -nRepository: nitrojs/nitro
Length of output: 371
🏁 Script executed:
#!/bin/bash
echo "=== Full task.ts runtime to understand scheduledTime payload ==="
wc -l src/runtime/internal/task.ts
echo -e "\n=== Lines around scheduledTime in task.ts ==="
sed -n '80,140p' src/runtime/internal/task.ts | cat -n
echo -e "\n=== Croner/dev server scheduling ==="
rg "croner|cron" src/runtime/ -l
echo -e "\n=== Check preset.ts files for task scheduling ==="
find src/presets -name "preset.ts" -exec grep -l "cron\|task\|scheduled" {} \; | head -5Repository: nitrojs/nitro
Length of output: 923
🏁 Script executed:
#!/bin/bash
echo "=== Full task.ts file ==="
cat -n src/runtime/internal/task.ts
echo -e "\n=== Check croner integration in dev ==="
rg "croner" src/ -B 2 -A 2 | head -50
echo -e "\n=== Verify scheduledTime payload in actual preset implementations ==="
echo "Vercel:"
grep -A 3 "scheduledTime" src/presets/vercel/runtime/cron-handler.ts
echo -e "\nCloudflare pages:"
grep -A 3 "scheduledTime\|payload" src/presets/cloudflare/runtime/cloudflare-pages.ts | grep -A 3 "scheduled"
echo -e "\n=== Check if there's a generic task execution that sets scheduledTime ==="
rg "scheduledTime" src/ --type ts -B 3 -A 1Repository: nitrojs/nitro
Length of output: 4529
🏁 Script executed:
#!/bin/bash
echo "=== Check Cloudflare module cron handler ==="
find src/presets/cloudflare -name "*module*" -type f | xargs grep -l "cron\|scheduled" | head -3
echo -e "\n=== Check if cloudflare-module has scheduled handler ==="
rg "scheduled|cron" src/presets/cloudflare/runtime/ -l
echo -e "\n=== Check cloudflare-durable for cron/scheduled ==="
rg "scheduled|cron|runCronTasks" src/presets/cloudflare/runtime/cloudflare-durable.ts -B 2 -A 2
echo -e "\n=== Summary of payload handling across presets ==="
echo "Checking all preset cron handlers for payload:"
rg "runCronTasks|payload" src/presets/*/runtime/ --type ts -B 1 -A 2 | grep -E "(src/presets|payload|runCronTasks)"Repository: nitrojs/nitro
Length of output: 3388
Platform support documentation requires accuracy correction and clarification.
The claim that "a payload with scheduledTime set to the current timestamp" is automatically provided to all scheduled tasks is inaccurate. This only applies to Vercel and croner-based platforms (dev, node_server, node_cluster, node_middleware, bun, deno_server). Cloudflare presets (both cloudflare_pages and cloudflare_module) pass an empty payload {} and do not include scheduledTime.
Additionally, the Vercel documentation should mention that Vercel provides an x-vercel-cron-schedule header in cron invocations to identify which schedule triggered the request. This allows handlers to determine the specific cron job that was invoked.
The CRON_SECRET environment variable documentation and automatic config generation claims are accurate and well-documented.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@docs/1.docs/50.tasks.md` around lines 122 - 129, Update the "Platform
support" section to remove the blanket claim that scheduled tasks always receive
a payload with scheduledTime and instead clarify behavior per platform: state
that dev, node_server, node_cluster, node_middleware, bun and deno_server
(croner) provide a payload with scheduledTime (Date.now()), whereas
cloudflare_module and cloudflare_pages deliver an empty payload {}; also add
that Vercel sends cron invocations with an x-vercel-cron-schedule header (and
keep the existing note about automatic Vercel cron job generation and
CRON_SECRET security), ensuring the presets names (dev, node_server,
node_cluster, node_middleware, bun, deno_server, cloudflare_module,
cloudflare_pages, vercel) are referenced exactly as in the diff so readers can
locate the relevant platform behaviors.
| | `node` | `node_middleware` (export changed to `middleware`) | | ||
| | `cloudflare`, `cloudflare_worker`, `cloudflare_module_legacy` | `cloudflare_module` | | ||
| | `deno-server-legacy` | `deno_server` with Deno v2 | | ||
| | `netlify-builder` | `netlify_functions` or `netlify_edge` | | ||
| | `netlify-builder` | `netlify` or `netlify_edge` | | ||
| | `vercel-edge` | `vercel` with Fluid compute enabled | | ||
| | `azure`, `azure_functions` | `azure_swa` | | ||
| | `firebase` | `firebase-functions` | | ||
| | `iis` | `iis-handler` | | ||
| | `deno` | `deno-deploy` | | ||
| | `firebase` | `firebase_app_hosting` | | ||
| | `iis` | `iis_handler` | | ||
| | `deno` | `deno_deploy` | |
There was a problem hiding this comment.
Clarify these as target-specific migrations, not direct renames.
Lines 92, 95, 98, and 100 currently read like one-to-one preset renames, but several of these imply a different runtime or deployment model. In particular, node_middleware changes the export contract, netlify vs netlify_edge depends on the chosen runtime, and firebase_app_hosting / deno_deploy are not generic replacements for every prior firebase / deno use case. As written, this can push users onto the wrong preset during migration.
Consider splitting these rows into explicit “use X if…” guidance, or mark the old preset as removed when there is no true drop-in equivalent.
Suggested doc shape
-| `node` | `node_middleware` (export changed to `middleware`) |
-| `netlify-builder` | `netlify` or `netlify_edge` |
-| `firebase` | `firebase_app_hosting` |
-| `deno` | `deno_deploy` |
+| `node` | Use the v3 preset that matches your target output; call out separately when `node_middleware` is required because the export changes to `middleware` |
+| `netlify-builder` | `netlify` for serverless output, `netlify_edge` for edge output |
+| `firebase` | No direct drop-in replacement; use `firebase_app_hosting` only if you are migrating to Firebase App Hosting |
+| `deno` | `deno_server` for self-hosted Deno, `deno_deploy` for Deno Deploy |Based on learnings, update documentation in docs/ for user-facing changes.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@docs/1.docs/99.migration.md` around lines 92 - 100, The table incorrectly
implies one-to-one preset renames; update the docs so each mapping is expressed
as target-specific migration guidance rather than a direct replacement: split
the `node` → `node_middleware (middleware)` row to explain the export contract
change and when to pick `node_middleware` vs keep `node`, clarify
`netlify-builder` → `netlify` vs `netlify_edge` with a “use X if you target Edge
vs JVM/Node runtime” note, change `firebase` → `firebase_app_hosting` and `deno`
→ `deno_deploy` rows to state the specific runtime/deployment scenarios where
the new preset applies (or mark the old preset removed if no drop-in exists),
and add short “use X if…” guidance for each affected preset name
(`node_middleware`, `netlify_edge`, `firebase_app_hosting`, `deno_deploy`) so
readers know which runtime/contract each replacement targets.
| ```json [tsconfig.json] | ||
| { | ||
| "include": [".nitro/types/nitro-imports.d.ts", "src"] | ||
| } |
There was a problem hiding this comment.
Include the files this page actually uses in tsconfig.json.
The example only includes src, but the files shown on this page live at server.ts and server/utils/**. Copy-pasting this config means the generated auto-import typings will not apply to the example files.
Suggested doc fix
{
- "include": [".nitro/types/nitro-imports.d.ts", "src"]
+ "include": [".nitro/types/nitro-imports.d.ts", "server.ts", "server/**/*"]
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| ```json [tsconfig.json] | |
| { | |
| "include": [".nitro/types/nitro-imports.d.ts", "src"] | |
| } |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@docs/4.examples/auto-imports.md` around lines 43 - 46, The tsconfig.json
shown only includes "src" so the generated auto-import typings won't apply to
the example files; update the "include" array to also cover the example files
referenced on the page by adding the example paths (e.g., "server.ts" and
"server/utils/**" or "server/**/*.ts") alongside the existing
".nitro/types/nitro-imports.d.ts" and "src" entry so the auto-import typings are
picked up for the example code.
| ```ts [nitro.config.ts] | ||
| import { defineConfig } from "nitro"; | ||
|
|
||
| export default defineConfig({}); | ||
| ``` |
There was a problem hiding this comment.
Inconsistency: Use defineNitroConfig instead of defineConfig.
According to the documentation guide in .agents/docs.md, Nitro config files should use defineNitroConfig from "nitro/config".
📝 Proposed fix
-import { defineConfig } from "nitro";
+import { defineNitroConfig } from "nitro/config";
-export default defineConfig({});
+export default defineNitroConfig({});As per coding guidelines: "Always use defineNitroConfig from "nitro/config" (not defineConfig)".
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@docs/4.examples/cached-handler.md` around lines 14 - 18, The snippet uses
defineConfig from "nitro" but the project standard requires defineNitroConfig
from "nitro/config"; update the import and config call by replacing defineConfig
with defineNitroConfig and import it from "nitro/config" (i.e., change the
import source and function name where the exported default calls defineConfig)
so the nitro.config.ts uses defineNitroConfig correctly.
| export default defineErrorHandler((error, _event) => { | ||
| return new Response(`Custom Error Handler: ${error.message}`, { | ||
| status: 500, | ||
| headers: { "Content-Type": "text/plain" }, | ||
| }); |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
In Nitro/h3, which status property is exposed on errors received by defineErrorHandler (status, statusCode, or both)?
💡 Result:
In Nitro (using h3), errors you receive in defineErrorHandler may expose both:
error.status(for h3’s newerHTTPError) (h3.dev)error.statusCode(for legacyH3Error/createError) (app.unpkg.com)
Nitro’s own error handler code explicitly checks error.status || error.statusCode || 500, so it supports either property. (app.unpkg.com)
Citations:
- 1: https://h3.dev/guide/basics/error
- 2: https://app.unpkg.com/h3%400.7.21/files/dist/index.d.ts?utm_source=openai
- 3: https://app.unpkg.com/%40nuxt/nitro-server%404.3.1/files/dist/runtime/handlers/error.mjs?utm_source=openai
🏁 Script executed:
cat -n docs/4.examples/custom-error-handler.md | sed -n '15,25p'Repository: nitrojs/nitro
Length of output: 404
🏁 Script executed:
cat -n docs/4.examples/custom-error-handler.md | sed -n '82,92p'Repository: nitrojs/nitro
Length of output: 564
Preserve HTTP status codes from errors instead of hardcoding 500.
Hardcoding status: 500 overwrites the original HTTP status from thrown errors. When developers copy this example for handling 4xx/5xx errors, they will inadvertently convert them all to server errors.
Nitro errors expose both error.status (h3 HTTPError) and error.statusCode (legacy createError), so read from either with a fallback:
Suggested fix
export default defineErrorHandler((error, _event) => {
+ const status =
+ (error as { status?: number; statusCode?: number }).status ??
+ (error as { status?: number; statusCode?: number }).statusCode ??
+ 500;
return new Response(`Custom Error Handler: ${error.message}`, {
- status: 500,
+ status,
headers: { "Content-Type": "text/plain" },
});
});Applies to lines 17-21 and 84-88.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| export default defineErrorHandler((error, _event) => { | |
| return new Response(`Custom Error Handler: ${error.message}`, { | |
| status: 500, | |
| headers: { "Content-Type": "text/plain" }, | |
| }); | |
| export default defineErrorHandler((error, _event) => { | |
| const status = | |
| (error as { status?: number; statusCode?: number }).status ?? | |
| (error as { status?: number; statusCode?: number }).statusCode ?? | |
| 500; | |
| return new Response(`Custom Error Handler: ${error.message}`, { | |
| status, | |
| headers: { "Content-Type": "text/plain" }, | |
| }); | |
| }); |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@docs/4.examples/custom-error-handler.md` around lines 17 - 21, Example error
handler currently hardcodes status: 500 which overwrites original error HTTP
status; update the handler returned by defineErrorHandler so it reads the status
from the thrown error (use error.status or fallback to error.statusCode) and
only default to 500 if neither exists, i.e. compute status = error.status ??
error.statusCode ?? 500 and use that value in the Response options to preserve
4xx/5xx statuses.
|
|
||
| # Vite + tRPC | ||
|
|
||
| > End-to-end typesafe APIs with tRPC in Nitro using Vite. |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
cat -n docs/4.examples/vite-trpc.md | head -200Repository: nitrojs/nitro
Length of output: 5715
🏁 Script executed:
# Check if there are any other usages of `@trpc/client` in the example
grep -r "@trpc/client" docs/4.examples/vite-trpc.mdRepository: nitrojs/nitro
Length of output: 87
Example contradicts its promise of end-to-end type safety.
The documentation claims "End-to-end typesafe APIs", but the client code bypasses tRPC's typed client entirely, hand-parsing raw HTTP responses instead. This leaves AppRouter unused and converts the example into a plain fetch pattern rather than a typed tRPC example. Either implement the client using @trpc/client with the exported AppRouter, or update the documentation copy to accurately reflect what the example demonstrates. tRPC's own documentation shows the typed-client pattern as the standard approach.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@docs/4.examples/vite-trpc.md` at line 8, The example claims "End-to-end
typesafe APIs" but the client code ignores AppRouter and hand-parses raw HTTP
responses; replace the fetch-based client with a typed tRPC client using the
exported AppRouter (e.g., import { AppRouter } and create a client via
createTRPCProxyClient or createTRPCClient from `@trpc/client` with httpBatchLink),
then call the typed procedures (router methods) instead of manual fetch/JSON
parsing so the example actually uses end-to-end type safety; alternatively, if
you prefer not to show the typed-client pattern, update the prose to remove the
"typesafe" claim and explain it demonstrates a raw-fetch example.
| ```json [package.json] | ||
| { | ||
| "type": "module", | ||
| "scripts": { | ||
| "dev": "vite", | ||
| "build": "vite build", | ||
| "preview": "vite preview" | ||
| }, | ||
| "devDependencies": { | ||
| "@trpc/client": "^11.9.0", | ||
| "@trpc/server": "^11.9.0", | ||
| "nitro": "latest", | ||
| "vite": "beta", | ||
| "zod": "^4.3.6" | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# Locate and examine the target file
find . -name "vite-trpc.md" -type fRepository: nitrojs/nitro
Length of output: 87
🏁 Script executed:
# If found, examine the specific lines
if [ -f "docs/4.examples/vite-trpc.md" ]; then
sed -n '109,123p' docs/4.examples/vite-trpc.md
fiRepository: nitrojs/nitro
Length of output: 351
🏁 Script executed:
# Also check the overall context of the file
wc -l docs/4.examples/vite-trpc.md 2>/dev/null || echo "File not found"Repository: nitrojs/nitro
Length of output: 89
🌐 Web query:
Nitro v3 beta release strategy npm dist-tags versions
💡 Result:
A solid Nitro v3 beta release strategy on npm is:
- Keep
lateston the current stable major (v2) until v3 is GA. npm installs thelatestdist-tag by default, so you don’t want prereleases to become the default install. [1] - Publish v3 prereleases as SemVer prereleases (e.g.
3.0.0-beta.0,3.0.0-beta.1,3.0.0-rc.0) and attach a non-latestdist-tag such asbetaornext. npm explicitly recommends using tags for unstable/prerelease versions (example:npm publish --tag=beta). [1][2] - Avoid dist-tags that start with
vor a number (so preferbeta/next/rcoverv3). [2] - When v3 goes stable (e.g.
3.0.0):- publish normally (or retag) so
latest -> 3.0.0 - optionally keep prerelease stream as
next/beta -> 3.1.0-beta.x - optionally park v2 as
v2/legacytag (so users can still dopkg@v2). [1][2]
- publish normally (or retag) so
Minimal command flow:
# v3 beta publish
npm version prerelease --preid beta # -> 3.0.0-beta.0 (example)
npm publish --tag beta # or --tag next
# later, when v3 is GA
npm version 3.0.0
npm publish # goes to tag "latest" by defaultContext: Nitro has already used prerelease versioning for v3 (e.g. v3.0.1-alpha.0 in GitHub releases), which fits this model; the key is ensuring those builds are on a non-latest dist-tag until GA. [3]
Sources: npm dist-tag docs [1], npm “adding dist-tags” guidance [2], Nitro GitHub releases showing v3 prerelease [3].
Pin nitro to the v3 beta dist-tag or version.
Using "nitro": "latest" in a v3 beta example is incorrect because npm resolves latest to the current stable release (v2). To match the beta documentation context and ensure reproducibility, change this to either "nitro": "beta" (to follow the same pattern as "vite": "beta" in the same snippet) or pin it to a specific v3 beta version such as "^3.0.0-beta.0". npm publishes prerelease versions under separate dist-tags until the stable release is published, so latest will not pull v3 beta.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@docs/4.examples/vite-trpc.md` around lines 109 - 123, The package.json
example pins "nitro" to "latest" which will pull the stable v2 release; update
the dependency entry for "nitro" (the "nitro" key in the shown package.json) to
a v3 beta dist-tag or version—e.g., change "nitro": "latest" to "nitro": "beta"
or "nitro": "^3.0.0-beta.0" so it matches the example's v3 beta context (similar
to how "vite": "beta" is used).
| <!-- automd:ui-code-tree src="../../examples/websocket" default="routes/_ws.ts" ignore="README.md,GUIDE.md" expandAll --> | ||
|
|
||
| ::code-tree{defaultValue="routes/_ws.ts" expandAll} |
There was a problem hiding this comment.
Exclude generated deployment output from the docs code tree.
This automd:ui-code-tree is pulling in .vercel / .wrangler build artifacts, which makes the page huge and bakes stale metadata into a v3 beta doc (3.0.1-alpha.2, fixed build timestamps, generated bundles). Please ignore generated output here and keep the example focused on source files only.
💡 Suggested change
-<!-- automd:ui-code-tree src="../../examples/websocket" default="routes/_ws.ts" ignore="README.md,GUIDE.md" expandAll -->
+<!-- automd:ui-code-tree src="../../examples/websocket" default="routes/_ws.ts" ignore="README.md,GUIDE.md,.vercel/**,.wrangler/**,.output/**" expandAll -->🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@docs/4.examples/websocket.md` around lines 10 - 12, The docs code tree tag
automd:ui-code-tree is including generated deployment artifacts (.vercel,
.wrangler, etc.) from src="../../examples/websocket"; update the tag
configuration (the automd:ui-code-tree element that has default="routes/_ws.ts")
to add ignore patterns for generated/build output (e.g., .vercel, .wrangler,
dist, build, *.zip) so only source files are shown; modify the tag attributes to
include these ignores or an explicit include list of source folders to keep the
example focused on source files only.
| const format = async () => { | ||
| for (const message of store.messages) { | ||
| if (!message._fmt && message.text.startsWith("{")) { | ||
| message._fmt = true; | ||
| const { codeToHtml } = await import("https://esm.sh/shiki@1.0.0"); | ||
| const str = JSON.stringify(JSON.parse(message.text), null, 2); | ||
| message.formattedText = await codeToHtml(str, { | ||
| lang: "json", | ||
| theme: "dark-plus", | ||
| }); | ||
| } | ||
| } | ||
| }; |
There was a problem hiding this comment.
Guard JSON.parse in format() against user input.
message.text comes from chat messages, so any payload that starts with { but is not valid JSON will throw here and break the demo client. Wrap the parse/highlight path in a try/catch and fall back to plain text.
💡 Suggested change
const format = async () => {
for (const message of store.messages) {
if (!message._fmt && message.text.startsWith("{")) {
message._fmt = true;
- const { codeToHtml } = await import("https://esm.sh/shiki@1.0.0");
- const str = JSON.stringify(JSON.parse(message.text), null, 2);
- message.formattedText = await codeToHtml(str, {
- lang: "json",
- theme: "dark-plus",
- });
+ try {
+ const { codeToHtml } = await import("https://esm.sh/shiki@1.0.0");
+ const str = JSON.stringify(JSON.parse(message.text), null, 2);
+ message.formattedText = await codeToHtml(str, {
+ lang: "json",
+ theme: "dark-plus",
+ });
+ } catch {
+ message.formattedText = "";
+ }
}
}
};📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const format = async () => { | |
| for (const message of store.messages) { | |
| if (!message._fmt && message.text.startsWith("{")) { | |
| message._fmt = true; | |
| const { codeToHtml } = await import("https://esm.sh/shiki@1.0.0"); | |
| const str = JSON.stringify(JSON.parse(message.text), null, 2); | |
| message.formattedText = await codeToHtml(str, { | |
| lang: "json", | |
| theme: "dark-plus", | |
| }); | |
| } | |
| } | |
| }; | |
| const format = async () => { | |
| for (const message of store.messages) { | |
| if (!message._fmt && message.text.startsWith("{")) { | |
| message._fmt = true; | |
| try { | |
| const { codeToHtml } = await import("https://esm.sh/shiki@1.0.0"); | |
| const str = JSON.stringify(JSON.parse(message.text), null, 2); | |
| message.formattedText = await codeToHtml(str, { | |
| lang: "json", | |
| theme: "dark-plus", | |
| }); | |
| } catch { | |
| message.formattedText = ""; | |
| } | |
| } | |
| } | |
| }; |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@docs/4.examples/websocket.md` around lines 45 - 57, The format() function
currently calls JSON.parse on message.text (inside the loop over store.messages)
without guarding against invalid JSON which can throw and break the demo; wrap
the parse/highlight path in a try/catch around JSON.parse and the subsequent
codeToHtml call, set message._fmt = true only when processing succeeds, and on
error fall back to assigning message.formattedText to the original message.text
(or a safe escaped/plain version) so the client continues to work even for
non-JSON inputs.
| const connect = async () => { | ||
| const isSecure = location.protocol === "https:"; | ||
| const url = (isSecure ? "wss://" : "ws://") + location.host + "/_ws"; | ||
| if (ws) { | ||
| log("ws", "Closing previous connection before reconnecting..."); | ||
| ws.close(); | ||
| clear(); | ||
| } | ||
|
|
||
| log("ws", "Connecting to", url, "..."); | ||
| ws = new WebSocket(url); | ||
|
|
||
| ws.addEventListener("message", async (event) => { | ||
| let data = typeof event.data === "string" ? event.data : await event.data.text(); | ||
| const { user = "system", message = "" } = data.startsWith("{") | ||
| ? JSON.parse(data) | ||
| : { message: data }; | ||
| log(user, typeof message === "string" ? message : JSON.stringify(message)); | ||
| }); | ||
|
|
||
| await new Promise((resolve) => ws.addEventListener("open", resolve)); | ||
| log("ws", "Connected!"); | ||
| }; | ||
|
|
||
| const clear = () => { | ||
| store.messages.splice(0, store.messages.length); | ||
| log("system", "previous messages cleared"); | ||
| }; | ||
|
|
||
| const send = () => { | ||
| console.log("sending message..."); | ||
| if (store.message) { | ||
| ws.send(store.message); | ||
| } | ||
| store.message = ""; | ||
| }; | ||
|
|
||
| const ping = () => { | ||
| log("ws", "Sending ping"); | ||
| ws.send("ping"); |
There was a problem hiding this comment.
Handle failed connections and closed sockets before sending.
connect() only waits for "open", so a refused upgrade/network failure leaves the top-level await connect() hanging. send() and ping() also call ws.send(...) unconditionally, which will throw whenever the socket is still connecting or already closed.
💡 Suggested change
const connect = async () => {
const isSecure = location.protocol === "https:";
const url = (isSecure ? "wss://" : "ws://") + location.host + "/_ws";
if (ws) {
log("ws", "Closing previous connection before reconnecting...");
ws.close();
clear();
}
log("ws", "Connecting to", url, "...");
ws = new WebSocket(url);
ws.addEventListener("message", async (event) => {
let data = typeof event.data === "string" ? event.data : await event.data.text();
const { user = "system", message = "" } = data.startsWith("{")
? JSON.parse(data)
: { message: data };
log(user, typeof message === "string" ? message : JSON.stringify(message));
});
+ ws.addEventListener("close", () => {
+ log("ws", "Connection closed");
+ });
- await new Promise((resolve) => ws.addEventListener("open", resolve));
+ await new Promise((resolve, reject) => {
+ ws.addEventListener("open", resolve, { once: true });
+ ws.addEventListener("error", () => reject(new Error("WebSocket connection failed")), {
+ once: true,
+ });
+ });
log("ws", "Connected!");
};
const send = () => {
console.log("sending message...");
- if (store.message) {
+ if (store.message && ws?.readyState === WebSocket.OPEN) {
ws.send(store.message);
}
store.message = "";
};
const ping = () => {
log("ws", "Sending ping");
- ws.send("ping");
+ if (ws?.readyState === WebSocket.OPEN) {
+ ws.send("ping");
+ }
};🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@docs/4.examples/websocket.md` around lines 71 - 110, The connect() function
must reject/timeout on failed upgrades and not hang, and send() and ping() must
guard against calling ws.send when the socket is not OPEN; update connect to
race the "open" event with a timeout and listen for "error"/"close" to reject so
await connect() never hangs (reference connect and ws), and update send() and
ping() to check ws.readyState === WebSocket.OPEN before calling ws.send (or
attempt reconnect/return a logged error) and handle exceptions from ws.send;
also ensure any cleanup path (clear) closes and nulled-out ws so subsequent
operations detect the closed socket.
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@docs/index.md`:
- Line 68: The phrase 'zero config and locked-in' is ambiguous; update the
description field value to clearly state the absence of vendor lock-in (e.g.,
replace "zero config and locked-in" with "zero config and no vendor lock-in" or
"zero config and portable — no vendor lock-in") so the intent is explicit;
locate the description entry (the line starting with description:) in
docs/index.md and modify the string accordingly.
- Line 4: Update the description string that reads "Add server routes to your
application and deploy many hosting platform with a zero-config experience." by
inserting the missing word "to" before "many" and pluralizing "platform" to
"platforms" so it becomes "Add server routes to your application and deploy to
many hosting platforms with a zero-config experience."; apply the same
correction to the duplicate occurrence in the hero description (the identical
sentence on line 52).
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 9110b482-bbcc-4605-8512-34a2ad619c47
📒 Files selected for processing (2)
docs/.docs/components/AppHeroLinks.vuedocs/index.md
🚧 Files skipped from review as they are similar to previous changes (1)
- docs/.docs/components/AppHeroLinks.vue
| seo: | ||
| title: Ship Full-Stack Vite Apps | ||
| title: Build Full-Stack Servers | ||
| description: Nitro extends your Vite application with a production-ready server, compatible with any runtime. Add server routes to your application and deploy many hosting platform with a zero-config experience. |
There was a problem hiding this comment.
Fix grammatical errors in the description.
The description has two issues:
- Missing "to" before "many"
- "platform" should be plural "platforms"
The same text appears on line 52 in the hero description.
📝 Proposed fix
- description: Nitro extends your Vite application with a production-ready server, compatible with any runtime. Add server routes to your application and deploy many hosting platform with a zero-config experience.
+ description: Nitro extends your Vite application with a production-ready server, compatible with any runtime. Add server routes to your application and deploy to many hosting platforms with a zero-config experience.Apply the same fix to line 52.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| description: Nitro extends your Vite application with a production-ready server, compatible with any runtime. Add server routes to your application and deploy many hosting platform with a zero-config experience. | |
| description: Nitro extends your Vite application with a production-ready server, compatible with any runtime. Add server routes to your application and deploy to many hosting platforms with a zero-config experience. |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@docs/index.md` at line 4, Update the description string that reads "Add
server routes to your application and deploy many hosting platform with a
zero-config experience." by inserting the missing word "to" before "many" and
pluralizing "platform" to "platforms" so it becomes "Add server routes to your
application and deploy to many hosting platforms with a zero-config
experience."; apply the same correction to the duplicate occurrence in the hero
description (the identical sentence on line 52).
| bgColor: bg-amber-500/10 | ||
| borderColor: "group-hover:border-amber-500/30" | ||
| - title: Agnostic | ||
| description: Deploy the same codebase to any deployment provider with zero config and locked-in. |
There was a problem hiding this comment.
Clarify the "locked-in" wording.
The phrase "zero config and locked-in" is confusing. The intent appears to be highlighting the absence of vendor lock-in.
📝 Suggested rewording
- description: Deploy the same codebase to any deployment provider with zero config and locked-in.
+ description: Deploy the same codebase to any deployment provider with zero config and no lock-in.📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| description: Deploy the same codebase to any deployment provider with zero config and locked-in. | |
| description: Deploy the same codebase to any deployment provider with zero config and no lock-in. |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@docs/index.md` at line 68, The phrase 'zero config and locked-in' is
ambiguous; update the description field value to clearly state the absence of
vendor lock-in (e.g., replace "zero config and locked-in" with "zero config and
no vendor lock-in" or "zero config and portable — no vendor lock-in") so the
intent is explicit; locate the description entry (the line starting with
description:) in docs/index.md and modify the string accordingly.
No description provided.