@kirchdev/duxt 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (401) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +151 -0
  3. package/app/app.config.ts +13 -0
  4. package/app/app.vue +122 -0
  5. package/app/assets/css/duxt.css +555 -0
  6. package/app/assets/css/typeset.css +498 -0
  7. package/app/components/DuxtBrand.vue +53 -0
  8. package/app/components/DuxtBreadcrumb.vue +37 -0
  9. package/app/components/DuxtCodeBlock.vue +143 -0
  10. package/app/components/DuxtCopyPage.vue +117 -0
  11. package/app/components/DuxtFooter.vue +86 -0
  12. package/app/components/DuxtHeader.vue +496 -0
  13. package/app/components/DuxtJsonEditor.vue +359 -0
  14. package/app/components/DuxtLandingProse.vue +90 -0
  15. package/app/components/DuxtLandingShowcase.vue +295 -0
  16. package/app/components/DuxtLiveWindow.vue +343 -0
  17. package/app/components/DuxtLocale.vue +86 -0
  18. package/app/components/DuxtMetaList.vue +76 -0
  19. package/app/components/DuxtNavigation.vue +94 -0
  20. package/app/components/DuxtNavigationLink.vue +41 -0
  21. package/app/components/DuxtOpenApiCallbacks.vue +92 -0
  22. package/app/components/DuxtOpenApiClient.vue +1339 -0
  23. package/app/components/DuxtOpenApiMedia.vue +108 -0
  24. package/app/components/DuxtOpenApiMethod.vue +59 -0
  25. package/app/components/DuxtOpenApiParameters.vue +114 -0
  26. package/app/components/DuxtOpenApiResponses.vue +109 -0
  27. package/app/components/DuxtOpenApiSchema.vue +365 -0
  28. package/app/components/DuxtOpenApiSecurity.vue +115 -0
  29. package/app/components/DuxtPageFeedback.vue +56 -0
  30. package/app/components/DuxtPageInfo.vue +194 -0
  31. package/app/components/DuxtPageNav.vue +93 -0
  32. package/app/components/DuxtPreviewSkeleton.vue +262 -0
  33. package/app/components/DuxtProgress.vue +45 -0
  34. package/app/components/DuxtSearch.vue +271 -0
  35. package/app/components/DuxtSections.vue +65 -0
  36. package/app/components/DuxtShortcuts.vue +46 -0
  37. package/app/components/DuxtSkipLink.vue +34 -0
  38. package/app/components/DuxtToc.vue +86 -0
  39. package/app/components/DuxtTranslationBanner.vue +64 -0
  40. package/app/components/DuxtVersion.vue +168 -0
  41. package/app/components/DuxtVersionBanner.vue +109 -0
  42. package/app/components/OgImage/Duxt.satori.vue +82 -0
  43. package/app/components/content/Accordion.vue +37 -0
  44. package/app/components/content/AccordionItem.vue +46 -0
  45. package/app/components/content/Callout.vue +58 -0
  46. package/app/components/content/ChangelogGroup.vue +91 -0
  47. package/app/components/content/ChangelogReleases.vue +520 -0
  48. package/app/components/content/CodeGroup.vue +183 -0
  49. package/app/components/content/DevtoolsPanel.vue +107 -0
  50. package/app/components/content/Field.vue +50 -0
  51. package/app/components/content/FieldGroup.vue +8 -0
  52. package/app/components/content/FileTree.vue +92 -0
  53. package/app/components/content/Mermaid.vue +70 -0
  54. package/app/components/content/OpenApiOperation.vue +185 -0
  55. package/app/components/content/OpenApiOperations.vue +72 -0
  56. package/app/components/content/OpenApiOverview.vue +302 -0
  57. package/app/components/content/PackageManagers.vue +187 -0
  58. package/app/components/content/PageCards.vue +48 -0
  59. package/app/components/content/Partial.vue +65 -0
  60. package/app/components/content/Preview.vue +173 -0
  61. package/app/components/content/ProseA.vue +55 -0
  62. package/app/components/content/ProseH2.vue +53 -0
  63. package/app/components/content/ProseH3.vue +53 -0
  64. package/app/components/content/ProseH4.vue +53 -0
  65. package/app/components/content/ProseImg.vue +87 -0
  66. package/app/components/content/ProsePre.vue +58 -0
  67. package/app/components/content/ProseTable.vue +11 -0
  68. package/app/components/content/Since.vue +21 -0
  69. package/app/components/content/Steps.vue +20 -0
  70. package/app/components/content/Tab.vue +23 -0
  71. package/app/components/content/TabGroup.vue +58 -0
  72. package/app/components/ui/alert/Alert.vue +21 -0
  73. package/app/components/ui/alert/AlertDescription.vue +22 -0
  74. package/app/components/ui/alert/AlertTitle.vue +22 -0
  75. package/app/components/ui/alert/index.ts +24 -0
  76. package/app/components/ui/badge/Badge.vue +28 -0
  77. package/app/components/ui/badge/index.ts +52 -0
  78. package/app/components/ui/breadcrumb/Breadcrumb.vue +13 -0
  79. package/app/components/ui/breadcrumb/BreadcrumbEllipsis.vue +22 -0
  80. package/app/components/ui/breadcrumb/BreadcrumbItem.vue +17 -0
  81. package/app/components/ui/breadcrumb/BreadcrumbLink.vue +24 -0
  82. package/app/components/ui/breadcrumb/BreadcrumbList.vue +22 -0
  83. package/app/components/ui/breadcrumb/BreadcrumbPage.vue +20 -0
  84. package/app/components/ui/breadcrumb/BreadcrumbSeparator.vue +21 -0
  85. package/app/components/ui/breadcrumb/index.ts +7 -0
  86. package/app/components/ui/button/Button.vue +31 -0
  87. package/app/components/ui/button/index.ts +39 -0
  88. package/app/components/ui/card/Card.vue +22 -0
  89. package/app/components/ui/card/CardAction.vue +22 -0
  90. package/app/components/ui/card/CardContent.vue +14 -0
  91. package/app/components/ui/card/CardDescription.vue +17 -0
  92. package/app/components/ui/card/CardFooter.vue +17 -0
  93. package/app/components/ui/card/CardHeader.vue +22 -0
  94. package/app/components/ui/card/CardTitle.vue +17 -0
  95. package/app/components/ui/card/index.ts +7 -0
  96. package/app/components/ui/collapsible/Collapsible.vue +19 -0
  97. package/app/components/ui/collapsible/CollapsibleContent.vue +12 -0
  98. package/app/components/ui/collapsible/CollapsibleTrigger.vue +12 -0
  99. package/app/components/ui/collapsible/index.ts +3 -0
  100. package/app/components/ui/command/Command.vue +98 -0
  101. package/app/components/ui/command/CommandDialog.vue +42 -0
  102. package/app/components/ui/command/CommandEmpty.vue +31 -0
  103. package/app/components/ui/command/CommandGroup.vue +52 -0
  104. package/app/components/ui/command/CommandInput.vue +45 -0
  105. package/app/components/ui/command/CommandItem.vue +85 -0
  106. package/app/components/ui/command/CommandList.vue +32 -0
  107. package/app/components/ui/command/CommandSeparator.vue +23 -0
  108. package/app/components/ui/command/CommandShortcut.vue +19 -0
  109. package/app/components/ui/command/index.ts +29 -0
  110. package/app/components/ui/dialog/Dialog.vue +15 -0
  111. package/app/components/ui/dialog/DialogClose.vue +12 -0
  112. package/app/components/ui/dialog/DialogContent.vue +61 -0
  113. package/app/components/ui/dialog/DialogDescription.vue +25 -0
  114. package/app/components/ui/dialog/DialogFooter.vue +30 -0
  115. package/app/components/ui/dialog/DialogHeader.vue +17 -0
  116. package/app/components/ui/dialog/DialogOverlay.vue +28 -0
  117. package/app/components/ui/dialog/DialogScrollContent.vue +65 -0
  118. package/app/components/ui/dialog/DialogTitle.vue +25 -0
  119. package/app/components/ui/dialog/DialogTrigger.vue +12 -0
  120. package/app/components/ui/dialog/index.ts +10 -0
  121. package/app/components/ui/dropdown-menu/DropdownMenu.vue +19 -0
  122. package/app/components/ui/dropdown-menu/DropdownMenuCheckboxItem.vue +47 -0
  123. package/app/components/ui/dropdown-menu/DropdownMenuContent.vue +47 -0
  124. package/app/components/ui/dropdown-menu/DropdownMenuGroup.vue +12 -0
  125. package/app/components/ui/dropdown-menu/DropdownMenuItem.vue +41 -0
  126. package/app/components/ui/dropdown-menu/DropdownMenuLabel.vue +27 -0
  127. package/app/components/ui/dropdown-menu/DropdownMenuRadioGroup.vue +21 -0
  128. package/app/components/ui/dropdown-menu/DropdownMenuRadioItem.vue +48 -0
  129. package/app/components/ui/dropdown-menu/DropdownMenuSeparator.vue +23 -0
  130. package/app/components/ui/dropdown-menu/DropdownMenuShortcut.vue +19 -0
  131. package/app/components/ui/dropdown-menu/DropdownMenuSub.vue +19 -0
  132. package/app/components/ui/dropdown-menu/DropdownMenuSubContent.vue +34 -0
  133. package/app/components/ui/dropdown-menu/DropdownMenuSubTrigger.vue +34 -0
  134. package/app/components/ui/dropdown-menu/DropdownMenuTrigger.vue +17 -0
  135. package/app/components/ui/dropdown-menu/index.ts +16 -0
  136. package/app/components/ui/input/Input.vue +35 -0
  137. package/app/components/ui/input/index.ts +1 -0
  138. package/app/components/ui/navigation-menu/NavigationMenu.vue +42 -0
  139. package/app/components/ui/navigation-menu/NavigationMenuContent.vue +35 -0
  140. package/app/components/ui/navigation-menu/NavigationMenuIndicator.vue +32 -0
  141. package/app/components/ui/navigation-menu/NavigationMenuItem.vue +23 -0
  142. package/app/components/ui/navigation-menu/NavigationMenuLink.vue +30 -0
  143. package/app/components/ui/navigation-menu/NavigationMenuList.vue +30 -0
  144. package/app/components/ui/navigation-menu/NavigationMenuTrigger.vue +31 -0
  145. package/app/components/ui/navigation-menu/NavigationMenuViewport.vue +30 -0
  146. package/app/components/ui/navigation-menu/index.ts +14 -0
  147. package/app/components/ui/scroll-area/ScrollArea.vue +31 -0
  148. package/app/components/ui/scroll-area/ScrollBar.vue +38 -0
  149. package/app/components/ui/scroll-area/index.ts +2 -0
  150. package/app/components/ui/select/Select.vue +15 -0
  151. package/app/components/ui/select/SelectContent.vue +59 -0
  152. package/app/components/ui/select/SelectGroup.vue +19 -0
  153. package/app/components/ui/select/SelectItem.vue +42 -0
  154. package/app/components/ui/select/SelectItemText.vue +12 -0
  155. package/app/components/ui/select/SelectLabel.vue +16 -0
  156. package/app/components/ui/select/SelectScrollDownButton.vue +28 -0
  157. package/app/components/ui/select/SelectScrollUpButton.vue +28 -0
  158. package/app/components/ui/select/SelectSeparator.vue +20 -0
  159. package/app/components/ui/select/SelectTrigger.vue +32 -0
  160. package/app/components/ui/select/SelectValue.vue +12 -0
  161. package/app/components/ui/select/index.ts +11 -0
  162. package/app/components/ui/separator/Separator.vue +30 -0
  163. package/app/components/ui/separator/index.ts +1 -0
  164. package/app/components/ui/sheet/Sheet.vue +15 -0
  165. package/app/components/ui/sheet/SheetClose.vue +12 -0
  166. package/app/components/ui/sheet/SheetContent.vue +68 -0
  167. package/app/components/ui/sheet/SheetDescription.vue +23 -0
  168. package/app/components/ui/sheet/SheetFooter.vue +15 -0
  169. package/app/components/ui/sheet/SheetHeader.vue +15 -0
  170. package/app/components/ui/sheet/SheetOverlay.vue +28 -0
  171. package/app/components/ui/sheet/SheetTitle.vue +23 -0
  172. package/app/components/ui/sheet/SheetTrigger.vue +12 -0
  173. package/app/components/ui/sheet/index.ts +8 -0
  174. package/app/components/ui/sidebar/Sidebar.vue +110 -0
  175. package/app/components/ui/sidebar/SidebarContent.vue +23 -0
  176. package/app/components/ui/sidebar/SidebarFooter.vue +18 -0
  177. package/app/components/ui/sidebar/SidebarGroup.vue +18 -0
  178. package/app/components/ui/sidebar/SidebarGroupAction.vue +31 -0
  179. package/app/components/ui/sidebar/SidebarGroupContent.vue +18 -0
  180. package/app/components/ui/sidebar/SidebarGroupLabel.vue +30 -0
  181. package/app/components/ui/sidebar/SidebarHeader.vue +18 -0
  182. package/app/components/ui/sidebar/SidebarInput.vue +19 -0
  183. package/app/components/ui/sidebar/SidebarInset.vue +23 -0
  184. package/app/components/ui/sidebar/SidebarMenu.vue +18 -0
  185. package/app/components/ui/sidebar/SidebarMenuAction.vue +42 -0
  186. package/app/components/ui/sidebar/SidebarMenuBadge.vue +28 -0
  187. package/app/components/ui/sidebar/SidebarMenuButton.vue +60 -0
  188. package/app/components/ui/sidebar/SidebarMenuButtonChild.vue +36 -0
  189. package/app/components/ui/sidebar/SidebarMenuItem.vue +18 -0
  190. package/app/components/ui/sidebar/SidebarMenuSkeleton.vue +35 -0
  191. package/app/components/ui/sidebar/SidebarMenuSub.vue +24 -0
  192. package/app/components/ui/sidebar/SidebarMenuSubButton.vue +43 -0
  193. package/app/components/ui/sidebar/SidebarMenuSubItem.vue +18 -0
  194. package/app/components/ui/sidebar/SidebarProvider.vue +109 -0
  195. package/app/components/ui/sidebar/SidebarRail.vue +35 -0
  196. package/app/components/ui/sidebar/SidebarSeparator.vue +19 -0
  197. package/app/components/ui/sidebar/SidebarTrigger.vue +26 -0
  198. package/app/components/ui/sidebar/index.ts +62 -0
  199. package/app/components/ui/sidebar/utils.ts +19 -0
  200. package/app/components/ui/skeleton/Skeleton.vue +17 -0
  201. package/app/components/ui/skeleton/index.ts +1 -0
  202. package/app/components/ui/sonner/Sonner.vue +67 -0
  203. package/app/components/ui/sonner/index.ts +1 -0
  204. package/app/components/ui/tabs/Tabs.vue +26 -0
  205. package/app/components/ui/tabs/TabsContent.vue +23 -0
  206. package/app/components/ui/tabs/TabsList.vue +28 -0
  207. package/app/components/ui/tabs/TabsTrigger.vue +30 -0
  208. package/app/components/ui/tabs/index.ts +4 -0
  209. package/app/components/ui/textarea/Textarea.vue +32 -0
  210. package/app/components/ui/textarea/index.ts +1 -0
  211. package/app/components/ui/tooltip/Tooltip.vue +15 -0
  212. package/app/components/ui/tooltip/TooltipContent.vue +49 -0
  213. package/app/components/ui/tooltip/TooltipProvider.vue +14 -0
  214. package/app/components/ui/tooltip/TooltipTrigger.vue +12 -0
  215. package/app/components/ui/tooltip/index.ts +4 -0
  216. package/app/composables/useActiveHeading.ts +90 -0
  217. package/app/composables/useDuxtAnimatedHeight.ts +155 -0
  218. package/app/composables/useDuxtBreadcrumb.ts +60 -0
  219. package/app/composables/useDuxtChoice.ts +28 -0
  220. package/app/composables/useDuxtCollection.ts +89 -0
  221. package/app/composables/useDuxtConfig.ts +47 -0
  222. package/app/composables/useDuxtNavigation.ts +87 -0
  223. package/app/composables/useDuxtPageFocus.ts +30 -0
  224. package/app/composables/useDuxtPath.ts +42 -0
  225. package/app/composables/useDuxtSearch.ts +208 -0
  226. package/app/composables/useDuxtSection.ts +44 -0
  227. package/app/composables/useDuxtSectionRow.ts +49 -0
  228. package/app/composables/useDuxtShortcuts.ts +58 -0
  229. package/app/composables/useDuxtSiteUrl.ts +27 -0
  230. package/app/composables/useDuxtToast.ts +25 -0
  231. package/app/composables/useDuxtVersion.ts +138 -0
  232. package/app/composables/useFuzzySearch.ts +83 -0
  233. package/app/composables/usePackageManager.ts +4 -0
  234. package/app/composables/useRecentPages.ts +52 -0
  235. package/app/error.vue +133 -0
  236. package/app/layouts/changelog.vue +85 -0
  237. package/app/layouts/default.vue +23 -0
  238. package/app/layouts/docs.vue +62 -0
  239. package/app/layouts/reference.vue +85 -0
  240. package/app/lib/utils.ts +7 -0
  241. package/app/middleware/duxt-section-layout.global.ts +57 -0
  242. package/app/pages/[...slug].vue +441 -0
  243. package/app/pages/index.vue +479 -0
  244. package/app/types/duxt.d.ts +955 -0
  245. package/app/utils/aside.ts +16 -0
  246. package/app/utils/changelog.ts +182 -0
  247. package/app/utils/code-highlight.ts +116 -0
  248. package/app/utils/duxt-config.ts +185 -0
  249. package/app/utils/duxt-text.ts +135 -0
  250. package/app/utils/file-icons.ts +62 -0
  251. package/app/utils/generated-sections.ts +190 -0
  252. package/app/utils/generated-toc.ts +216 -0
  253. package/app/utils/heading-link.ts +32 -0
  254. package/app/utils/locale-path.ts +45 -0
  255. package/app/utils/navigation-tree.ts +206 -0
  256. package/app/utils/nearest-page.ts +72 -0
  257. package/app/utils/openapi.ts +1028 -0
  258. package/app/utils/package-command.ts +162 -0
  259. package/app/utils/request-samples.ts +635 -0
  260. package/app/utils/section-scope.ts +97 -0
  261. package/app/utils/sheet-navigation.ts +100 -0
  262. package/app/utils/source-file.ts +84 -0
  263. package/app/utils/version-choices.ts +68 -0
  264. package/app/utils/version-paths.ts +65 -0
  265. package/bin/duxt-report.mjs +45 -0
  266. package/components.json +19 -0
  267. package/content-cache.ts +193 -0
  268. package/content.config.ts +38 -0
  269. package/duxt-app-config.ts +124 -0
  270. package/highlight-langs.ts +68 -0
  271. package/i18n/i18n.config.ts +16 -0
  272. package/i18n/locales/de/duxt/changelog.json +17 -0
  273. package/i18n/locales/de/duxt/code.json +13 -0
  274. package/i18n/locales/de/duxt/defaults.json +22 -0
  275. package/i18n/locales/de/duxt/devtools.json +7 -0
  276. package/i18n/locales/de/duxt/error.json +10 -0
  277. package/i18n/locales/de/duxt/footer.json +7 -0
  278. package/i18n/locales/de/duxt/locale.json +7 -0
  279. package/i18n/locales/de/duxt/nav.json +17 -0
  280. package/i18n/locales/de/duxt/openapi.json +89 -0
  281. package/i18n/locales/de/duxt/page.json +34 -0
  282. package/i18n/locales/de/duxt/search.json +12 -0
  283. package/i18n/locales/de/duxt/shortcuts.json +11 -0
  284. package/i18n/locales/de/duxt/theme.json +7 -0
  285. package/i18n/locales/de/duxt/toc.json +7 -0
  286. package/i18n/locales/de/duxt/version.json +25 -0
  287. package/i18n/locales/en/duxt/changelog.json +17 -0
  288. package/i18n/locales/en/duxt/code.json +13 -0
  289. package/i18n/locales/en/duxt/defaults.json +22 -0
  290. package/i18n/locales/en/duxt/devtools.json +7 -0
  291. package/i18n/locales/en/duxt/error.json +10 -0
  292. package/i18n/locales/en/duxt/footer.json +7 -0
  293. package/i18n/locales/en/duxt/locale.json +7 -0
  294. package/i18n/locales/en/duxt/nav.json +17 -0
  295. package/i18n/locales/en/duxt/openapi.json +89 -0
  296. package/i18n/locales/en/duxt/page.json +34 -0
  297. package/i18n/locales/en/duxt/search.json +12 -0
  298. package/i18n/locales/en/duxt/shortcuts.json +11 -0
  299. package/i18n/locales/en/duxt/theme.json +7 -0
  300. package/i18n/locales/en/duxt/toc.json +7 -0
  301. package/i18n/locales/en/duxt/version.json +25 -0
  302. package/i18n/locales/es/duxt/changelog.json +17 -0
  303. package/i18n/locales/es/duxt/code.json +13 -0
  304. package/i18n/locales/es/duxt/defaults.json +22 -0
  305. package/i18n/locales/es/duxt/devtools.json +7 -0
  306. package/i18n/locales/es/duxt/error.json +10 -0
  307. package/i18n/locales/es/duxt/footer.json +7 -0
  308. package/i18n/locales/es/duxt/locale.json +7 -0
  309. package/i18n/locales/es/duxt/nav.json +17 -0
  310. package/i18n/locales/es/duxt/openapi.json +89 -0
  311. package/i18n/locales/es/duxt/page.json +34 -0
  312. package/i18n/locales/es/duxt/search.json +12 -0
  313. package/i18n/locales/es/duxt/shortcuts.json +11 -0
  314. package/i18n/locales/es/duxt/theme.json +7 -0
  315. package/i18n/locales/es/duxt/toc.json +7 -0
  316. package/i18n/locales/es/duxt/version.json +25 -0
  317. package/i18n/locales/fr/duxt/changelog.json +17 -0
  318. package/i18n/locales/fr/duxt/code.json +13 -0
  319. package/i18n/locales/fr/duxt/defaults.json +22 -0
  320. package/i18n/locales/fr/duxt/devtools.json +7 -0
  321. package/i18n/locales/fr/duxt/error.json +10 -0
  322. package/i18n/locales/fr/duxt/footer.json +7 -0
  323. package/i18n/locales/fr/duxt/locale.json +7 -0
  324. package/i18n/locales/fr/duxt/nav.json +17 -0
  325. package/i18n/locales/fr/duxt/openapi.json +89 -0
  326. package/i18n/locales/fr/duxt/page.json +34 -0
  327. package/i18n/locales/fr/duxt/search.json +12 -0
  328. package/i18n/locales/fr/duxt/shortcuts.json +11 -0
  329. package/i18n/locales/fr/duxt/theme.json +7 -0
  330. package/i18n/locales/fr/duxt/toc.json +7 -0
  331. package/i18n/locales/fr/duxt/version.json +25 -0
  332. package/i18n/locales/pt/duxt/changelog.json +17 -0
  333. package/i18n/locales/pt/duxt/code.json +13 -0
  334. package/i18n/locales/pt/duxt/defaults.json +22 -0
  335. package/i18n/locales/pt/duxt/devtools.json +7 -0
  336. package/i18n/locales/pt/duxt/error.json +10 -0
  337. package/i18n/locales/pt/duxt/footer.json +7 -0
  338. package/i18n/locales/pt/duxt/locale.json +7 -0
  339. package/i18n/locales/pt/duxt/nav.json +17 -0
  340. package/i18n/locales/pt/duxt/openapi.json +89 -0
  341. package/i18n/locales/pt/duxt/page.json +34 -0
  342. package/i18n/locales/pt/duxt/search.json +12 -0
  343. package/i18n/locales/pt/duxt/shortcuts.json +11 -0
  344. package/i18n/locales/pt/duxt/theme.json +7 -0
  345. package/i18n/locales/pt/duxt/toc.json +7 -0
  346. package/i18n/locales/pt/duxt/version.json +25 -0
  347. package/i18n/locales/pt-BR/duxt/error.json +8 -0
  348. package/i18n/locales/pt-BR/duxt/nav.json +10 -0
  349. package/i18n/locales/pt-BR/duxt/page.json +10 -0
  350. package/i18n/locales/pt-BR/duxt/search.json +11 -0
  351. package/i18n/locales/pt-BR/duxt/version.json +13 -0
  352. package/mdc.config.ts +28 -0
  353. package/modules/config.ts +440 -0
  354. package/modules/devtools.ts +126 -0
  355. package/modules/git-meta.ts +349 -0
  356. package/modules/redirects.ts +152 -0
  357. package/modules/validate.ts +137 -0
  358. package/nuxt.config.ts +530 -0
  359. package/openapi-model.ts +358 -0
  360. package/openapi-parse.ts +1052 -0
  361. package/package.json +161 -0
  362. package/public/devtools/cache.html +318 -0
  363. package/public/devtools/checks.html +309 -0
  364. package/public/devtools/config.html +461 -0
  365. package/public/devtools/i18n.html +309 -0
  366. package/public/devtools/pages.html +348 -0
  367. package/public/devtools/paths.html +315 -0
  368. package/public/devtools/redirects.html +309 -0
  369. package/public/devtools/search.html +324 -0
  370. package/public/devtools/sources.html +309 -0
  371. package/public/devtools/versions.html +318 -0
  372. package/report.ts +303 -0
  373. package/repository-root.ts +26 -0
  374. package/section-reports.ts +55 -0
  375. package/sections-changelog.ts +644 -0
  376. package/sections-openapi.ts +450 -0
  377. package/sections-resolve.ts +711 -0
  378. package/sections.ts +157 -0
  379. package/server/devtools/content.ts +120 -0
  380. package/server/devtools/context.ts +38 -0
  381. package/server/devtools/entry-path.ts +30 -0
  382. package/server/devtools/handler.ts +104 -0
  383. package/server/devtools/preview.ts +461 -0
  384. package/server/devtools/render/content.ts +233 -0
  385. package/server/devtools/render/sources.ts +414 -0
  386. package/server/devtools/render/system.ts +352 -0
  387. package/server/devtools/shell.ts +611 -0
  388. package/server/devtools/sources.ts +122 -0
  389. package/server/devtools/system.ts +178 -0
  390. package/server/mcp/tools/list-pages.ts +52 -0
  391. package/server/mcp/tools/read-page.ts +57 -0
  392. package/server/mcp/tools/search-docs.ts +74 -0
  393. package/server/middleware/raw-markdown.ts +86 -0
  394. package/server/routes/llms-full.txt.get.ts +75 -0
  395. package/server/routes/llms.txt.get.ts +63 -0
  396. package/server/routes/rss.xml.get.ts +125 -0
  397. package/server/utils/duxt-server-text.ts +46 -0
  398. package/sources-git.ts +113 -0
  399. package/sources-resolve.ts +908 -0
  400. package/sources.ts +287 -0
  401. package/validate-report.ts +494 -0
package/sections.ts ADDED
@@ -0,0 +1,157 @@
1
+ /**
2
+ * Generated sections, as Content collections.
3
+ *
4
+ * The build-time half of `sections-resolve.ts`, split from it for the reason
5
+ * `sources.ts` is split from `sources-resolve.ts`: this file imports
6
+ * `@nuxt/content` and reads files off disk, and the bundler refuses to follow
7
+ * either out of app code.
8
+ *
9
+ * A section is an ORDINARY collection — nothing here mounts a route, adds a
10
+ * hook or reaches into the renderer. What makes that possible is Content's
11
+ * custom collection source: `getKeys` and `getItem` hand it a list of files and
12
+ * their contents, so a type's parser can turn one artefact into as many pages as
13
+ * it has releases, endpoints or records, and Content parses them exactly as it
14
+ * parses Markdown on disk.
15
+ *
16
+ * Reading a file is all that is left here. What a finding MEANS — a missing
17
+ * artefact, a type that read nothing out of one — is the severity policy, and
18
+ * it lives in the pure half where a test can reach it.
19
+ */
20
+ import { existsSync, readFileSync } from 'node:fs';
21
+ import { join } from 'node:path';
22
+ import { defineCollection, defineCollectionSource } from '@nuxt/content';
23
+ import type {
24
+ DuxtResolvedSource,
25
+ DuxtSource,
26
+ DuxtSourcesOptions
27
+ } from './sources-resolve';
28
+ import type {
29
+ DuxtSectionPage,
30
+ DuxtSectionType,
31
+ DuxtSectionTypes
32
+ } from './sections-resolve';
33
+ import {
34
+ duxtSectionTypes,
35
+ generatedSectionRef,
36
+ missingSectionArtefact,
37
+ resolveGeneratedSections,
38
+ sectionPages
39
+ } from './sections-resolve';
40
+ import { resolveLatestRefs } from './sources-git';
41
+ import { pageSchema, repositoryRoot } from './sources';
42
+
43
+ /**
44
+ * One collection per declared section.
45
+ *
46
+ * Composed beside `duxtSources` rather than inside it: both read the same
47
+ * source list, and keeping them apart is what lets `duxtSources` walk its own
48
+ * result index-for-index against `expandSources`.
49
+ */
50
+ export function duxtGeneratedCollections(
51
+ input: DuxtSource[],
52
+ options: DuxtSourcesOptions = {},
53
+ types: DuxtSectionTypes = duxtSectionTypes()
54
+ ) {
55
+ // The same `latest` resolution both other entry points do. Cached per
56
+ // repository for the life of the process, so asking again is free and cannot
57
+ // straddle a release.
58
+ const sources = resolveLatestRefs(input);
59
+ const collections: Record<string, ReturnType<typeof defineCollection>> = {};
60
+
61
+ for (const entry of resolveGeneratedSections(sources, options, types)) {
62
+ const type = types[entry.generated!.type]!;
63
+
64
+ collections[entry.collection] = entry.generated!.remote
65
+ ? remoteCollection(entry, type)
66
+ : localCollection(entry, type);
67
+ }
68
+
69
+ return collections;
70
+ }
71
+
72
+ /**
73
+ * A section whose artefact is in the repository being built.
74
+ *
75
+ * Read and parsed HERE, while the config is being loaded, rather than lazily:
76
+ * the file is on disk already, and a missing one is an error this build must
77
+ * fail on — see `missingSectionArtefact`. Failing at config load says which
78
+ * section and which path, where the same throw from inside the parse pass says
79
+ * neither.
80
+ */
81
+ function localCollection(entry: DuxtResolvedSource, type: DuxtSectionType) {
82
+ const file = join(repositoryRoot(), entry.path);
83
+
84
+ const pages = existsSync(file)
85
+ ? sectionPages(entry, type, readFileSync(file, 'utf8'))
86
+ : missingSectionArtefact(entry, file);
87
+
88
+ const source = defineCollectionSource({
89
+ getKeys: async () => pages.map((page) => page.file),
90
+ getItem: async (key) => body(pages, key)
91
+ });
92
+
93
+ // The URL these pages are served at. Content builds a page's path from its
94
+ // key with the source's prefix in front, which is the whole reason a section
95
+ // needs no route of its own.
96
+ source.prefix = entry.prefix;
97
+
98
+ return defineCollection({ type: 'page', schema: pageSchema, source });
99
+ }
100
+
101
+ /**
102
+ * A section whose artefact is in a repository Content downloads.
103
+ *
104
+ * The download is Content's, not this layer's: the collection is declared with
105
+ * the ordinary `repository` source, and only `getKeys`/`getItem` are replaced.
106
+ * That is deliberate — where the checkout lands under `.data/content/` is
107
+ * Content's own hash-cached answer, and a second implementation of it would be
108
+ * a directory name that drifts on the first release.
109
+ *
110
+ * Lazy, because the checkout does not exist until Content has run `prepare`.
111
+ */
112
+ function remoteCollection(entry: DuxtResolvedSource, type: DuxtSectionType) {
113
+ const ref = generatedSectionRef(entry);
114
+ const url = entry.repositoryUrl!;
115
+
116
+ const collection = defineCollection({
117
+ type: 'page',
118
+ schema: pageSchema,
119
+ source: {
120
+ repository: ref
121
+ ? 'tag' in ref
122
+ ? { url, tag: ref.tag }
123
+ : { url, branch: ref.branch }
124
+ : url,
125
+ include: entry.path
126
+ }
127
+ });
128
+
129
+ const source = collection.source![0]!;
130
+ source.prefix = entry.prefix;
131
+
132
+ let pages: DuxtSectionPage[] | undefined;
133
+
134
+ const read = () => {
135
+ if (pages) return pages;
136
+
137
+ // `cwd` is where Content put the checkout, filled in by the `prepare` it
138
+ // installed on this source and run before the first `getKeys`.
139
+ const file = join(source.cwd, entry.path);
140
+
141
+ pages = existsSync(file)
142
+ ? sectionPages(entry, type, readFileSync(file, 'utf8'))
143
+ : missingSectionArtefact(entry, file);
144
+
145
+ return pages;
146
+ };
147
+
148
+ source.getKeys = async () => read().map((page) => page.file);
149
+ source.getItem = async (key) => body(read(), key);
150
+
151
+ return collection;
152
+ }
153
+
154
+ /** One page's file, by name. */
155
+ function body(pages: DuxtSectionPage[], key: string): string {
156
+ return pages.find((page) => page.file === key)?.body ?? '';
157
+ }
@@ -0,0 +1,120 @@
1
+ import type { H3Event } from 'h3';
2
+ import {
3
+ queryCollection,
4
+ queryCollectionSearchSections
5
+ } from '@nuxt/content/nitro';
6
+ import type { Collected, PageRecord } from '../../validate-report';
7
+ import { walk } from '../../validate-report';
8
+ import { context, resolvedSources } from './context';
9
+ import type { Doc, DocGroup, IndexedSection } from './render/content';
10
+ import { renderChecks, renderPages, renderSearch } from './render/content';
11
+
12
+ /**
13
+ * The queries behind the three content panels.
14
+ *
15
+ * All three ask the running site — `queryCollection` against the database the
16
+ * pages render from — instead of re-reading Markdown off disk. A panel that
17
+ * parsed its own copy would answer about a site that does not exist. What comes
18
+ * back goes to `render/content.ts`, which turns it into the tables.
19
+ */
20
+
21
+ async function docsOf(event: H3Event, fields?: string[]): Promise<DocGroup[]> {
22
+ const sources = resolvedSources();
23
+
24
+ return Promise.all(
25
+ sources.map(async (source) => {
26
+ try {
27
+ const query = queryCollection(
28
+ event,
29
+ source.collection as Parameters<typeof queryCollection>[1]
30
+ );
31
+ const docs = (await (
32
+ fields ? query.select(...(fields as ['path'])) : query
33
+ )
34
+ .order('path', 'ASC')
35
+ .all()) as unknown as Doc[];
36
+
37
+ return { collection: source.collection, docs };
38
+ } catch {
39
+ return { collection: source.collection, docs: [] };
40
+ }
41
+ })
42
+ );
43
+ }
44
+
45
+ /** Every page, with what the frontmatter and the git history gave it. */
46
+ export async function pagesPanel(event: H3Event): Promise<string> {
47
+ const groups = await docsOf(event, [
48
+ 'path',
49
+ 'title',
50
+ 'description',
51
+ 'icon',
52
+ 'id',
53
+ 'lastUpdated',
54
+ 'contributors'
55
+ ]);
56
+
57
+ return renderPages(groups, context.rootDir);
58
+ }
59
+
60
+ /** The build validator, run against the served site. */
61
+ export async function checksPanel(event: H3Event): Promise<string> {
62
+ const sources = resolvedSources();
63
+ const groups = await docsOf(event);
64
+
65
+ const pages: PageRecord[] = groups.flatMap(({ collection, docs }) =>
66
+ docs.map((doc) => {
67
+ const collected: Collected = {
68
+ anchors: new Set<string>(),
69
+ links: [],
70
+ commands: []
71
+ };
72
+ walk(doc.body, collected);
73
+
74
+ return {
75
+ collection,
76
+ path: doc.path,
77
+ file: doc.id ?? doc.path,
78
+ title: doc.title,
79
+ description: doc.description,
80
+ anchors: collected.anchors,
81
+ links: collected.links,
82
+ commands: collected.commands
83
+ };
84
+ })
85
+ );
86
+
87
+ return renderChecks(sources, pages, context.rootDir);
88
+ }
89
+
90
+ /** What the search index holds, through the same query the client runs. */
91
+ export async function searchPanel(
92
+ event: H3Event,
93
+ term: string
94
+ ): Promise<string> {
95
+ const sources = resolvedSources();
96
+
97
+ const sections = (
98
+ await Promise.all(
99
+ sources.map(async (source) => {
100
+ try {
101
+ const found = await queryCollectionSearchSections(
102
+ event,
103
+ source.collection as Parameters<
104
+ typeof queryCollectionSearchSections
105
+ >[1]
106
+ );
107
+
108
+ return found.map((section) => ({
109
+ collection: source.collection,
110
+ ...section
111
+ })) as IndexedSection[];
112
+ } catch {
113
+ return [] as IndexedSection[];
114
+ }
115
+ })
116
+ )
117
+ ).flat();
118
+
119
+ return renderSearch(term, sections);
120
+ }
@@ -0,0 +1,38 @@
1
+ // @ts-expect-error virtual module, generated in modules/devtools.ts
2
+ import { devtools } from '#duxt-devtools';
3
+ import type { DevtoolsContext } from './shell';
4
+
5
+ /**
6
+ * The two things a panel cannot render itself: where this build sits on disk,
7
+ * and what the running app config resolved to.
8
+ *
9
+ * Split from `shell.ts` so that file stays free of both the virtual module and
10
+ * the Nitro auto-imports. Everything in `shell.ts` and `render/` is then plain
11
+ * data in, HTML out — importable from a plain Node script, which is how the
12
+ * documentation renders a panel of its own with fixture data instead of a
13
+ * screenshot that goes stale.
14
+ */
15
+ export const context = devtools as DevtoolsContext;
16
+
17
+ /** The collections the site is serving, straight out of the running app config. */
18
+ export function resolvedSources(): DuxtResolvedSource[] {
19
+ const { duxt } = useAppConfig() as { duxt?: Partial<DuxtConfig> };
20
+
21
+ return (
22
+ duxt?.resolvedSources ?? [
23
+ {
24
+ collection: 'docs',
25
+ prefix: '',
26
+ path: 'docs',
27
+ isDefault: true,
28
+ // The fallback is the site's only source, so it is also the language
29
+ // everything falls back to — the field is not optional on the manifest.
30
+ isDefaultLocale: true,
31
+ status: 'current',
32
+ // A source read off disk is a full checkout, so its history is
33
+ // readable without asking.
34
+ history: true
35
+ }
36
+ ]
37
+ );
38
+ }
@@ -0,0 +1,30 @@
1
+ import { join, resolve } from 'node:path';
2
+
3
+ /**
4
+ * Resolve a cache entry the tab may delete, or refuse.
5
+ *
6
+ * Its own file, importing nothing but `node:path`, for the same reason
7
+ * `validate-report.ts` is its own file: everything else under `devtools/`
8
+ * reaches the virtual module the build generates, and a guard that cannot be
9
+ * tested without booting Nitro is a guard nobody re-checks. This is the one
10
+ * destructive thing the panel can do, so it is the one part that is proven.
11
+ *
12
+ * The name arrives from a form field, so it is checked rather than trusted: the
13
+ * result has to be a DIRECT child of the cache directory. A traversal, an
14
+ * absolute path, a nested path or an empty name all resolve somewhere else,
15
+ * which is why the comparison is on the resolved parent and never on the string
16
+ * that was submitted.
17
+ */
18
+ export function cacheEntryToDrop(
19
+ dataDir: string,
20
+ name: unknown
21
+ ): string | undefined {
22
+ if (typeof name !== 'string' || !name || name === '.' || name === '..') {
23
+ return undefined;
24
+ }
25
+
26
+ const target = resolve(dataDir, name);
27
+ if (resolve(join(target, '..')) !== resolve(dataDir)) return undefined;
28
+
29
+ return target;
30
+ }
@@ -0,0 +1,104 @@
1
+ import { rmSync } from 'node:fs';
2
+ import type { H3Event } from 'h3';
3
+ import { context } from './context';
4
+ import { page, PANELS } from './shell';
5
+ import { pathsPanel, sourcesPanel, versionsPanel } from './sources';
6
+ import { checksPanel, pagesPanel, searchPanel } from './content';
7
+ import { cacheEntryToDrop } from './entry-path';
8
+ import { cachePanel, configPanel, i18nPanel, redirectsPanel } from './system';
9
+
10
+ /**
11
+ * The devtools tab, as one route with a panel per path segment.
12
+ *
13
+ * NOT under `server/routes/`, and that is the point. Nitro scans a layer's
14
+ * `server/routes/` and registers what it finds — in every build, dev or not —
15
+ * so a file there is a production route no matter what the module that
16
+ * "registers" it decides. The tab shipped that way once: `/_duxt/devtools` was
17
+ * in the production server bundle, serving the resolved configuration, absolute
18
+ * filesystem paths and a POST that deletes a directory, while
19
+ * `modules/devtools.ts` returned early believing it had prevented exactly that.
20
+ * Sitting outside the scanned directory, the handler exists only because the
21
+ * dev-only module points Nitro at it by path. Everything the panels show is computed per
22
+ * request out of the RUNNING app config and the served database, not out of a
23
+ * snapshot taken when the module loaded: the first version froze its data into
24
+ * a virtual module, and editing `app.config.ts` then left the tab confidently
25
+ * describing the previous state, which is the one thing a debugging view must
26
+ * never do.
27
+ */
28
+ export default defineEventHandler(async (event) => {
29
+ const slug = ((event.context.params?._ as string | undefined) ?? '').replace(
30
+ /^\/+|\/+$/g,
31
+ ''
32
+ );
33
+
34
+ if (slug && !PANELS.some((panel) => panel.slug === slug)) {
35
+ setResponseStatus(event, 404);
36
+ return html(page('', '<div class="note">No such panel.</div>'));
37
+ }
38
+
39
+ // The one mutation in the tab: dropping a cache entry. A POST because it
40
+ // deletes, so a reload or a prefetch cannot trigger it.
41
+ if (event.method === 'POST' && slug === 'cache') {
42
+ const body = (await readBody(event)) as { drop?: string } | undefined;
43
+ const target = cacheEntryToDrop(context.dataDir, body?.drop);
44
+
45
+ if (!target) {
46
+ return html(
47
+ page(
48
+ slug,
49
+ cachePanel('That name is not an entry of the cache directory.')
50
+ )
51
+ );
52
+ }
53
+
54
+ rmSync(target, { recursive: true, force: true });
55
+
56
+ return html(
57
+ page(
58
+ slug,
59
+ cachePanel(`Dropped ${body?.drop}. The next build re-downloads it.`)
60
+ )
61
+ );
62
+ }
63
+
64
+ const query = getQuery(event) as { path?: string; q?: string };
65
+
66
+ const body = await panelBody(event, slug, query);
67
+
68
+ return html(page(slug, body));
69
+ });
70
+
71
+ function panelBody(
72
+ event: H3Event,
73
+ slug: string,
74
+ query: { path?: string; q?: string }
75
+ ): string | Promise<string> {
76
+ switch (slug) {
77
+ case 'paths':
78
+ return pathsPanel(event, query.path ?? '');
79
+ case 'pages':
80
+ return pagesPanel(event);
81
+ case 'versions':
82
+ return versionsPanel(event);
83
+ case 'checks':
84
+ return checksPanel(event);
85
+ case 'search':
86
+ return searchPanel(event, query.q ?? '');
87
+ case 'config':
88
+ return configPanel();
89
+ case 'i18n':
90
+ return i18nPanel();
91
+ case 'cache':
92
+ return cachePanel();
93
+ case 'redirects':
94
+ return redirectsPanel();
95
+ default:
96
+ return sourcesPanel();
97
+ }
98
+ }
99
+
100
+ function html(body: string) {
101
+ return new Response(body, {
102
+ headers: { 'content-type': 'text/html; charset=utf-8' }
103
+ });
104
+ }