Skip to content

fix: address vite doctor diagnostics#2261

Open
onmax wants to merge 7 commits into
nuxt:mainfrom
onmax:codex/vite-doctor-diagnostics
Open

fix: address vite doctor diagnostics#2261
onmax wants to merge 7 commits into
nuxt:mainfrom
onmax:codex/vite-doctor-diagnostics

Conversation

@onmax
Copy link
Copy Markdown
Contributor

@onmax onmax commented May 31, 2026

This is an experiment from running the Vite Doctor CLI against nuxt.com. The project rules are documented at https://vite-doctor.onmax.me/nuxt/rules.

I ran the CLI on origin/main and on this draft branch so maintainers can compare the before/after output below. More context for each change is in the individual commits.

Before: Vite Doctor on origin/main (0 blockers, 4 errors, 33 warnings, 50 info)
$ pnpm exec vite-doctor /tmp/nuxt-com-main-refresh.68ymqB --framework nuxt --no-cache

Detected: Nuxt 4.4.6 + Vue 3.5.34
Workspace: /tmp/nuxt-com-main-refresh.68ymqB
Health score: 28/100
Evidence used: manifest missing, route graph missing, build manifest missing, 0 prerender routes, 0 server routes
Confidence mix: 4 proven, 33 probable, 50 source-only

Errors
  [NUXT0060] useState() is serialized between server and client. Do not store functions, sockets, classes, Map/Set, or other non-serializable values.
  ├▶ fix: useState() is serialized between server and client. Do not store functions, sockets, classes, Map/Set, or other non-serializable values.
  ├▶ sources: https://nuxt.com/docs/4.x/api/composables/use-state
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NUXT0060
    rule: nuxt/state/no-nonserializable-usestate
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/composables/useDateRange.ts:9:21
  [NUXT0020] useFetch() is called after await in Nuxt context and may lose async context.
  ├▶ fix: Call Nuxt composables before the first await or use Nuxt's compiler-aware data factories.
  ├▶ sources: https://nuxt.com/docs/4.x/api/composables/use-nuxt-app
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NUXT0020
    rule: nuxt/context/no-composable-after-await
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/composables/useSponsors.ts:5:5
  [NUXT0020] useAsyncData() is called after await in Nuxt context and may lose async context.
  ├▶ fix: Call Nuxt composables before the first await or use Nuxt's compiler-aware data factories.
  ├▶ sources: https://nuxt.com/docs/4.x/api/composables/use-nuxt-app
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NUXT0020
    rule: nuxt/context/no-composable-after-await
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/composables/useSponsors.ts:6:5
  [NUXT0009] Images need alt text or an explicit empty alt for decorative images.
  ├▶ fix: Add alt text that describes the image.
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NUXT0009
    rule: nuxt-image/require-alt
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/pages/deploy/index.vue:65:15

Warnings
  [VUE0022] Native buttons should declare type="button", type="submit", or type="reset".
  ├▶ fix: Add type="button" unless this button intentionally submits a form.
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/VUE0022
    rule: vue/template/html-button-has-type
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/components/chat/ChatPanel.vue:126:13
  [VUE0020] This watcher reads DOM state before Vue has flushed owner DOM updates.
  ├▶ fix: Pass { flush: 'post' } or use watchPostEffect().
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/VUE0020
    rule: vue/watch/require-post-flush-for-dom-read
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/components/AdminDashboard.vue:319:1
  [VUE0020] This watcher reads DOM state before Vue has flushed owner DOM updates.
  ├▶ fix: Pass { flush: 'post' } or use watchPostEffect().
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/VUE0020
    rule: vue/watch/require-post-flush-for-dom-read
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/pages/modules/index.vue:90:1
  [VUE0015] Vue 3.5 supports reactive props destructure with native default values.
  ├▶ fix: Use const { prop = defaultValue } = defineProps<Props>().
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/VUE0015
    rule: vue/style/prefer-props-destructure-defaults
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/components/agent/AgentShader.vue:5:15
  [VUE0015] Vue 3.5 supports reactive props destructure with native default values.
  ├▶ fix: Use const { prop = defaultValue } = defineProps<Props>().
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/VUE0015
    rule: vue/style/prefer-props-destructure-defaults
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/components/content/VideoAccordion.vue:2:1
  [VUE0015] Vue 3.5 supports reactive props destructure with native default values.
  ├▶ fix: Use const { prop = defaultValue } = defineProps<Props>().
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/VUE0015
    rule: vue/style/prefer-props-destructure-defaults
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/components/EmptyCard.vue:2:1
  [VUE0015] Vue 3.5 supports reactive props destructure with native default values.
  ├▶ fix: Use const { prop = defaultValue } = defineProps<Props>().
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/VUE0015
    rule: vue/style/prefer-props-destructure-defaults
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/components/feedback/FeedbackStatCard.vue:17:1
  [VUE0015] Vue 3.5 supports reactive props destructure with native default values.
  ├▶ fix: Use const { prop = defaultValue } = defineProps<Props>().
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/VUE0015
    rule: vue/style/prefer-props-destructure-defaults
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/components/module/ModuleItem.vue:9:15
  [VUE0016] TypeScript <script setup> components should declare props with a type argument.
  ├▶ fix: Use defineProps<Props>() instead of a runtime props declaration.
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/VUE0016
    rule: vue/style/prefer-type-props
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/components/content/enterprise/support/EnterpriseSupportLogoCarousel.vue:11:19
  [VUE0016] TypeScript <script setup> components should declare props with a type argument.
  ├▶ fix: Use defineProps<Props>() instead of a runtime props declaration.
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/VUE0016
    rule: vue/style/prefer-type-props
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/components/content/ReadMore.vue:4:15
  [VUE0016] TypeScript <script setup> components should declare props with a type argument.
  ├▶ fix: Use defineProps<Props>() instead of a runtime props declaration.
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/VUE0016
    rule: vue/style/prefer-type-props
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/components/content/Sandbox.vue:15:15
  [VUE0016] TypeScript <script setup> components should declare props with a type argument.
  ├▶ fix: Use defineProps<Props>() instead of a runtime props declaration.
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/VUE0016
    rule: vue/style/prefer-type-props
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/components/module/ModuleProseA.vue:17:15
  [VUE0016] TypeScript <script setup> components should declare props with a type argument.
  ├▶ fix: Use defineProps<Props>() instead of a runtime props declaration.
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/VUE0016
    rule: vue/style/prefer-type-props
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/components/module/ModuleProseImg.vue:7:15
  [VUE0016] TypeScript <script setup> components should declare props with a type argument.
  ├▶ fix: Use defineProps<Props>() instead of a runtime props declaration.
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/VUE0016
    rule: vue/style/prefer-type-props
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/components/UInputCopy.vue:2:15
  [NITRO0011] $fetch() in Nitro handlers does not automatically carry request event context.
  ├▶ fix: Use event.$fetch() when proxying to other server routes.
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NITRO0011
    rule: nitro/server/prefer-event-fetch
    source: /tmp/nuxt-com-main-refresh.68ymqB/server/api/v1/teams/index.get.ts:5:5
  [NITRO0011] $fetch() in Nitro handlers does not automatically carry request event context.
  ├▶ fix: Use event.$fetch() when proxying to other server routes.
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NITRO0011
    rule: nitro/server/prefer-event-fetch
    source: /tmp/nuxt-com-main-refresh.68ymqB/server/api/v1/teams/index.get.ts:6:5
  [NITRO0011] $fetch() in Nitro handlers does not automatically carry request event context.
  ├▶ fix: Use event.$fetch() when proxying to other server routes.
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NITRO0011
    rule: nitro/server/prefer-event-fetch
    source: /tmp/nuxt-com-main-refresh.68ymqB/server/utils/team.ts:3:74
  [NITRO0008] Server handlers should read runtime config with the request event.
  ├▶ fix: Use useRuntimeConfig(event).
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NITRO0008
    rule: nitro/runtime/require-event-runtime-config-in-server
    source: /tmp/nuxt-com-main-refresh.68ymqB/server/utils/team.ts:20:15
  [NUXT0026] This fetch runs in setup for SSR-rendered data. Use useFetch() or useAsyncData() to avoid duplicate fetching and hydration issues.
  ├▶ fix: Replace with await useFetch(...) or await useAsyncData(key, () => $fetch(...)).
  ├▶ sources: https://nuxt.com/docs/4.x/getting-started/data-fetching
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NUXT0026
    rule: nuxt/fetch/no-raw-fetch-in-setup
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/components/PageHeaderLinks.vue:70:14
  [NUXT0026] This fetch runs in setup for SSR-rendered data. Use useFetch() or useAsyncData() to avoid duplicate fetching and hydration issues.
  ├▶ fix: Replace with await useFetch(...) or await useAsyncData(key, () => $fetch(...)).
  ├▶ sources: https://nuxt.com/docs/4.x/getting-started/data-fetching
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NUXT0026
    rule: nuxt/fetch/no-raw-fetch-in-setup
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/components/tools/FeedbackCard.vue:18:26
  [NUXT0039] `immediate: false` only disables initial execution. This async-data entry can still run from refreshNuxtData().
  ├▶ fix: Use async data for replay-safe reads, and keep one-shot actions outside Nuxt async-data entries.
  ├▶ sources: https://nuxt.com/docs/4.x/api/composables/use-fetch
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NUXT0039
    rule: nuxt/no-manual-action-usefetch
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/components/AdminMcpInstall.vue:4:42
  [NUXT0039] `immediate: false` only disables initial execution. This async-data entry can still run from refreshNuxtData().
  ├▶ fix: Use async data for replay-safe reads, and keep one-shot actions outside Nuxt async-data entries.
  ├▶ sources: https://nuxt.com/docs/4.x/api/composables/use-fetch
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NUXT0039
    rule: nuxt/no-manual-action-usefetch
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/composables/useEnterpriseAgencies.ts:6:39
  [NUXT0039] `immediate: false` only disables initial execution. This async-data entry can still run from refreshNuxtData().
  ├▶ fix: Use async data for replay-safe reads, and keep one-shot actions outside Nuxt async-data entries.
  ├▶ sources: https://nuxt.com/docs/4.x/api/composables/use-fetch
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NUXT0039
    rule: nuxt/no-manual-action-usefetch
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/composables/useEnterpriseJobs.ts:7:35
  [NUXT0039] `immediate: false` only disables initial execution. This async-data entry can still run from refreshNuxtData().
  ├▶ fix: Use async data for replay-safe reads, and keep one-shot actions outside Nuxt async-data entries.
  ├▶ sources: https://nuxt.com/docs/4.x/api/composables/use-fetch
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NUXT0039
    rule: nuxt/no-manual-action-usefetch
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/composables/useHostingProviders.ts:2:40
  [NUXT0039] `immediate: false` only disables initial execution. This async-data entry can still run from refreshNuxtData().
  ├▶ fix: Use async data for replay-safe reads, and keep one-shot actions outside Nuxt async-data entries.
  ├▶ sources: https://nuxt.com/docs/4.x/api/composables/use-fetch
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NUXT0039
    rule: nuxt/no-manual-action-usefetch
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/composables/useModules.ts:45:29
  [NUXT0028] This keyed composable relies on a generated location key.
  ├▶ fix: Pass an explicit stable key before the data handler when data may be shared, prerendered, or wrapped.
  ├▶ sources: https://nuxt.com/docs/4.x/api/composables/use-async-data
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NUXT0028
    rule: nuxt/fetch/require-stable-asyncdata-key
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/composables/useHostingProviders.ts:2:40
  [NUXT0023] SSR $fetch() to an internal API route may omit request cookies and auth headers.
  ├▶ fix: Use useFetch(), useRequestFetch(), or forward selected headers explicitly.
  ├▶ sources: https://nuxt.com/docs/4.x/api/composables/use-request-fetch
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NUXT0023
    rule: nuxt/fetch/forward-auth-headers-ssr
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/components/tools/FeedbackCard.vue:18:26
  [NUXT0023] SSR $fetch() to an internal API route may omit request cookies and auth headers.
  ├▶ fix: Use useFetch(), useRequestFetch(), or forward selected headers explicitly.
  ├▶ sources: https://nuxt.com/docs/4.x/api/composables/use-request-fetch
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NUXT0023
    rule: nuxt/fetch/forward-auth-headers-ssr
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/composables/useAgentChat.ts:93:5
  [NUXT0023] SSR $fetch() to an internal API route may omit request cookies and auth headers.
  ├▶ fix: Use useFetch(), useRequestFetch(), or forward selected headers explicitly.
  ├▶ sources: https://nuxt.com/docs/4.x/api/composables/use-request-fetch
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NUXT0023
    rule: nuxt/fetch/forward-auth-headers-ssr
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/composables/useFeedback.ts:239:13
  [NUXT0057] SEO metadata is safer and better typed through Nuxt SEO composables.
  ├▶ fix: Use useSeoMeta() for SEO metadata and useHeadSafe() for untrusted values.
  ├▶ sources: https://nuxt.com/docs/4.x/api/composables/use-seo-meta
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NUXT0057
    rule: nuxt/seo/prefer-seo-composables
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/app.vue:18:1
  [NUXT0057] SEO metadata is safer and better typed through Nuxt SEO composables.
  ├▶ fix: Use useSeoMeta() for SEO metadata and useHeadSafe() for untrusted values.
  ├▶ sources: https://nuxt.com/docs/4.x/api/composables/use-seo-meta
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NUXT0057
    rule: nuxt/seo/prefer-seo-composables
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/pages/chat.vue:10:1
  [NUXT0056] Head values derived from route, content, or user data should be constrained.
  ├▶ fix: Use useHeadSafe() or sanitize the value before passing it to useHead().
  ├▶ sources: https://nuxt.com/docs/4.x/api/composables/use-head-safe
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NUXT0056
    rule: nuxt/security/prefer-useheadsafe-for-untrusted-values
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/composables/useCanonical.ts:13:3
  [NUXT0008] Nuxt images should declare dimensions or responsive sizes.
  ├▶ fix: Add width/height for fixed images or sizes for responsive images.
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NUXT0008
    rule: nuxt-image/prefer-responsive-dimensions
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/pages/video-courses.vue:43:13

Info
  [VUE0023] Use Vue's same-name prop shorthand for message.
  ├▶ fix: Use :message.
  ├▶ sources: https://vuejs.org/guide/essentials/template-syntax.html#same-name-shorthand
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/VUE0023
    rule: vue/template/prefer-same-name-prop-shorthand
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/components/chat/ChatPanel.vue:162:30
  [VUE0023] Use Vue's same-name prop shorthand for message.
  ├▶ fix: Use :message.
  ├▶ sources: https://vuejs.org/guide/essentials/template-syntax.html#same-name-shorthand
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/VUE0023
    rule: vue/template/prefer-same-name-prop-shorthand
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/components/chat/ChatPanel.vue:168:19
  [VUE0023] Use Vue's same-name prop shorthand for open.
  ├▶ fix: Use :open.
  ├▶ sources: https://vuejs.org/guide/essentials/template-syntax.html#same-name-shorthand
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/VUE0023
    rule: vue/template/prefer-same-name-prop-shorthand
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/components/header/Header.vue:96:9
  [VUE0023] Use Vue's same-name prop shorthand for href.
  ├▶ fix: Use :href.
  ├▶ sources: https://vuejs.org/guide/essentials/template-syntax.html#same-name-shorthand
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/VUE0023
    rule: vue/template/prefer-same-name-prop-shorthand
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/components/module/ModuleProseA.vue:3:5
  [VUE0023] Use Vue's same-name prop shorthand for target.
  ├▶ fix: Use :target.
  ├▶ sources: https://vuejs.org/guide/essentials/template-syntax.html#same-name-shorthand
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/VUE0023
    rule: vue/template/prefer-same-name-prop-shorthand
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/components/module/ModuleProseA.vue:4:5
  [VUE0023] Use Vue's same-name prop shorthand for src.
  ├▶ fix: Use :src.
  ├▶ sources: https://vuejs.org/guide/essentials/template-syntax.html#same-name-shorthand
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/VUE0023
    rule: vue/template/prefer-same-name-prop-shorthand
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/components/module/ModuleProseImg.vue:34:5
  [VUE0023] Use Vue's same-name prop shorthand for alt.
  ├▶ fix: Use :alt.
  ├▶ sources: https://vuejs.org/guide/essentials/template-syntax.html#same-name-shorthand
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/VUE0023
    rule: vue/template/prefer-same-name-prop-shorthand
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/components/module/ModuleProseImg.vue:35:5
  [VUE0023] Use Vue's same-name prop shorthand for width.
  ├▶ fix: Use :width.
  ├▶ sources: https://vuejs.org/guide/essentials/template-syntax.html#same-name-shorthand
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/VUE0023
    rule: vue/template/prefer-same-name-prop-shorthand
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/components/module/ModuleProseImg.vue:36:5
  [VUE0023] Use Vue's same-name prop shorthand for height.
  ├▶ fix: Use :height.
  ├▶ sources: https://vuejs.org/guide/essentials/template-syntax.html#same-name-shorthand
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/VUE0023
    rule: vue/template/prefer-same-name-prop-shorthand
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/components/module/ModuleProseImg.vue:37:5
  [VUE0023] Use Vue's same-name prop shorthand for items.
  ├▶ fix: Use :items.
  ├▶ sources: https://vuejs.org/guide/essentials/template-syntax.html#same-name-shorthand
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/VUE0023
    rule: vue/template/prefer-same-name-prop-shorthand
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/components/PageHeaderLinks.vue:90:7
  [VUE0023] Use Vue's same-name prop shorthand for items.
  ├▶ fix: Use :items.
  ├▶ sources: https://vuejs.org/guide/essentials/template-syntax.html#same-name-shorthand
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/VUE0023
    rule: vue/template/prefer-same-name-prop-shorthand
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/components/VersionMenu.vue:11:5
  [VUE0023] Use Vue's same-name prop shorthand for title.
  ├▶ fix: Use :title.
  ├▶ sources: https://vuejs.org/guide/essentials/template-syntax.html#same-name-shorthand
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/VUE0023
    rule: vue/template/prefer-same-name-prop-shorthand
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/pages/enterprise/jobs.vue:35:7
  [VUE0023] Use Vue's same-name prop shorthand for description.
  ├▶ fix: Use :description.
  ├▶ sources: https://vuejs.org/guide/essentials/template-syntax.html#same-name-shorthand
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/VUE0023
    rule: vue/template/prefer-same-name-prop-shorthand
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/pages/enterprise/jobs.vue:36:7
  [VUE0023] Use Vue's same-name prop shorthand for title.
  ├▶ fix: Use :title.
  ├▶ sources: https://vuejs.org/guide/essentials/template-syntax.html#same-name-shorthand
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/VUE0023
    rule: vue/template/prefer-same-name-prop-shorthand
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/pages/enterprise/sponsors.vue:36:7
  [VUE0023] Use Vue's same-name prop shorthand for description.
  ├▶ fix: Use :description.
  ├▶ sources: https://vuejs.org/guide/essentials/template-syntax.html#same-name-shorthand
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/VUE0023
    rule: vue/template/prefer-same-name-prop-shorthand
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/pages/enterprise/sponsors.vue:37:7
  [VUE0023] Use Vue's same-name prop shorthand for key.
  ├▶ fix: Use :key.
  ├▶ sources: https://vuejs.org/guide/essentials/template-syntax.html#same-name-shorthand
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/VUE0023
    rule: vue/template/prefer-same-name-prop-shorthand
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/pages/enterprise/sponsors.vue:43:65
  [VUE0023] Use Vue's same-name prop shorthand for logo.
  ├▶ fix: Use :logo.
  ├▶ sources: https://vuejs.org/guide/essentials/template-syntax.html#same-name-shorthand
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/VUE0023
    rule: vue/template/prefer-same-name-prop-shorthand
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/pages/enterprise/support.vue:56:45
  [VUE0023] Use Vue's same-name prop shorthand for title.
  ├▶ fix: Use :title.
  ├▶ sources: https://vuejs.org/guide/essentials/template-syntax.html#same-name-shorthand
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/VUE0023
    rule: vue/template/prefer-same-name-prop-shorthand
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/pages/newsletter.vue:30:7
  [VUE0023] Use Vue's same-name prop shorthand for description.
  ├▶ fix: Use :description.
  ├▶ sources: https://vuejs.org/guide/essentials/template-syntax.html#same-name-shorthand
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/VUE0023
    rule: vue/template/prefer-same-name-prop-shorthand
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/pages/newsletter.vue:31:7
  [VUE0023] Use Vue's same-name prop shorthand for title.
  ├▶ fix: Use :title.
  ├▶ sources: https://vuejs.org/guide/essentials/template-syntax.html#same-name-shorthand
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/VUE0023
    rule: vue/template/prefer-same-name-prop-shorthand
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/pages/templates.vue:38:7
  [VUE0023] Use Vue's same-name prop shorthand for description.
  ├▶ fix: Use :description.
  ├▶ sources: https://vuejs.org/guide/essentials/template-syntax.html#same-name-shorthand
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/VUE0023
    rule: vue/template/prefer-same-name-prop-shorthand
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/pages/templates.vue:39:7
  [VUE0023] Use Vue's same-name prop shorthand for template.
  ├▶ fix: Use :template.
  ├▶ sources: https://vuejs.org/guide/essentials/template-syntax.html#same-name-shorthand
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/VUE0023
    rule: vue/template/prefer-same-name-prop-shorthand
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/pages/templates.vue:52:15
  [VUE0023] Use Vue's same-name prop shorthand for index.
  ├▶ fix: Use :index.
  ├▶ sources: https://vuejs.org/guide/essentials/template-syntax.html#same-name-shorthand
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/VUE0023
    rule: vue/template/prefer-same-name-prop-shorthand
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/pages/templates.vue:53:15
  [VUE0023] Use Vue's same-name prop shorthand for title.
  ├▶ fix: Use :title.
  ├▶ sources: https://vuejs.org/guide/essentials/template-syntax.html#same-name-shorthand
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/VUE0023
    rule: vue/template/prefer-same-name-prop-shorthand
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/pages/video-courses.vue:35:7
  [VUE0023] Use Vue's same-name prop shorthand for description.
  ├▶ fix: Use :description.
  ├▶ sources: https://vuejs.org/guide/essentials/template-syntax.html#same-name-shorthand
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/VUE0023
    rule: vue/template/prefer-same-name-prop-shorthand
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/pages/video-courses.vue:36:7
  [NUXT0027] Exported custom data composables should use Nuxt's compiler-aware data factories.
  ├▶ fix: Use createUseFetch() or createUseAsyncData() for reusable keyed data composables.
  ├▶ sources: https://nuxt.com/docs/4.x/api/composables/create-use-fetch
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NUXT0027
    rule: nuxt/fetch/prefer-create-use-fetch
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/composables/useBlog.ts:4:39
  [NUXT0027] Exported custom data composables should use Nuxt's compiler-aware data factories.
  ├▶ fix: Use createUseFetch() or createUseAsyncData() for reusable keyed data composables.
  ├▶ sources: https://nuxt.com/docs/4.x/api/composables/create-use-fetch
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NUXT0027
    rule: nuxt/fetch/prefer-create-use-fetch
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/composables/useDocsVersion.ts:54:26
  [NUXT0027] Exported custom data composables should use Nuxt's compiler-aware data factories.
  ├▶ fix: Use createUseFetch() or createUseAsyncData() for reusable keyed data composables.
  ├▶ sources: https://nuxt.com/docs/4.x/api/composables/create-use-fetch
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NUXT0027
    rule: nuxt/fetch/prefer-create-use-fetch
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/composables/useEnterpriseAgencies.ts:6:39
  [NUXT0027] Exported custom data composables should use Nuxt's compiler-aware data factories.
  ├▶ fix: Use createUseFetch() or createUseAsyncData() for reusable keyed data composables.
  ├▶ sources: https://nuxt.com/docs/4.x/api/composables/create-use-fetch
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NUXT0027
    rule: nuxt/fetch/prefer-create-use-fetch
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/composables/useEnterpriseJobs.ts:7:35
  [NUXT0027] Exported custom data composables should use Nuxt's compiler-aware data factories.
  ├▶ fix: Use createUseFetch() or createUseAsyncData() for reusable keyed data composables.
  ├▶ sources: https://nuxt.com/docs/4.x/api/composables/create-use-fetch
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NUXT0027
    rule: nuxt/fetch/prefer-create-use-fetch
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/composables/useHostingProviders.ts:2:40
  [NUXT0027] Exported custom data composables should use Nuxt's compiler-aware data factories.
  ├▶ fix: Use createUseFetch() or createUseAsyncData() for reusable keyed data composables.
  ├▶ sources: https://nuxt.com/docs/4.x/api/composables/create-use-fetch
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NUXT0027
    rule: nuxt/fetch/prefer-create-use-fetch
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/composables/useModules.ts:45:29
  [NUXT0027] Exported custom data composables should use Nuxt's compiler-aware data factories.
  ├▶ fix: Use createUseFetch() or createUseAsyncData() for reusable keyed data composables.
  ├▶ sources: https://nuxt.com/docs/4.x/api/composables/create-use-fetch
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NUXT0027
    rule: nuxt/fetch/prefer-create-use-fetch
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/composables/useSponsors.ts:5:5
  [NUXT0013] Native <button> reimplements behavior that Nuxt UI already provides.
  ├▶ fix: Use <UButton> and map styling to Nuxt UI props such as icon, size, color, and variant.
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NUXT0013
    rule: nuxt-ui/prefer-u-button
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/components/chat/ChatPanel.vue:126:13
  [NUXT0068] setTimeout is easier to clean up through a composable.
  ├▶ fix: Use VueUse useTimeoutFn() for lifecycle-aware timing.
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NUXT0068
    rule: vueuse/prefer-use-timers
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/components/ads/AdsMN.vue:12:3
  [NUXT0068] setInterval is easier to clean up through a composable.
  ├▶ fix: Use VueUse useIntervalFn() for lifecycle-aware timing.
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NUXT0068
    rule: vueuse/prefer-use-timers
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/components/ads/AdsMN.vue:28:14
  [NUXT0068] setTimeout is easier to clean up through a composable.
  ├▶ fix: Use VueUse useTimeoutFn() for lifecycle-aware timing.
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NUXT0068
    rule: vueuse/prefer-use-timers
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/components/ads/AdsNuxtCertificate.vue:12:3
  [NUXT0068] setInterval is easier to clean up through a composable.
  ├▶ fix: Use VueUse useIntervalFn() for lifecycle-aware timing.
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NUXT0068
    rule: vueuse/prefer-use-timers
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/components/ads/AdsNuxtCertificate.vue:28:14
  [NUXT0068] setTimeout is easier to clean up through a composable.
  ├▶ fix: Use VueUse useTimeoutFn() for lifecycle-aware timing.
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NUXT0068
    rule: vueuse/prefer-use-timers
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/components/agent/AgentFloatingInput.vue:26:17
  [NUXT0068] requestAnimationFrame is easier to clean up through a composable.
  ├▶ fix: Use VueUse useRafFn() for lifecycle-aware timing.
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NUXT0068
    rule: vueuse/prefer-use-timers
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/components/agent/AgentIndicator.vue:63:7
  [NUXT0068] setInterval is easier to clean up through a composable.
  ├▶ fix: Use VueUse useIntervalFn() for lifecycle-aware timing.
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NUXT0068
    rule: vueuse/prefer-use-timers
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/components/agent/AgentIndicator.vue:77:20
  [NUXT0068] setTimeout is easier to clean up through a composable.
  ├▶ fix: Use VueUse useTimeoutFn() for lifecycle-aware timing.
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NUXT0068
    rule: vueuse/prefer-use-timers
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/components/home/HomeSectionContributors.vue:36:20
  [NUXT0068] setTimeout is easier to clean up through a composable.
  ├▶ fix: Use VueUse useTimeoutFn() for lifecycle-aware timing.
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NUXT0068
    rule: vueuse/prefer-use-timers
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/composables/useFeedback.ts:244:36
  [NUXT0068] setTimeout is easier to clean up through a composable.
  ├▶ fix: Use VueUse useTimeoutFn() for lifecycle-aware timing.
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NUXT0068
    rule: vueuse/prefer-use-timers
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/layouts/default.vue:9:3
  [NUXT0068] setTimeout is easier to clean up through a composable.
  ├▶ fix: Use VueUse useTimeoutFn() for lifecycle-aware timing.
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NUXT0068
    rule: vueuse/prefer-use-timers
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/pages/docs/[...slug].vue:49:5
  [NUXT0068] requestAnimationFrame is easier to clean up through a composable.
  ├▶ fix: Use VueUse useRafFn() for lifecycle-aware timing.
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NUXT0068
    rule: vueuse/prefer-use-timers
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/pages/docs/[...slug].vue:50:5
  [NUXT0068] setTimeout is easier to clean up through a composable.
  ├▶ fix: Use VueUse useTimeoutFn() for lifecycle-aware timing.
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NUXT0068
    rule: vueuse/prefer-use-timers
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/pages/modules/index.vue:74:3
  [NUXT0006] Raw <img> misses Nuxt Image optimization and responsive providers.
  ├▶ fix: Use <NuxtImg> for application images.
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NUXT0006
    rule: nuxt-image/prefer-nuxtimg
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/components/ads/AdsFreeWeekend.vue:9:7
  [NUXT0006] Raw <img> misses Nuxt Image optimization and responsive providers.
  ├▶ fix: Use <NuxtImg> for application images.
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NUXT0006
    rule: nuxt-image/prefer-nuxtimg
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/components/module/ModuleProseImg.vue:33:3
  [NUXT0007] Format negotiation is clearer with <NuxtPicture>.
  ├▶ fix: Use <NuxtPicture> when serving modern formats with fallbacks.
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NUXT0007
    rule: nuxt-image/prefer-nuxtpicture-for-formats
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/pages/showcase.vue:116:15
  [NUXT0007] Format negotiation is clearer with <NuxtPicture>.
  ├▶ fix: Use <NuxtPicture> when serving modern formats with fallbacks.
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NUXT0007
    rule: nuxt-image/prefer-nuxtpicture-for-formats
    source: /tmp/nuxt-com-main-refresh.68ymqB/app/pages/video-courses.vue:43:13

Summary
  0 blockers, 4 errors, 33 warnings, 50 info
  0 safe fixes available

Graph
  341 files, 596 imports, 241 exports, 309 roots, 0 cycles
After: Vite Doctor on this draft branch (0 blockers, 0 errors, 24 warnings, 50 info)
$ pnpm exec vite-doctor /tmp/nuxt-com-browser-test.ujXeyY --framework nuxt --no-cache

Detected: Nuxt 4.4.6 + Vue 3.5.34
Workspace: /tmp/nuxt-com-browser-test.ujXeyY
Health score: 65/100
Evidence used: manifest missing, route graph missing, build manifest missing, 0 prerender routes, 0 server routes
Confidence mix: 0 proven, 24 probable, 50 source-only

Warnings
  [VUE0015] Vue 3.5 supports reactive props destructure with native default values.
  ├▶ fix: Use const { prop = defaultValue } = defineProps<Props>().
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/VUE0015
    rule: vue/style/prefer-props-destructure-defaults
    source: /tmp/nuxt-com-browser-test.ujXeyY/app/components/agent/AgentShader.vue:5:15
  [VUE0015] Vue 3.5 supports reactive props destructure with native default values.
  ├▶ fix: Use const { prop = defaultValue } = defineProps<Props>().
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/VUE0015
    rule: vue/style/prefer-props-destructure-defaults
    source: /tmp/nuxt-com-browser-test.ujXeyY/app/components/content/VideoAccordion.vue:2:1
  [VUE0015] Vue 3.5 supports reactive props destructure with native default values.
  ├▶ fix: Use const { prop = defaultValue } = defineProps<Props>().
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/VUE0015
    rule: vue/style/prefer-props-destructure-defaults
    source: /tmp/nuxt-com-browser-test.ujXeyY/app/components/EmptyCard.vue:2:1
  [VUE0015] Vue 3.5 supports reactive props destructure with native default values.
  ├▶ fix: Use const { prop = defaultValue } = defineProps<Props>().
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/VUE0015
    rule: vue/style/prefer-props-destructure-defaults
    source: /tmp/nuxt-com-browser-test.ujXeyY/app/components/feedback/FeedbackStatCard.vue:17:1
  [VUE0015] Vue 3.5 supports reactive props destructure with native default values.
  ├▶ fix: Use const { prop = defaultValue } = defineProps<Props>().
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/VUE0015
    rule: vue/style/prefer-props-destructure-defaults
    source: /tmp/nuxt-com-browser-test.ujXeyY/app/components/module/ModuleItem.vue:9:15
  [VUE0016] TypeScript <script setup> components should declare props with a type argument.
  ├▶ fix: Use defineProps<Props>() instead of a runtime props declaration.
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/VUE0016
    rule: vue/style/prefer-type-props
    source: /tmp/nuxt-com-browser-test.ujXeyY/app/components/content/enterprise/support/EnterpriseSupportLogoCarousel.vue:11:19
  [VUE0016] TypeScript <script setup> components should declare props with a type argument.
  ├▶ fix: Use defineProps<Props>() instead of a runtime props declaration.
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/VUE0016
    rule: vue/style/prefer-type-props
    source: /tmp/nuxt-com-browser-test.ujXeyY/app/components/content/ReadMore.vue:4:15
  [VUE0016] TypeScript <script setup> components should declare props with a type argument.
  ├▶ fix: Use defineProps<Props>() instead of a runtime props declaration.
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/VUE0016
    rule: vue/style/prefer-type-props
    source: /tmp/nuxt-com-browser-test.ujXeyY/app/components/content/Sandbox.vue:15:15
  [VUE0016] TypeScript <script setup> components should declare props with a type argument.
  ├▶ fix: Use defineProps<Props>() instead of a runtime props declaration.
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/VUE0016
    rule: vue/style/prefer-type-props
    source: /tmp/nuxt-com-browser-test.ujXeyY/app/components/module/ModuleProseA.vue:17:15
  [VUE0016] TypeScript <script setup> components should declare props with a type argument.
  ├▶ fix: Use defineProps<Props>() instead of a runtime props declaration.
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/VUE0016
    rule: vue/style/prefer-type-props
    source: /tmp/nuxt-com-browser-test.ujXeyY/app/components/module/ModuleProseImg.vue:7:15
  [VUE0016] TypeScript <script setup> components should declare props with a type argument.
  ├▶ fix: Use defineProps<Props>() instead of a runtime props declaration.
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/VUE0016
    rule: vue/style/prefer-type-props
    source: /tmp/nuxt-com-browser-test.ujXeyY/app/components/UInputCopy.vue:2:15
  [NUXT0026] This fetch runs in setup for SSR-rendered data. Use useFetch() or useAsyncData() to avoid duplicate fetching and hydration issues.
  ├▶ fix: Replace with await useFetch(...) or await useAsyncData(key, () => $fetch(...)).
  ├▶ sources: https://nuxt.com/docs/4.x/getting-started/data-fetching
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NUXT0026
    rule: nuxt/fetch/no-raw-fetch-in-setup
    source: /tmp/nuxt-com-browser-test.ujXeyY/app/components/PageHeaderLinks.vue:70:14
  [NUXT0026] This fetch runs in setup for SSR-rendered data. Use useFetch() or useAsyncData() to avoid duplicate fetching and hydration issues.
  ├▶ fix: Replace with await useFetch(...) or await useAsyncData(key, () => $fetch(...)).
  ├▶ sources: https://nuxt.com/docs/4.x/getting-started/data-fetching
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NUXT0026
    rule: nuxt/fetch/no-raw-fetch-in-setup
    source: /tmp/nuxt-com-browser-test.ujXeyY/app/components/tools/FeedbackCard.vue:18:26
  [NUXT0039] `immediate: false` only disables initial execution. This async-data entry can still run from refreshNuxtData().
  ├▶ fix: Use async data for replay-safe reads, and keep one-shot actions outside Nuxt async-data entries.
  ├▶ sources: https://nuxt.com/docs/4.x/api/composables/use-fetch
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NUXT0039
    rule: nuxt/no-manual-action-usefetch
    source: /tmp/nuxt-com-browser-test.ujXeyY/app/components/AdminMcpInstall.vue:4:42
  [NUXT0039] `immediate: false` only disables initial execution. This async-data entry can still run from refreshNuxtData().
  ├▶ fix: Use async data for replay-safe reads, and keep one-shot actions outside Nuxt async-data entries.
  ├▶ sources: https://nuxt.com/docs/4.x/api/composables/use-fetch
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NUXT0039
    rule: nuxt/no-manual-action-usefetch
    source: /tmp/nuxt-com-browser-test.ujXeyY/app/composables/useEnterpriseAgencies.ts:6:39
  [NUXT0039] `immediate: false` only disables initial execution. This async-data entry can still run from refreshNuxtData().
  ├▶ fix: Use async data for replay-safe reads, and keep one-shot actions outside Nuxt async-data entries.
  ├▶ sources: https://nuxt.com/docs/4.x/api/composables/use-fetch
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NUXT0039
    rule: nuxt/no-manual-action-usefetch
    source: /tmp/nuxt-com-browser-test.ujXeyY/app/composables/useEnterpriseJobs.ts:7:35
  [NUXT0039] `immediate: false` only disables initial execution. This async-data entry can still run from refreshNuxtData().
  ├▶ fix: Use async data for replay-safe reads, and keep one-shot actions outside Nuxt async-data entries.
  ├▶ sources: https://nuxt.com/docs/4.x/api/composables/use-fetch
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NUXT0039
    rule: nuxt/no-manual-action-usefetch
    source: /tmp/nuxt-com-browser-test.ujXeyY/app/composables/useHostingProviders.ts:2:40
  [NUXT0039] `immediate: false` only disables initial execution. This async-data entry can still run from refreshNuxtData().
  ├▶ fix: Use async data for replay-safe reads, and keep one-shot actions outside Nuxt async-data entries.
  ├▶ sources: https://nuxt.com/docs/4.x/api/composables/use-fetch
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NUXT0039
    rule: nuxt/no-manual-action-usefetch
    source: /tmp/nuxt-com-browser-test.ujXeyY/app/composables/useModules.ts:45:29
  [NUXT0028] This keyed composable relies on a generated location key.
  ├▶ fix: Pass an explicit stable key before the data handler when data may be shared, prerendered, or wrapped.
  ├▶ sources: https://nuxt.com/docs/4.x/api/composables/use-async-data
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NUXT0028
    rule: nuxt/fetch/require-stable-asyncdata-key
    source: /tmp/nuxt-com-browser-test.ujXeyY/app/composables/useHostingProviders.ts:2:40
  [NUXT0023] SSR $fetch() to an internal API route may omit request cookies and auth headers.
  ├▶ fix: Use useFetch(), useRequestFetch(), or forward selected headers explicitly.
  ├▶ sources: https://nuxt.com/docs/4.x/api/composables/use-request-fetch
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NUXT0023
    rule: nuxt/fetch/forward-auth-headers-ssr
    source: /tmp/nuxt-com-browser-test.ujXeyY/app/components/tools/FeedbackCard.vue:18:26
  [NUXT0023] SSR $fetch() to an internal API route may omit request cookies and auth headers.
  ├▶ fix: Use useFetch(), useRequestFetch(), or forward selected headers explicitly.
  ├▶ sources: https://nuxt.com/docs/4.x/api/composables/use-request-fetch
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NUXT0023
    rule: nuxt/fetch/forward-auth-headers-ssr
    source: /tmp/nuxt-com-browser-test.ujXeyY/app/composables/useAgentChat.ts:93:5
  [NUXT0023] SSR $fetch() to an internal API route may omit request cookies and auth headers.
  ├▶ fix: Use useFetch(), useRequestFetch(), or forward selected headers explicitly.
  ├▶ sources: https://nuxt.com/docs/4.x/api/composables/use-request-fetch
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NUXT0023
    rule: nuxt/fetch/forward-auth-headers-ssr
    source: /tmp/nuxt-com-browser-test.ujXeyY/app/composables/useFeedback.ts:239:13
  [NUXT0057] SEO metadata is safer and better typed through Nuxt SEO composables.
  ├▶ fix: Use useSeoMeta() for SEO metadata and useHeadSafe() for untrusted values.
  ├▶ sources: https://nuxt.com/docs/4.x/api/composables/use-seo-meta
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NUXT0057
    rule: nuxt/seo/prefer-seo-composables
    source: /tmp/nuxt-com-browser-test.ujXeyY/app/app.vue:18:1
  [NUXT0057] SEO metadata is safer and better typed through Nuxt SEO composables.
  ├▶ fix: Use useSeoMeta() for SEO metadata and useHeadSafe() for untrusted values.
  ├▶ sources: https://nuxt.com/docs/4.x/api/composables/use-seo-meta
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NUXT0057
    rule: nuxt/seo/prefer-seo-composables
    source: /tmp/nuxt-com-browser-test.ujXeyY/app/pages/chat.vue:10:1

Info
  [VUE0023] Use Vue's same-name prop shorthand for message.
  ├▶ fix: Use :message.
  ├▶ sources: https://vuejs.org/guide/essentials/template-syntax.html#same-name-shorthand
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/VUE0023
    rule: vue/template/prefer-same-name-prop-shorthand
    source: /tmp/nuxt-com-browser-test.ujXeyY/app/components/chat/ChatPanel.vue:163:30
  [VUE0023] Use Vue's same-name prop shorthand for message.
  ├▶ fix: Use :message.
  ├▶ sources: https://vuejs.org/guide/essentials/template-syntax.html#same-name-shorthand
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/VUE0023
    rule: vue/template/prefer-same-name-prop-shorthand
    source: /tmp/nuxt-com-browser-test.ujXeyY/app/components/chat/ChatPanel.vue:169:19
  [VUE0023] Use Vue's same-name prop shorthand for open.
  ├▶ fix: Use :open.
  ├▶ sources: https://vuejs.org/guide/essentials/template-syntax.html#same-name-shorthand
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/VUE0023
    rule: vue/template/prefer-same-name-prop-shorthand
    source: /tmp/nuxt-com-browser-test.ujXeyY/app/components/header/Header.vue:96:9
  [VUE0023] Use Vue's same-name prop shorthand for href.
  ├▶ fix: Use :href.
  ├▶ sources: https://vuejs.org/guide/essentials/template-syntax.html#same-name-shorthand
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/VUE0023
    rule: vue/template/prefer-same-name-prop-shorthand
    source: /tmp/nuxt-com-browser-test.ujXeyY/app/components/module/ModuleProseA.vue:3:5
  [VUE0023] Use Vue's same-name prop shorthand for target.
  ├▶ fix: Use :target.
  ├▶ sources: https://vuejs.org/guide/essentials/template-syntax.html#same-name-shorthand
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/VUE0023
    rule: vue/template/prefer-same-name-prop-shorthand
    source: /tmp/nuxt-com-browser-test.ujXeyY/app/components/module/ModuleProseA.vue:4:5
  [VUE0023] Use Vue's same-name prop shorthand for src.
  ├▶ fix: Use :src.
  ├▶ sources: https://vuejs.org/guide/essentials/template-syntax.html#same-name-shorthand
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/VUE0023
    rule: vue/template/prefer-same-name-prop-shorthand
    source: /tmp/nuxt-com-browser-test.ujXeyY/app/components/module/ModuleProseImg.vue:34:5
  [VUE0023] Use Vue's same-name prop shorthand for alt.
  ├▶ fix: Use :alt.
  ├▶ sources: https://vuejs.org/guide/essentials/template-syntax.html#same-name-shorthand
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/VUE0023
    rule: vue/template/prefer-same-name-prop-shorthand
    source: /tmp/nuxt-com-browser-test.ujXeyY/app/components/module/ModuleProseImg.vue:35:5
  [VUE0023] Use Vue's same-name prop shorthand for width.
  ├▶ fix: Use :width.
  ├▶ sources: https://vuejs.org/guide/essentials/template-syntax.html#same-name-shorthand
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/VUE0023
    rule: vue/template/prefer-same-name-prop-shorthand
    source: /tmp/nuxt-com-browser-test.ujXeyY/app/components/module/ModuleProseImg.vue:36:5
  [VUE0023] Use Vue's same-name prop shorthand for height.
  ├▶ fix: Use :height.
  ├▶ sources: https://vuejs.org/guide/essentials/template-syntax.html#same-name-shorthand
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/VUE0023
    rule: vue/template/prefer-same-name-prop-shorthand
    source: /tmp/nuxt-com-browser-test.ujXeyY/app/components/module/ModuleProseImg.vue:37:5
  [VUE0023] Use Vue's same-name prop shorthand for items.
  ├▶ fix: Use :items.
  ├▶ sources: https://vuejs.org/guide/essentials/template-syntax.html#same-name-shorthand
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/VUE0023
    rule: vue/template/prefer-same-name-prop-shorthand
    source: /tmp/nuxt-com-browser-test.ujXeyY/app/components/PageHeaderLinks.vue:90:7
  [VUE0023] Use Vue's same-name prop shorthand for items.
  ├▶ fix: Use :items.
  ├▶ sources: https://vuejs.org/guide/essentials/template-syntax.html#same-name-shorthand
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/VUE0023
    rule: vue/template/prefer-same-name-prop-shorthand
    source: /tmp/nuxt-com-browser-test.ujXeyY/app/components/VersionMenu.vue:11:5
  [VUE0023] Use Vue's same-name prop shorthand for title.
  ├▶ fix: Use :title.
  ├▶ sources: https://vuejs.org/guide/essentials/template-syntax.html#same-name-shorthand
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/VUE0023
    rule: vue/template/prefer-same-name-prop-shorthand
    source: /tmp/nuxt-com-browser-test.ujXeyY/app/pages/enterprise/jobs.vue:35:7
  [VUE0023] Use Vue's same-name prop shorthand for description.
  ├▶ fix: Use :description.
  ├▶ sources: https://vuejs.org/guide/essentials/template-syntax.html#same-name-shorthand
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/VUE0023
    rule: vue/template/prefer-same-name-prop-shorthand
    source: /tmp/nuxt-com-browser-test.ujXeyY/app/pages/enterprise/jobs.vue:36:7
  [VUE0023] Use Vue's same-name prop shorthand for title.
  ├▶ fix: Use :title.
  ├▶ sources: https://vuejs.org/guide/essentials/template-syntax.html#same-name-shorthand
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/VUE0023
    rule: vue/template/prefer-same-name-prop-shorthand
    source: /tmp/nuxt-com-browser-test.ujXeyY/app/pages/enterprise/sponsors.vue:36:7
  [VUE0023] Use Vue's same-name prop shorthand for description.
  ├▶ fix: Use :description.
  ├▶ sources: https://vuejs.org/guide/essentials/template-syntax.html#same-name-shorthand
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/VUE0023
    rule: vue/template/prefer-same-name-prop-shorthand
    source: /tmp/nuxt-com-browser-test.ujXeyY/app/pages/enterprise/sponsors.vue:37:7
  [VUE0023] Use Vue's same-name prop shorthand for key.
  ├▶ fix: Use :key.
  ├▶ sources: https://vuejs.org/guide/essentials/template-syntax.html#same-name-shorthand
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/VUE0023
    rule: vue/template/prefer-same-name-prop-shorthand
    source: /tmp/nuxt-com-browser-test.ujXeyY/app/pages/enterprise/sponsors.vue:43:65
  [VUE0023] Use Vue's same-name prop shorthand for logo.
  ├▶ fix: Use :logo.
  ├▶ sources: https://vuejs.org/guide/essentials/template-syntax.html#same-name-shorthand
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/VUE0023
    rule: vue/template/prefer-same-name-prop-shorthand
    source: /tmp/nuxt-com-browser-test.ujXeyY/app/pages/enterprise/support.vue:56:45
  [VUE0023] Use Vue's same-name prop shorthand for title.
  ├▶ fix: Use :title.
  ├▶ sources: https://vuejs.org/guide/essentials/template-syntax.html#same-name-shorthand
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/VUE0023
    rule: vue/template/prefer-same-name-prop-shorthand
    source: /tmp/nuxt-com-browser-test.ujXeyY/app/pages/newsletter.vue:30:7
  [VUE0023] Use Vue's same-name prop shorthand for description.
  ├▶ fix: Use :description.
  ├▶ sources: https://vuejs.org/guide/essentials/template-syntax.html#same-name-shorthand
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/VUE0023
    rule: vue/template/prefer-same-name-prop-shorthand
    source: /tmp/nuxt-com-browser-test.ujXeyY/app/pages/newsletter.vue:31:7
  [VUE0023] Use Vue's same-name prop shorthand for title.
  ├▶ fix: Use :title.
  ├▶ sources: https://vuejs.org/guide/essentials/template-syntax.html#same-name-shorthand
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/VUE0023
    rule: vue/template/prefer-same-name-prop-shorthand
    source: /tmp/nuxt-com-browser-test.ujXeyY/app/pages/templates.vue:38:7
  [VUE0023] Use Vue's same-name prop shorthand for description.
  ├▶ fix: Use :description.
  ├▶ sources: https://vuejs.org/guide/essentials/template-syntax.html#same-name-shorthand
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/VUE0023
    rule: vue/template/prefer-same-name-prop-shorthand
    source: /tmp/nuxt-com-browser-test.ujXeyY/app/pages/templates.vue:39:7
  [VUE0023] Use Vue's same-name prop shorthand for template.
  ├▶ fix: Use :template.
  ├▶ sources: https://vuejs.org/guide/essentials/template-syntax.html#same-name-shorthand
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/VUE0023
    rule: vue/template/prefer-same-name-prop-shorthand
    source: /tmp/nuxt-com-browser-test.ujXeyY/app/pages/templates.vue:52:15
  [VUE0023] Use Vue's same-name prop shorthand for index.
  ├▶ fix: Use :index.
  ├▶ sources: https://vuejs.org/guide/essentials/template-syntax.html#same-name-shorthand
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/VUE0023
    rule: vue/template/prefer-same-name-prop-shorthand
    source: /tmp/nuxt-com-browser-test.ujXeyY/app/pages/templates.vue:53:15
  [VUE0023] Use Vue's same-name prop shorthand for title.
  ├▶ fix: Use :title.
  ├▶ sources: https://vuejs.org/guide/essentials/template-syntax.html#same-name-shorthand
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/VUE0023
    rule: vue/template/prefer-same-name-prop-shorthand
    source: /tmp/nuxt-com-browser-test.ujXeyY/app/pages/video-courses.vue:35:7
  [VUE0023] Use Vue's same-name prop shorthand for description.
  ├▶ fix: Use :description.
  ├▶ sources: https://vuejs.org/guide/essentials/template-syntax.html#same-name-shorthand
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/VUE0023
    rule: vue/template/prefer-same-name-prop-shorthand
    source: /tmp/nuxt-com-browser-test.ujXeyY/app/pages/video-courses.vue:36:7
  [NUXT0027] Exported custom data composables should use Nuxt's compiler-aware data factories.
  ├▶ fix: Use createUseFetch() or createUseAsyncData() for reusable keyed data composables.
  ├▶ sources: https://nuxt.com/docs/4.x/api/composables/create-use-fetch
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NUXT0027
    rule: nuxt/fetch/prefer-create-use-fetch
    source: /tmp/nuxt-com-browser-test.ujXeyY/app/composables/useBlog.ts:4:39
  [NUXT0027] Exported custom data composables should use Nuxt's compiler-aware data factories.
  ├▶ fix: Use createUseFetch() or createUseAsyncData() for reusable keyed data composables.
  ├▶ sources: https://nuxt.com/docs/4.x/api/composables/create-use-fetch
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NUXT0027
    rule: nuxt/fetch/prefer-create-use-fetch
    source: /tmp/nuxt-com-browser-test.ujXeyY/app/composables/useDocsVersion.ts:54:26
  [NUXT0027] Exported custom data composables should use Nuxt's compiler-aware data factories.
  ├▶ fix: Use createUseFetch() or createUseAsyncData() for reusable keyed data composables.
  ├▶ sources: https://nuxt.com/docs/4.x/api/composables/create-use-fetch
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NUXT0027
    rule: nuxt/fetch/prefer-create-use-fetch
    source: /tmp/nuxt-com-browser-test.ujXeyY/app/composables/useEnterpriseAgencies.ts:6:39
  [NUXT0027] Exported custom data composables should use Nuxt's compiler-aware data factories.
  ├▶ fix: Use createUseFetch() or createUseAsyncData() for reusable keyed data composables.
  ├▶ sources: https://nuxt.com/docs/4.x/api/composables/create-use-fetch
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NUXT0027
    rule: nuxt/fetch/prefer-create-use-fetch
    source: /tmp/nuxt-com-browser-test.ujXeyY/app/composables/useEnterpriseJobs.ts:7:35
  [NUXT0027] Exported custom data composables should use Nuxt's compiler-aware data factories.
  ├▶ fix: Use createUseFetch() or createUseAsyncData() for reusable keyed data composables.
  ├▶ sources: https://nuxt.com/docs/4.x/api/composables/create-use-fetch
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NUXT0027
    rule: nuxt/fetch/prefer-create-use-fetch
    source: /tmp/nuxt-com-browser-test.ujXeyY/app/composables/useHostingProviders.ts:2:40
  [NUXT0027] Exported custom data composables should use Nuxt's compiler-aware data factories.
  ├▶ fix: Use createUseFetch() or createUseAsyncData() for reusable keyed data composables.
  ├▶ sources: https://nuxt.com/docs/4.x/api/composables/create-use-fetch
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NUXT0027
    rule: nuxt/fetch/prefer-create-use-fetch
    source: /tmp/nuxt-com-browser-test.ujXeyY/app/composables/useModules.ts:45:29
  [NUXT0027] Exported custom data composables should use Nuxt's compiler-aware data factories.
  ├▶ fix: Use createUseFetch() or createUseAsyncData() for reusable keyed data composables.
  ├▶ sources: https://nuxt.com/docs/4.x/api/composables/create-use-fetch
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NUXT0027
    rule: nuxt/fetch/prefer-create-use-fetch
    source: /tmp/nuxt-com-browser-test.ujXeyY/app/composables/useSponsors.ts:4:33
  [NUXT0013] Native <button> reimplements behavior that Nuxt UI already provides.
  ├▶ fix: Use <UButton> and map styling to Nuxt UI props such as icon, size, color, and variant.
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NUXT0013
    rule: nuxt-ui/prefer-u-button
    source: /tmp/nuxt-com-browser-test.ujXeyY/app/components/chat/ChatPanel.vue:126:13
  [NUXT0068] setTimeout is easier to clean up through a composable.
  ├▶ fix: Use VueUse useTimeoutFn() for lifecycle-aware timing.
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NUXT0068
    rule: vueuse/prefer-use-timers
    source: /tmp/nuxt-com-browser-test.ujXeyY/app/components/ads/AdsMN.vue:12:3
  [NUXT0068] setInterval is easier to clean up through a composable.
  ├▶ fix: Use VueUse useIntervalFn() for lifecycle-aware timing.
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NUXT0068
    rule: vueuse/prefer-use-timers
    source: /tmp/nuxt-com-browser-test.ujXeyY/app/components/ads/AdsMN.vue:28:14
  [NUXT0068] setTimeout is easier to clean up through a composable.
  ├▶ fix: Use VueUse useTimeoutFn() for lifecycle-aware timing.
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NUXT0068
    rule: vueuse/prefer-use-timers
    source: /tmp/nuxt-com-browser-test.ujXeyY/app/components/ads/AdsNuxtCertificate.vue:12:3
  [NUXT0068] setInterval is easier to clean up through a composable.
  ├▶ fix: Use VueUse useIntervalFn() for lifecycle-aware timing.
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NUXT0068
    rule: vueuse/prefer-use-timers
    source: /tmp/nuxt-com-browser-test.ujXeyY/app/components/ads/AdsNuxtCertificate.vue:28:14
  [NUXT0068] setTimeout is easier to clean up through a composable.
  ├▶ fix: Use VueUse useTimeoutFn() for lifecycle-aware timing.
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NUXT0068
    rule: vueuse/prefer-use-timers
    source: /tmp/nuxt-com-browser-test.ujXeyY/app/components/agent/AgentFloatingInput.vue:26:17
  [NUXT0068] requestAnimationFrame is easier to clean up through a composable.
  ├▶ fix: Use VueUse useRafFn() for lifecycle-aware timing.
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NUXT0068
    rule: vueuse/prefer-use-timers
    source: /tmp/nuxt-com-browser-test.ujXeyY/app/components/agent/AgentIndicator.vue:63:7
  [NUXT0068] setInterval is easier to clean up through a composable.
  ├▶ fix: Use VueUse useIntervalFn() for lifecycle-aware timing.
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NUXT0068
    rule: vueuse/prefer-use-timers
    source: /tmp/nuxt-com-browser-test.ujXeyY/app/components/agent/AgentIndicator.vue:77:20
  [NUXT0068] setTimeout is easier to clean up through a composable.
  ├▶ fix: Use VueUse useTimeoutFn() for lifecycle-aware timing.
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NUXT0068
    rule: vueuse/prefer-use-timers
    source: /tmp/nuxt-com-browser-test.ujXeyY/app/components/home/HomeSectionContributors.vue:36:20
  [NUXT0068] setTimeout is easier to clean up through a composable.
  ├▶ fix: Use VueUse useTimeoutFn() for lifecycle-aware timing.
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NUXT0068
    rule: vueuse/prefer-use-timers
    source: /tmp/nuxt-com-browser-test.ujXeyY/app/composables/useFeedback.ts:244:36
  [NUXT0068] setTimeout is easier to clean up through a composable.
  ├▶ fix: Use VueUse useTimeoutFn() for lifecycle-aware timing.
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NUXT0068
    rule: vueuse/prefer-use-timers
    source: /tmp/nuxt-com-browser-test.ujXeyY/app/layouts/default.vue:9:3
  [NUXT0068] setTimeout is easier to clean up through a composable.
  ├▶ fix: Use VueUse useTimeoutFn() for lifecycle-aware timing.
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NUXT0068
    rule: vueuse/prefer-use-timers
    source: /tmp/nuxt-com-browser-test.ujXeyY/app/pages/docs/[...slug].vue:49:5
  [NUXT0068] requestAnimationFrame is easier to clean up through a composable.
  ├▶ fix: Use VueUse useRafFn() for lifecycle-aware timing.
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NUXT0068
    rule: vueuse/prefer-use-timers
    source: /tmp/nuxt-com-browser-test.ujXeyY/app/pages/docs/[...slug].vue:50:5
  [NUXT0068] setTimeout is easier to clean up through a composable.
  ├▶ fix: Use VueUse useTimeoutFn() for lifecycle-aware timing.
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NUXT0068
    rule: vueuse/prefer-use-timers
    source: /tmp/nuxt-com-browser-test.ujXeyY/app/pages/modules/index.vue:74:3
  [NUXT0006] Raw <img> misses Nuxt Image optimization and responsive providers.
  ├▶ fix: Use <NuxtImg> for application images.
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NUXT0006
    rule: nuxt-image/prefer-nuxtimg
    source: /tmp/nuxt-com-browser-test.ujXeyY/app/components/ads/AdsFreeWeekend.vue:9:7
  [NUXT0006] Raw <img> misses Nuxt Image optimization and responsive providers.
  ├▶ fix: Use <NuxtImg> for application images.
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NUXT0006
    rule: nuxt-image/prefer-nuxtimg
    source: /tmp/nuxt-com-browser-test.ujXeyY/app/components/module/ModuleProseImg.vue:33:3
  [NUXT0007] Format negotiation is clearer with <NuxtPicture>.
  ├▶ fix: Use <NuxtPicture> when serving modern formats with fallbacks.
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NUXT0007
    rule: nuxt-image/prefer-nuxtpicture-for-formats
    source: /tmp/nuxt-com-browser-test.ujXeyY/app/pages/showcase.vue:116:15
  [NUXT0007] Format negotiation is clearer with <NuxtPicture>.
  ├▶ fix: Use <NuxtPicture> when serving modern formats with fallbacks.
  ╰▶ see: https://vite-doctor.onmax.me/diagnostics/NUXT0007
    rule: nuxt-image/prefer-nuxtpicture-for-formats
    source: /tmp/nuxt-com-browser-test.ujXeyY/app/pages/video-courses.vue:43:13

Summary
  0 blockers, 0 errors, 24 warnings, 50 info
  0 safe fixes available

Graph
  341 files, 597 imports, 241 exports, 331 roots, 0 cycles

PR made with codex

@vercel
Copy link
Copy Markdown
Contributor

vercel Bot commented May 31, 2026

@onmax is attempting to deploy a commit to the Nuxt Team on Vercel.

A member of the Team first needs to authorize it.

@onmax onmax force-pushed the codex/vite-doctor-diagnostics branch 4 times, most recently from d0c0c3c to 47e0744 Compare May 31, 2026 10:04
@onmax onmax marked this pull request as ready for review May 31, 2026 10:27
@onmax onmax requested a review from atinux as a code owner May 31, 2026 10:27
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 31, 2026

Review Change Stack

Warning

Review limit reached

@onmax, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 11 minutes and 39 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 16b52a64-1b88-40ae-b1b5-d4380ff8336c

📥 Commits

Reviewing files that changed from the base of the PR and between 3fa9adb and 75a4e85.

📒 Files selected for processing (12)
  • app/components/AdminDashboard.vue
  • app/components/chat/ChatPanel.vue
  • app/composables/useCanonical.ts
  • app/composables/useDateRange.ts
  • app/composables/useSponsors.ts
  • app/pages/deploy/index.vue
  • app/pages/modules/index.vue
  • app/pages/video-courses.vue
  • server/api/admin/mcp-install.get.ts
  • server/api/auth/github.get.ts
  • server/api/v1/teams/index.get.ts
  • server/utils/team.ts
📝 Walkthrough

Walkthrough

This PR updates three interconnected systems. On the client, Vue component watchers are deferred to post-flush timing for scroll and load-more handlers, composables are refactored to use ISO string serialization (useDateRange), synchronous reactive calls (useSponsors), and safer head registration (useCanonical), and element attributes are added for button types and responsive image sizing. On the server, team authorization and member-checking utilities accept H3Event to enable event-scoped runtime config and fetch operations, and three API handlers now pass the event through to these authorization functions for proper environment-aware configuration access.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'fix: address vite doctor diagnostics' is clear and directly describes the main purpose of the PR, which is to fix issues identified by the Vite Doctor diagnostics tool.
Description check ✅ Passed The description is comprehensive and directly related to the changeset, explaining the Vite Doctor CLI experiment, before/after health score improvements (28/100 to 65/100), and reduction in errors (4 to 0).
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
server/utils/team.ts (1)

9-18: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

login parameter should be normalized inside isCoreTeamMember.

The comparison on line 17 lowercases member.login but compares to login as-is. Since this function is exported, callers could pass mixed-case logins directly (e.g., "UserName"), causing the comparison to fail.

Currently isAuthorizedAdmin pre-normalizes, but the exported contract is unclear.

🛡️ Proposed fix to normalize inside the function
 export async function isCoreTeamMember(event: H3Event, login: string): Promise<boolean> {
+  const normalizedLogin = login.toLowerCase()
   const coreMembers = await getCoreMembers(event)
   if (!coreMembers || !Array.isArray(coreMembers)) {
     throw createError({
       statusCode: 500,
       statusMessage: 'Failed to fetch core team members.'
     })
   }
-  return coreMembers.some(member => member.login.toLowerCase() === login)
+  return coreMembers.some(member => member.login.toLowerCase() === normalizedLogin)
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/utils/team.ts` around lines 9 - 18, The isCoreTeamMember function
compares member.login.toLowerCase() to the incoming login without normalizing
the login param; update isCoreTeamMember to normalize the incoming login (e.g.,
trim() and toLowerCase()) before the comparison so callers can pass mixed-case
values; locate isCoreTeamMember and ensure you normalize the login variable
prior to returning coreMembers.some(...) (getCoreMembers remains unchanged and
keep the existing createError behavior).
🧹 Nitpick comments (1)
server/utils/team.ts (1)

4-7: 💤 Low value

Static cache key means event is only used on first invocation.

getCoreMembers accepts event for event.$fetch, but the cache key is static ('core-members'). After the first call within the 7-day cache window, subsequent calls return the cached result without invoking the function—effectively ignoring the event parameter.

For fetching immutable team data this may be acceptable, but if request-specific behavior (e.g., headers forwarding) is expected on every call, this pattern won't provide it.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/utils/team.ts` around lines 4 - 7, getCoreMembers is using a static
cache key ('core-members') so the event parameter (and any per-request headers)
is only used the first time; subsequent calls within the cache window will
return the cached result and ignore event.$fetch. Fix by making the cache key
depend on the request when needed (e.g., change getKey to accept event and
return a key that includes any request-specific bits such as an authorization
header or host, e.g. getKey: (event) =>
`core-members:${event?.node?.req?.headers['authorization']||''}`), or if the
data is truly immutable remove the event parameter from getCoreMembers to avoid
confusion; update the cachedFunction invocation accordingly so event.$fetch is
invoked on every call when per-request behavior is required.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@app/composables/useDateRange.ts`:
- Around line 13-18: createDefaultDateRange() currently returns raw timestamps
which are narrower than the normalized ranges created by setDateRange(); update
createDefaultDateRange to compute the end as endOfDay(new Date()) and the start
as startOfDay(subDays(end, 30)) (then toISOString both) so the initial "Last 30
days" matches the same startOfDay/endOfDay normalization used by setDateRange().

---

Outside diff comments:
In `@server/utils/team.ts`:
- Around line 9-18: The isCoreTeamMember function compares
member.login.toLowerCase() to the incoming login without normalizing the login
param; update isCoreTeamMember to normalize the incoming login (e.g., trim() and
toLowerCase()) before the comparison so callers can pass mixed-case values;
locate isCoreTeamMember and ensure you normalize the login variable prior to
returning coreMembers.some(...) (getCoreMembers remains unchanged and keep the
existing createError behavior).

---

Nitpick comments:
In `@server/utils/team.ts`:
- Around line 4-7: getCoreMembers is using a static cache key ('core-members')
so the event parameter (and any per-request headers) is only used the first
time; subsequent calls within the cache window will return the cached result and
ignore event.$fetch. Fix by making the cache key depend on the request when
needed (e.g., change getKey to accept event and return a key that includes any
request-specific bits such as an authorization header or host, e.g. getKey:
(event) => `core-members:${event?.node?.req?.headers['authorization']||''}`), or
if the data is truly immutable remove the event parameter from getCoreMembers to
avoid confusion; update the cachedFunction invocation accordingly so
event.$fetch is invoked on every call when per-request behavior is required.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ee0e771a-bb50-4308-a521-4889b0ff3b91

📥 Commits

Reviewing files that changed from the base of the PR and between 5a31b51 and 47e0744.

📒 Files selected for processing (12)
  • app/components/AdminDashboard.vue
  • app/components/chat/ChatPanel.vue
  • app/composables/useCanonical.ts
  • app/composables/useDateRange.ts
  • app/composables/useSponsors.ts
  • app/pages/deploy/index.vue
  • app/pages/modules/index.vue
  • app/pages/video-courses.vue
  • server/api/admin/mcp-install.get.ts
  • server/api/auth/github.get.ts
  • server/api/v1/teams/index.get.ts
  • server/utils/team.ts

Comment thread app/composables/useDateRange.ts Outdated
onmax added 7 commits May 31, 2026 12:45
A form-associated <button> defaults to type="submit", not type="button". The suggestion tiles trigger a chat action, so declaring type="button" keeps them inert if this prompt area is ever wrapped by a form.

Docs: https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/button#type
Nuxt useState is serialized through the payload, so the state value should stay JSON-safe. Store ISO strings there and expose Date objects through a computed wrapper so consumers keep the same API without relying on Date instances surviving hydration.

The default range also uses the same startOfDay/endOfDay normalization as setDateRange. That keeps the first "Last 30 days" window aligned with picker and preset updates instead of using raw timestamps.

Docs: https://nuxt.com/docs/4.x/getting-started/state-management

Docs: https://nuxt.com/docs/api/composables/use-state
Nuxt documents useFetch as a composable that should be called directly in setup, plugins, or route middleware so it can register payload state for hydration. Calling useFetch and useAsyncData directly in this composable keeps the Nuxt data primitives visible instead of hiding them behind a generic Promise.all boundary.

The call sites can still include useSponsors() in their existing Promise.all arrays; Promise.all accepts plain values, and the composable keeps returning the same sponsors helpers.

Docs: https://nuxt.com/docs/4.x/api/composables/use-fetch
Nuxt server-route docs say request headers and request context are not forwarded by default for server-side fetches, and event.$fetch should be used when that context should follow the internal request. The same server docs recommend passing event to useRuntimeConfig in server routes so runtime environment overrides are resolved against the active request.

This keeps the admin/team helpers on request-aware server primitives instead of ambient global fetch/config access.

Docs: https://nuxt.com/docs/4.x/directory-structure/server#forwarding-context-headers

Docs: https://nuxt.com/docs/4.x/directory-structure/server#runtime-config
Nuxt recommends useHeadSafe when head data is derived from input because it restricts rendered head fields to a safe attribute whitelist. The canonical composable builds links from route and optional content-derived markdown paths, and useHeadSafe still allows the rel, href, type, and related link attributes this helper emits.

Docs: https://nuxt.com/docs/4.x/api/composables/use-head-safe
Vue runs normal watcher callbacks before the owner component DOM has updated. These watchers read or mutate DOM state after reactive values change, so flush="post" schedules them after Vue applies the render update.

Docs: https://vuejs.org/guide/essentials/watchers.html#callback-flush-timing
Nuxt Image renders native img attributes and documents that alt should always be provided. Deployment logos carry information, so the logo image gets an explicit label.

Nuxt Image also generates responsive candidates from the sizes option. The video-course logos are fixed-size images, so the sizes value now matches the actual sponsor/non-sponsor rendered width instead of forcing a wider candidate for every course.

Docs: https://image.nuxt.com/usage/nuxt-img#alt

Docs: https://image.nuxt.com/usage/nuxt-img#sizes
@onmax onmax force-pushed the codex/vite-doctor-diagnostics branch from 3fa9adb to 75a4e85 Compare May 31, 2026 10:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant