jamdesk 1.0.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 (435) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +323 -0
  3. package/bin/jamdesk.js +76 -0
  4. package/dist/__tests__/integration/deprecated-components.integration.test.d.ts +8 -0
  5. package/dist/__tests__/integration/deprecated-components.integration.test.d.ts.map +1 -0
  6. package/dist/__tests__/integration/deprecated-components.integration.test.js +165 -0
  7. package/dist/__tests__/integration/deprecated-components.integration.test.js.map +1 -0
  8. package/dist/__tests__/integration/migrate.integration.test.d.ts +2 -0
  9. package/dist/__tests__/integration/migrate.integration.test.d.ts.map +1 -0
  10. package/dist/__tests__/integration/migrate.integration.test.js +64 -0
  11. package/dist/__tests__/integration/migrate.integration.test.js.map +1 -0
  12. package/dist/__tests__/integration/prepublish.integration.test.d.ts +2 -0
  13. package/dist/__tests__/integration/prepublish.integration.test.d.ts.map +1 -0
  14. package/dist/__tests__/integration/prepublish.integration.test.js +27 -0
  15. package/dist/__tests__/integration/prepublish.integration.test.js.map +1 -0
  16. package/dist/__tests__/integration/validate.integration.test.d.ts +2 -0
  17. package/dist/__tests__/integration/validate.integration.test.d.ts.map +1 -0
  18. package/dist/__tests__/integration/validate.integration.test.js +56 -0
  19. package/dist/__tests__/integration/validate.integration.test.js.map +1 -0
  20. package/dist/__tests__/unit/deploy-templates.test.d.ts +2 -0
  21. package/dist/__tests__/unit/deploy-templates.test.d.ts.map +1 -0
  22. package/dist/__tests__/unit/deploy-templates.test.js +124 -0
  23. package/dist/__tests__/unit/deploy-templates.test.js.map +1 -0
  24. package/dist/__tests__/unit/deprecated-components-sync.test.d.ts +2 -0
  25. package/dist/__tests__/unit/deprecated-components-sync.test.d.ts.map +1 -0
  26. package/dist/__tests__/unit/deprecated-components-sync.test.js +69 -0
  27. package/dist/__tests__/unit/deprecated-components-sync.test.js.map +1 -0
  28. package/dist/__tests__/unit/deps-sync.test.d.ts +14 -0
  29. package/dist/__tests__/unit/deps-sync.test.d.ts.map +1 -0
  30. package/dist/__tests__/unit/deps-sync.test.js +166 -0
  31. package/dist/__tests__/unit/deps-sync.test.js.map +1 -0
  32. package/dist/__tests__/unit/docs-config.test.d.ts +2 -0
  33. package/dist/__tests__/unit/docs-config.test.d.ts.map +1 -0
  34. package/dist/__tests__/unit/docs-config.test.js +288 -0
  35. package/dist/__tests__/unit/docs-config.test.js.map +1 -0
  36. package/dist/__tests__/unit/errors.test.d.ts +2 -0
  37. package/dist/__tests__/unit/errors.test.d.ts.map +1 -0
  38. package/dist/__tests__/unit/errors.test.js +27 -0
  39. package/dist/__tests__/unit/errors.test.js.map +1 -0
  40. package/dist/__tests__/unit/extract-hooks.test.d.ts +5 -0
  41. package/dist/__tests__/unit/extract-hooks.test.d.ts.map +1 -0
  42. package/dist/__tests__/unit/extract-hooks.test.js +205 -0
  43. package/dist/__tests__/unit/extract-hooks.test.js.map +1 -0
  44. package/dist/__tests__/unit/frontmatter-sync.test.d.ts +8 -0
  45. package/dist/__tests__/unit/frontmatter-sync.test.d.ts.map +1 -0
  46. package/dist/__tests__/unit/frontmatter-sync.test.js +26 -0
  47. package/dist/__tests__/unit/frontmatter-sync.test.js.map +1 -0
  48. package/dist/__tests__/unit/mdx-validator.test.d.ts +2 -0
  49. package/dist/__tests__/unit/mdx-validator.test.d.ts.map +1 -0
  50. package/dist/__tests__/unit/mdx-validator.test.js +264 -0
  51. package/dist/__tests__/unit/mdx-validator.test.js.map +1 -0
  52. package/dist/__tests__/unit/migrate-convert.test.d.ts +2 -0
  53. package/dist/__tests__/unit/migrate-convert.test.d.ts.map +1 -0
  54. package/dist/__tests__/unit/migrate-convert.test.js +297 -0
  55. package/dist/__tests__/unit/migrate-convert.test.js.map +1 -0
  56. package/dist/__tests__/unit/migrate-detect.test.d.ts +2 -0
  57. package/dist/__tests__/unit/migrate-detect.test.d.ts.map +1 -0
  58. package/dist/__tests__/unit/migrate-detect.test.js +35 -0
  59. package/dist/__tests__/unit/migrate-detect.test.js.map +1 -0
  60. package/dist/__tests__/unit/migrate-mdx.test.d.ts +2 -0
  61. package/dist/__tests__/unit/migrate-mdx.test.d.ts.map +1 -0
  62. package/dist/__tests__/unit/migrate-mdx.test.js +158 -0
  63. package/dist/__tests__/unit/migrate-mdx.test.js.map +1 -0
  64. package/dist/__tests__/unit/openapi.test.d.ts +2 -0
  65. package/dist/__tests__/unit/openapi.test.d.ts.map +1 -0
  66. package/dist/__tests__/unit/openapi.test.js +52 -0
  67. package/dist/__tests__/unit/openapi.test.js.map +1 -0
  68. package/dist/__tests__/unit/package-config.test.d.ts +2 -0
  69. package/dist/__tests__/unit/package-config.test.d.ts.map +1 -0
  70. package/dist/__tests__/unit/package-config.test.js +63 -0
  71. package/dist/__tests__/unit/package-config.test.js.map +1 -0
  72. package/dist/__tests__/unit/port.test.d.ts +2 -0
  73. package/dist/__tests__/unit/port.test.d.ts.map +1 -0
  74. package/dist/__tests__/unit/port.test.js +20 -0
  75. package/dist/__tests__/unit/port.test.js.map +1 -0
  76. package/dist/__tests__/unit/vendored-sync.test.d.ts +14 -0
  77. package/dist/__tests__/unit/vendored-sync.test.d.ts.map +1 -0
  78. package/dist/__tests__/unit/vendored-sync.test.js +90 -0
  79. package/dist/__tests__/unit/vendored-sync.test.js.map +1 -0
  80. package/dist/commands/broken-links.d.ts +11 -0
  81. package/dist/commands/broken-links.d.ts.map +1 -0
  82. package/dist/commands/broken-links.js +95 -0
  83. package/dist/commands/broken-links.js.map +1 -0
  84. package/dist/commands/clean.d.ts +7 -0
  85. package/dist/commands/clean.d.ts.map +1 -0
  86. package/dist/commands/clean.js +59 -0
  87. package/dist/commands/clean.js.map +1 -0
  88. package/dist/commands/deploy/cloudflare.d.ts +12 -0
  89. package/dist/commands/deploy/cloudflare.d.ts.map +1 -0
  90. package/dist/commands/deploy/cloudflare.js +409 -0
  91. package/dist/commands/deploy/cloudflare.js.map +1 -0
  92. package/dist/commands/deploy/templates.d.ts +23 -0
  93. package/dist/commands/deploy/templates.d.ts.map +1 -0
  94. package/dist/commands/deploy/templates.js +179 -0
  95. package/dist/commands/deploy/templates.js.map +1 -0
  96. package/dist/commands/deploy/types.d.ts +19 -0
  97. package/dist/commands/deploy/types.d.ts.map +1 -0
  98. package/dist/commands/deploy/types.js +5 -0
  99. package/dist/commands/deploy/types.js.map +1 -0
  100. package/dist/commands/dev.d.ts +14 -0
  101. package/dist/commands/dev.d.ts.map +1 -0
  102. package/dist/commands/dev.js +817 -0
  103. package/dist/commands/dev.js.map +1 -0
  104. package/dist/commands/doctor.d.ts +7 -0
  105. package/dist/commands/doctor.d.ts.map +1 -0
  106. package/dist/commands/doctor.js +159 -0
  107. package/dist/commands/doctor.js.map +1 -0
  108. package/dist/commands/init.d.ts +7 -0
  109. package/dist/commands/init.d.ts.map +1 -0
  110. package/dist/commands/init.js +96 -0
  111. package/dist/commands/init.js.map +1 -0
  112. package/dist/commands/migrate/convert-mdx.d.ts +50 -0
  113. package/dist/commands/migrate/convert-mdx.d.ts.map +1 -0
  114. package/dist/commands/migrate/convert-mdx.js +108 -0
  115. package/dist/commands/migrate/convert-mdx.js.map +1 -0
  116. package/dist/commands/migrate/convert.d.ts +80 -0
  117. package/dist/commands/migrate/convert.d.ts.map +1 -0
  118. package/dist/commands/migrate/convert.js +158 -0
  119. package/dist/commands/migrate/convert.js.map +1 -0
  120. package/dist/commands/migrate/detect.d.ts +31 -0
  121. package/dist/commands/migrate/detect.d.ts.map +1 -0
  122. package/dist/commands/migrate/detect.js +62 -0
  123. package/dist/commands/migrate/detect.js.map +1 -0
  124. package/dist/commands/migrate/extract-hooks.d.ts +71 -0
  125. package/dist/commands/migrate/extract-hooks.d.ts.map +1 -0
  126. package/dist/commands/migrate/extract-hooks.js +473 -0
  127. package/dist/commands/migrate/extract-hooks.js.map +1 -0
  128. package/dist/commands/migrate/index.d.ts +17 -0
  129. package/dist/commands/migrate/index.d.ts.map +1 -0
  130. package/dist/commands/migrate/index.js +282 -0
  131. package/dist/commands/migrate/index.js.map +1 -0
  132. package/dist/commands/migrate/prompts.d.ts +22 -0
  133. package/dist/commands/migrate/prompts.d.ts.map +1 -0
  134. package/dist/commands/migrate/prompts.js +67 -0
  135. package/dist/commands/migrate/prompts.js.map +1 -0
  136. package/dist/commands/migrate/types.d.ts +22 -0
  137. package/dist/commands/migrate/types.d.ts.map +1 -0
  138. package/dist/commands/migrate/types.js +26 -0
  139. package/dist/commands/migrate/types.js.map +1 -0
  140. package/dist/commands/openapi-check.d.ts +11 -0
  141. package/dist/commands/openapi-check.d.ts.map +1 -0
  142. package/dist/commands/openapi-check.js +88 -0
  143. package/dist/commands/openapi-check.js.map +1 -0
  144. package/dist/commands/rename.d.ts +10 -0
  145. package/dist/commands/rename.d.ts.map +1 -0
  146. package/dist/commands/rename.js +125 -0
  147. package/dist/commands/rename.js.map +1 -0
  148. package/dist/commands/update.d.ts +10 -0
  149. package/dist/commands/update.d.ts.map +1 -0
  150. package/dist/commands/update.js +57 -0
  151. package/dist/commands/update.js.map +1 -0
  152. package/dist/commands/validate.d.ts +12 -0
  153. package/dist/commands/validate.d.ts.map +1 -0
  154. package/dist/commands/validate.js +163 -0
  155. package/dist/commands/validate.js.map +1 -0
  156. package/dist/index.d.ts +9 -0
  157. package/dist/index.d.ts.map +1 -0
  158. package/dist/index.js +334 -0
  159. package/dist/index.js.map +1 -0
  160. package/dist/lib/config.d.ts +7 -0
  161. package/dist/lib/config.d.ts.map +1 -0
  162. package/dist/lib/config.js +18 -0
  163. package/dist/lib/config.js.map +1 -0
  164. package/dist/lib/deprecated-components.d.ts +72 -0
  165. package/dist/lib/deprecated-components.d.ts.map +1 -0
  166. package/dist/lib/deprecated-components.js +138 -0
  167. package/dist/lib/deprecated-components.js.map +1 -0
  168. package/dist/lib/deps.d.ts +17 -0
  169. package/dist/lib/deps.d.ts.map +1 -0
  170. package/dist/lib/deps.js +186 -0
  171. package/dist/lib/deps.js.map +1 -0
  172. package/dist/lib/docs-config.d.ts +67 -0
  173. package/dist/lib/docs-config.d.ts.map +1 -0
  174. package/dist/lib/docs-config.js +294 -0
  175. package/dist/lib/docs-config.js.map +1 -0
  176. package/dist/lib/errors.d.ts +23 -0
  177. package/dist/lib/errors.d.ts.map +1 -0
  178. package/dist/lib/errors.js +32 -0
  179. package/dist/lib/errors.js.map +1 -0
  180. package/dist/lib/frontmatter-utils.d.ts +25 -0
  181. package/dist/lib/frontmatter-utils.d.ts.map +1 -0
  182. package/dist/lib/frontmatter-utils.js +64 -0
  183. package/dist/lib/frontmatter-utils.js.map +1 -0
  184. package/dist/lib/mdx-validator.d.ts +27 -0
  185. package/dist/lib/mdx-validator.d.ts.map +1 -0
  186. package/dist/lib/mdx-validator.js +148 -0
  187. package/dist/lib/mdx-validator.js.map +1 -0
  188. package/dist/lib/navigation-validator.d.ts +31 -0
  189. package/dist/lib/navigation-validator.d.ts.map +1 -0
  190. package/dist/lib/navigation-validator.js +75 -0
  191. package/dist/lib/navigation-validator.js.map +1 -0
  192. package/dist/lib/normalize-config.d.ts +57 -0
  193. package/dist/lib/normalize-config.d.ts.map +1 -0
  194. package/dist/lib/normalize-config.js +63 -0
  195. package/dist/lib/normalize-config.js.map +1 -0
  196. package/dist/lib/openapi/cache.d.ts +40 -0
  197. package/dist/lib/openapi/cache.d.ts.map +1 -0
  198. package/dist/lib/openapi/cache.js +76 -0
  199. package/dist/lib/openapi/cache.js.map +1 -0
  200. package/dist/lib/openapi/errors.d.ts +36 -0
  201. package/dist/lib/openapi/errors.d.ts.map +1 -0
  202. package/dist/lib/openapi/errors.js +162 -0
  203. package/dist/lib/openapi/errors.js.map +1 -0
  204. package/dist/lib/openapi/index.d.ts +10 -0
  205. package/dist/lib/openapi/index.d.ts.map +1 -0
  206. package/dist/lib/openapi/index.js +12 -0
  207. package/dist/lib/openapi/index.js.map +1 -0
  208. package/dist/lib/openapi/types.d.ts +198 -0
  209. package/dist/lib/openapi/types.d.ts.map +1 -0
  210. package/dist/lib/openapi/types.js +8 -0
  211. package/dist/lib/openapi/types.js.map +1 -0
  212. package/dist/lib/openapi/validator.d.ts +45 -0
  213. package/dist/lib/openapi/validator.d.ts.map +1 -0
  214. package/dist/lib/openapi/validator.js +128 -0
  215. package/dist/lib/openapi/validator.js.map +1 -0
  216. package/dist/lib/openapi.d.ts +7 -0
  217. package/dist/lib/openapi.d.ts.map +1 -0
  218. package/dist/lib/openapi.js +7 -0
  219. package/dist/lib/openapi.js.map +1 -0
  220. package/dist/lib/output.d.ts +14 -0
  221. package/dist/lib/output.d.ts.map +1 -0
  222. package/dist/lib/output.js +19 -0
  223. package/dist/lib/output.js.map +1 -0
  224. package/dist/lib/path-security.d.ts +23 -0
  225. package/dist/lib/path-security.d.ts.map +1 -0
  226. package/dist/lib/path-security.js +35 -0
  227. package/dist/lib/path-security.js.map +1 -0
  228. package/dist/lib/port.d.ts +18 -0
  229. package/dist/lib/port.d.ts.map +1 -0
  230. package/dist/lib/port.js +65 -0
  231. package/dist/lib/port.js.map +1 -0
  232. package/dist/lib/spinner.d.ts +4 -0
  233. package/dist/lib/spinner.d.ts.map +1 -0
  234. package/dist/lib/spinner.js +16 -0
  235. package/dist/lib/spinner.js.map +1 -0
  236. package/dist/lib/version.d.ts +2 -0
  237. package/dist/lib/version.d.ts.map +1 -0
  238. package/dist/lib/version.js +49 -0
  239. package/dist/lib/version.js.map +1 -0
  240. package/dist/utils/update-checker.d.ts +34 -0
  241. package/dist/utils/update-checker.d.ts.map +1 -0
  242. package/dist/utils/update-checker.js +142 -0
  243. package/dist/utils/update-checker.js.map +1 -0
  244. package/package.json +125 -0
  245. package/templates/docs.json +11 -0
  246. package/templates/introduction.mdx +19 -0
  247. package/templates/quickstart.mdx +20 -0
  248. package/vendored/app/[[...slug]]/error.tsx +103 -0
  249. package/vendored/app/[[...slug]]/page.tsx +690 -0
  250. package/vendored/app/api/assets/[...path]/route.ts +78 -0
  251. package/vendored/app/api/ev/route.ts +61 -0
  252. package/vendored/app/api/isr-health/route.ts +66 -0
  253. package/vendored/app/api/mcp/[project]/route.ts +435 -0
  254. package/vendored/app/api/og/route.tsx +167 -0
  255. package/vendored/app/api/r2/[project]/[...path]/route.ts +214 -0
  256. package/vendored/app/api/revalidate/route.ts +76 -0
  257. package/vendored/app/globals.css +37 -0
  258. package/vendored/app/layout.tsx +571 -0
  259. package/vendored/app/not-found.tsx +47 -0
  260. package/vendored/components/CodeBlockCopyButton.tsx +146 -0
  261. package/vendored/components/HeaderLinkCopy.tsx +135 -0
  262. package/vendored/components/errors/NotFoundContent.tsx +147 -0
  263. package/vendored/components/layout/LayoutWrapper.tsx +128 -0
  264. package/vendored/components/mdx/Accordion.tsx +91 -0
  265. package/vendored/components/mdx/ApiCodePanel.tsx +51 -0
  266. package/vendored/components/mdx/ApiEndpoint.tsx +104 -0
  267. package/vendored/components/mdx/ApiPage.tsx +379 -0
  268. package/vendored/components/mdx/Badge.tsx +169 -0
  269. package/vendored/components/mdx/Callouts.tsx +140 -0
  270. package/vendored/components/mdx/Card.tsx +214 -0
  271. package/vendored/components/mdx/CodeGroup.tsx +136 -0
  272. package/vendored/components/mdx/Color.tsx +244 -0
  273. package/vendored/components/mdx/Columns.tsx +37 -0
  274. package/vendored/components/mdx/Expandable.tsx +37 -0
  275. package/vendored/components/mdx/Frame.tsx +51 -0
  276. package/vendored/components/mdx/Icon.tsx +132 -0
  277. package/vendored/components/mdx/Latex.tsx +75 -0
  278. package/vendored/components/mdx/MDXComponents.tsx +414 -0
  279. package/vendored/components/mdx/Mermaid.tsx +35 -0
  280. package/vendored/components/mdx/MermaidInner.tsx +342 -0
  281. package/vendored/components/mdx/OpenApiEndpoint.tsx +971 -0
  282. package/vendored/components/mdx/Panel.tsx +26 -0
  283. package/vendored/components/mdx/PanelWrapper.tsx +100 -0
  284. package/vendored/components/mdx/ParamField.tsx +75 -0
  285. package/vendored/components/mdx/RequestExample.tsx +91 -0
  286. package/vendored/components/mdx/ResponseExample.tsx +145 -0
  287. package/vendored/components/mdx/ResponseField.tsx +109 -0
  288. package/vendored/components/mdx/Steps.tsx +173 -0
  289. package/vendored/components/mdx/Table.tsx +352 -0
  290. package/vendored/components/mdx/Tabs.tsx +147 -0
  291. package/vendored/components/mdx/Tile.tsx +127 -0
  292. package/vendored/components/mdx/Tooltip.tsx +111 -0
  293. package/vendored/components/mdx/Tree.tsx +484 -0
  294. package/vendored/components/mdx/Update.tsx +90 -0
  295. package/vendored/components/mdx/View.tsx +354 -0
  296. package/vendored/components/mdx/YouTube.tsx +35 -0
  297. package/vendored/components/mdx/ZoomableImage.tsx +83 -0
  298. package/vendored/components/navigation/Breadcrumb.tsx +241 -0
  299. package/vendored/components/navigation/DefaultLogo.tsx +81 -0
  300. package/vendored/components/navigation/Header.tsx +512 -0
  301. package/vendored/components/navigation/LanguageSelector.tsx +249 -0
  302. package/vendored/components/navigation/PageNavigation.tsx +174 -0
  303. package/vendored/components/navigation/Sidebar.tsx +713 -0
  304. package/vendored/components/navigation/SocialFooter.tsx +186 -0
  305. package/vendored/components/navigation/TableOfContents.tsx +435 -0
  306. package/vendored/components/navigation/TabsNav.tsx +182 -0
  307. package/vendored/components/search/LazySearchModal.tsx +19 -0
  308. package/vendored/components/search/SearchModal.tsx +573 -0
  309. package/vendored/components/snippets/ProjectSnippets.tsx +4 -0
  310. package/vendored/components/theme/ThemeProvider.tsx +31 -0
  311. package/vendored/components/theme/ThemeToggle.tsx +134 -0
  312. package/vendored/components/ui/CodePanel.tsx +517 -0
  313. package/vendored/components/ui/CodePanelModal.tsx +342 -0
  314. package/vendored/contexts/TabSyncContext.tsx +30 -0
  315. package/vendored/hooks/useFocusTrap.ts +42 -0
  316. package/vendored/hooks/useHashNavigation.ts +39 -0
  317. package/vendored/hooks/useShikiHighlight.ts +101 -0
  318. package/vendored/lib/analytics-client.ts +77 -0
  319. package/vendored/lib/build/cache.ts +138 -0
  320. package/vendored/lib/build/error-parser.ts +690 -0
  321. package/vendored/lib/build/estimation.ts +113 -0
  322. package/vendored/lib/build/index.ts +17 -0
  323. package/vendored/lib/build/page-file-map.ts +48 -0
  324. package/vendored/lib/build/r2-upload.ts +179 -0
  325. package/vendored/lib/cache-keys.ts +117 -0
  326. package/vendored/lib/code-utils.ts +42 -0
  327. package/vendored/lib/content-loader.ts +176 -0
  328. package/vendored/lib/deprecated-components.ts +185 -0
  329. package/vendored/lib/docs-isr.ts +180 -0
  330. package/vendored/lib/docs-types.ts +874 -0
  331. package/vendored/lib/docs.ts +203 -0
  332. package/vendored/lib/domain-helpers.ts +107 -0
  333. package/vendored/lib/email-notifier.ts +102 -0
  334. package/vendored/lib/email-templates/build-failure.tsx +193 -0
  335. package/vendored/lib/email-templates/components/base-layout.tsx +150 -0
  336. package/vendored/lib/email-templates/components/error-box.tsx +88 -0
  337. package/vendored/lib/email-templates/components/info-row.tsx +63 -0
  338. package/vendored/lib/email-templates/index.ts +13 -0
  339. package/vendored/lib/empty-polyfill.js +3 -0
  340. package/vendored/lib/extract-highlights.ts +124 -0
  341. package/vendored/lib/fonts.ts +227 -0
  342. package/vendored/lib/frontmatter-utils.ts +77 -0
  343. package/vendored/lib/fs-utils.ts +20 -0
  344. package/vendored/lib/git-utils.ts +87 -0
  345. package/vendored/lib/health-checks.ts +224 -0
  346. package/vendored/lib/icon-utils.ts +492 -0
  347. package/vendored/lib/infer-page-type.ts +14 -0
  348. package/vendored/lib/isr-build-executor.ts +185 -0
  349. package/vendored/lib/language-icons.ts +152 -0
  350. package/vendored/lib/language-utils.ts +338 -0
  351. package/vendored/lib/latex-config.ts +64 -0
  352. package/vendored/lib/link-prefix-context.tsx +32 -0
  353. package/vendored/lib/logger.ts +63 -0
  354. package/vendored/lib/mcp-search.ts +255 -0
  355. package/vendored/lib/mdx-inline-components.ts +155 -0
  356. package/vendored/lib/mdx.ts +100 -0
  357. package/vendored/lib/middleware-helpers.ts +519 -0
  358. package/vendored/lib/navigation-resolver.ts +621 -0
  359. package/vendored/lib/navigation-utils.ts +103 -0
  360. package/vendored/lib/normalize-config.ts +94 -0
  361. package/vendored/lib/openapi/cache.ts +92 -0
  362. package/vendored/lib/openapi/code-examples.ts +389 -0
  363. package/vendored/lib/openapi/errors.ts +253 -0
  364. package/vendored/lib/openapi/generator.ts +230 -0
  365. package/vendored/lib/openapi/index.ts +84 -0
  366. package/vendored/lib/openapi/parser.ts +474 -0
  367. package/vendored/lib/openapi/types.ts +232 -0
  368. package/vendored/lib/openapi/validator.ts +156 -0
  369. package/vendored/lib/openapi-isr.ts +121 -0
  370. package/vendored/lib/page-isr-helpers.ts +137 -0
  371. package/vendored/lib/path-safety.ts +130 -0
  372. package/vendored/lib/paths.ts +35 -0
  373. package/vendored/lib/preprocess-mdx.ts +951 -0
  374. package/vendored/lib/process-mdx-with-exports.ts +75 -0
  375. package/vendored/lib/project-resolver.ts +165 -0
  376. package/vendored/lib/r2-content.ts +60 -0
  377. package/vendored/lib/r2-manifest.ts +84 -0
  378. package/vendored/lib/recent-searches.ts +41 -0
  379. package/vendored/lib/recma-compound-components.ts +84 -0
  380. package/vendored/lib/redirect-compiler.ts +160 -0
  381. package/vendored/lib/redirect-matcher.ts +296 -0
  382. package/vendored/lib/redis.ts +23 -0
  383. package/vendored/lib/rehype-class-to-classname.ts +31 -0
  384. package/vendored/lib/rehype-code-meta.ts +275 -0
  385. package/vendored/lib/rehype-nozoom-to-data.ts +45 -0
  386. package/vendored/lib/remark-extract-exports.ts +104 -0
  387. package/vendored/lib/resilience.ts +260 -0
  388. package/vendored/lib/revalidation-helpers.ts +200 -0
  389. package/vendored/lib/revalidation-trigger.ts +150 -0
  390. package/vendored/lib/screenshot-capture.ts +229 -0
  391. package/vendored/lib/search-client.ts +91 -0
  392. package/vendored/lib/search-suggestions.ts +38 -0
  393. package/vendored/lib/search.ts +158 -0
  394. package/vendored/lib/seo.ts +264 -0
  395. package/vendored/lib/shiki-client.ts +131 -0
  396. package/vendored/lib/shiki-config.ts +289 -0
  397. package/vendored/lib/shiki-css-theme.ts +46 -0
  398. package/vendored/lib/shiki-highlighter.ts +62 -0
  399. package/vendored/lib/shiki-transformers.ts +337 -0
  400. package/vendored/lib/slack-notifier.ts +248 -0
  401. package/vendored/lib/snippet-compiler-isr.ts +114 -0
  402. package/vendored/lib/snippet-loader-isr.ts +276 -0
  403. package/vendored/lib/static-artifacts.ts +375 -0
  404. package/vendored/lib/static-file-route.ts +72 -0
  405. package/vendored/lib/tracking-script.ts +19 -0
  406. package/vendored/lib/typography-config.ts +42 -0
  407. package/vendored/lib/validate-config.ts +268 -0
  408. package/vendored/next.config.js +45 -0
  409. package/vendored/postcss.config.js +6 -0
  410. package/vendored/schema/README.md +28 -0
  411. package/vendored/schema/docs-schema.json +4631 -0
  412. package/vendored/scripts/build-project.cjs +174 -0
  413. package/vendored/scripts/build-search-index.cjs +347 -0
  414. package/vendored/scripts/compile-snippets.cjs +488 -0
  415. package/vendored/scripts/copy-files.cjs +295 -0
  416. package/vendored/scripts/dev-project.cjs +534 -0
  417. package/vendored/scripts/enhance-navigation.cjs +354 -0
  418. package/vendored/scripts/validate-links.cjs +423 -0
  419. package/vendored/shared/constants.ts +6 -0
  420. package/vendored/shared/index.ts +19 -0
  421. package/vendored/shared/logger.ts +62 -0
  422. package/vendored/shared/memory-monitor.ts +190 -0
  423. package/vendored/shared/navigation-validator.ts +101 -0
  424. package/vendored/shared/path-security.ts +39 -0
  425. package/vendored/shared/status-reporter.ts +199 -0
  426. package/vendored/shared/timer.ts +51 -0
  427. package/vendored/shared/types.ts +102 -0
  428. package/vendored/tailwind.config.ts +39 -0
  429. package/vendored/themes/base.css +1311 -0
  430. package/vendored/themes/index.ts +119 -0
  431. package/vendored/themes/jam/variables.css +835 -0
  432. package/vendored/themes/nebula/variables.css +282 -0
  433. package/vendored/themes/pulsar/variables.css +1009 -0
  434. package/vendored/themes/types.ts +89 -0
  435. package/vendored/tsconfig.json +48 -0
@@ -0,0 +1,296 @@
1
+ /**
2
+ * Redirect Handling Module
3
+ *
4
+ * Fetches and matches redirects from _redirects.json in R2.
5
+ * Uses Upstash Redis for caching with 5-minute TTL.
6
+ */
7
+
8
+ import { redis } from './redis';
9
+ import { getFileBufferFromR2 } from './r2';
10
+
11
+ // Cache TTL in seconds (5 minutes)
12
+ const CACHE_TTL = 300;
13
+
14
+ // Redis cache key prefix
15
+ const CACHE_PREFIX = 'redirects:';
16
+
17
+ /**
18
+ * Redirect rule as stored in _redirects.json
19
+ */
20
+ export interface RedirectRule {
21
+ source: string;
22
+ destination: string;
23
+ permanent: boolean;
24
+ pattern: string;
25
+ hasWildcard: boolean;
26
+ // Pre-compiled regex for performance (added at runtime, not stored in JSON)
27
+ _compiledRegex?: RegExp;
28
+ }
29
+
30
+ /**
31
+ * Redirects file structure
32
+ */
33
+ interface RedirectsFile {
34
+ version: number;
35
+ generatedAt?: string;
36
+ redirects: RedirectRule[];
37
+ }
38
+
39
+ /**
40
+ * Match result with resolved destination
41
+ */
42
+ export interface RedirectMatch {
43
+ destination: string;
44
+ permanent: boolean;
45
+ }
46
+
47
+ /**
48
+ * Pre-compile regex patterns for wildcard rules.
49
+ * Mutates the rules array in place for performance.
50
+ */
51
+ function compileRedirectPatterns(rules: RedirectRule[]): void {
52
+ for (const rule of rules) {
53
+ if (!rule.hasWildcard || !rule.pattern || rule._compiledRegex) continue;
54
+
55
+ try {
56
+ rule._compiledRegex = new RegExp(rule.pattern);
57
+ } catch (e) {
58
+ console.error('[Redirects] Invalid regex pattern:', rule.pattern, e);
59
+ }
60
+ }
61
+ }
62
+
63
+ /**
64
+ * Fetch redirects for a project from R2 with Redis caching
65
+ * Returns null if no redirects file or error (fail open)
66
+ */
67
+ export async function getRedirects(projectName: string): Promise<RedirectRule[] | null> {
68
+ const cacheKey = `${CACHE_PREFIX}${projectName}`;
69
+
70
+ // Try cache first (if Redis is available)
71
+ if (redis) {
72
+ try {
73
+ const cached = await redis.get<RedirectsFile>(cacheKey);
74
+ if (cached && cached.redirects) {
75
+ // Pre-compile regex patterns (not serialized in Redis)
76
+ compileRedirectPatterns(cached.redirects);
77
+ return cached.redirects;
78
+ }
79
+ } catch (error) {
80
+ console.error('[Redirects] Redis cache read failed:', error);
81
+ // Continue to fetch from R2
82
+ }
83
+ }
84
+
85
+ // Fetch from R2
86
+ try {
87
+ const buffer = await getFileBufferFromR2(projectName, '_redirects.json');
88
+ if (!buffer) {
89
+ // No redirects file - cache the "no redirects" state to avoid repeated R2 lookups
90
+ if (redis) {
91
+ try {
92
+ await redis.set(cacheKey, { version: 1, redirects: [] }, { ex: CACHE_TTL });
93
+ } catch {
94
+ // Ignore cache write errors
95
+ }
96
+ }
97
+ return null;
98
+ }
99
+
100
+ const content = buffer.toString('utf-8');
101
+ const data: RedirectsFile = JSON.parse(content);
102
+
103
+ if (!data.redirects || !Array.isArray(data.redirects)) {
104
+ return null;
105
+ }
106
+
107
+ // Pre-compile regex patterns for wildcard rules
108
+ compileRedirectPatterns(data.redirects);
109
+
110
+ // Cache in Redis
111
+ if (redis) {
112
+ try {
113
+ await redis.set(cacheKey, data, { ex: CACHE_TTL });
114
+ } catch {
115
+ // Ignore cache write errors
116
+ }
117
+ }
118
+
119
+ return data.redirects;
120
+ } catch (error) {
121
+ console.error('[Redirects] Failed to fetch redirects for', projectName, error);
122
+ return null; // Fail open
123
+ }
124
+ }
125
+
126
+ /**
127
+ * Normalize a path by stripping trailing slash (except for root)
128
+ */
129
+ function normalizePath(pathname: string): string {
130
+ if (pathname === '/') return pathname;
131
+ return pathname.endsWith('/') ? pathname.slice(0, -1) : pathname;
132
+ }
133
+
134
+ /**
135
+ * Paths that should never be redirected (system paths).
136
+ * These are protected to prevent redirect loops and system breakage.
137
+ */
138
+ const PROTECTED_PATHS = [
139
+ '/api/',
140
+ '/_next/',
141
+ '/.well-known/',
142
+ ];
143
+
144
+ /**
145
+ * Check if a redirect destination is invalid.
146
+ * Invalid destinations include system paths and malformed patterns.
147
+ */
148
+ export function isInvalidDestination(destination: string): boolean {
149
+ // Destinations to system paths are invalid (would break the site)
150
+ for (const protected_path of PROTECTED_PATHS) {
151
+ if (destination.startsWith(protected_path)) {
152
+ return true;
153
+ }
154
+ }
155
+ // Destinations with unresolved wildcards are likely misconfigured
156
+ if (destination.includes('*')) {
157
+ return true;
158
+ }
159
+ return false;
160
+ }
161
+
162
+ /**
163
+ * Match a pathname against redirect rules
164
+ * Returns the matched redirect with resolved destination, or null if no match
165
+ */
166
+ // Max path length to process (limits ReDoS attack surface)
167
+ const MAX_PATH_LENGTH = 2048;
168
+
169
+ export function matchRedirect(
170
+ pathname: string,
171
+ redirects: RedirectRule[]
172
+ ): RedirectMatch | null {
173
+ // Never redirect protected system paths
174
+ for (const protected_path of PROTECTED_PATHS) {
175
+ if (pathname.startsWith(protected_path)) {
176
+ return null;
177
+ }
178
+ }
179
+
180
+ // Limit path length to reduce ReDoS attack surface
181
+ if (pathname.length > MAX_PATH_LENGTH) {
182
+ console.warn('[Redirects] Path too long, skipping redirect matching:', pathname.length);
183
+ return null;
184
+ }
185
+
186
+ // Normalize incoming path (strip trailing slash for matching)
187
+ const normalizedPath = normalizePath(pathname);
188
+
189
+ for (const rule of redirects) {
190
+ // Normalize rule source for matching
191
+ const normalizedSource = normalizePath(rule.source);
192
+
193
+ // Try exact match first (fast path)
194
+ if (!rule.hasWildcard && normalizedPath === normalizedSource) {
195
+ // Skip redirects with invalid destinations
196
+ if (isInvalidDestination(rule.destination)) {
197
+ console.warn('[Redirects] Skipping invalid destination:', normalizedPath, '->', rule.destination);
198
+ continue;
199
+ }
200
+ // Detect circular redirect (destination same as source)
201
+ const normalizedDest = normalizePath(rule.destination);
202
+ if (normalizedDest === normalizedPath) {
203
+ console.warn('[Redirects] Skipping circular redirect:', normalizedPath, '->', rule.destination);
204
+ continue;
205
+ }
206
+ return {
207
+ destination: rule.destination,
208
+ permanent: rule.permanent,
209
+ };
210
+ }
211
+
212
+ // Try pattern match for wildcards
213
+ if (rule.hasWildcard) {
214
+ // Use pre-compiled regex, skip rule if compilation failed
215
+ if (!rule._compiledRegex) continue;
216
+
217
+ // Safety: wrap regex match in try-catch to handle malformed patterns
218
+ // Note: This doesn't protect against ReDoS (catastrophic backtracking).
219
+ // Patterns should be validated at build time for production safety.
220
+ let match: RegExpMatchArray | null = null;
221
+ try {
222
+ match = normalizedPath.match(rule._compiledRegex);
223
+ } catch (error) {
224
+ console.error('[Redirects] Regex match failed:', rule.pattern, error);
225
+ continue; // Skip this rule
226
+ }
227
+
228
+ if (match) {
229
+ // Replace captured groups in destination
230
+ let destination = rule.destination;
231
+
232
+ // Handle :slug* style replacements
233
+ // The pattern captures groups, and destination uses :slug* placeholders
234
+ if (match.length > 1) {
235
+ // Replace :slug* in destination with captured value
236
+ const captured = match[1] || '';
237
+ destination = destination.replace(/:(\w+)\*/g, captured);
238
+
239
+ // Also handle trailing * in destination
240
+ if (destination.endsWith('/*')) {
241
+ destination = destination.slice(0, -2) + '/' + captured;
242
+ } else if (destination.endsWith('*')) {
243
+ destination = destination.slice(0, -1) + captured;
244
+ }
245
+ }
246
+
247
+ // Skip redirects with invalid destinations
248
+ if (isInvalidDestination(destination)) {
249
+ console.warn('[Redirects] Skipping invalid destination:', normalizedPath, '->', destination);
250
+ continue;
251
+ }
252
+
253
+ // Detect circular redirect (destination same as source after substitution)
254
+ const normalizedDest = normalizePath(destination);
255
+ if (normalizedDest === normalizedPath) {
256
+ console.warn('[Redirects] Skipping circular redirect:', normalizedPath, '->', destination);
257
+ continue;
258
+ }
259
+
260
+ return {
261
+ destination,
262
+ permanent: rule.permanent,
263
+ };
264
+ }
265
+ }
266
+ }
267
+
268
+ return null;
269
+ }
270
+
271
+ /**
272
+ * Merge query strings from source URL with destination
273
+ * Source query params take precedence on conflicts
274
+ */
275
+ export function mergeQueryStrings(
276
+ sourceSearch: string,
277
+ destinationPath: string
278
+ ): string {
279
+ // Parse source query string
280
+ const sourceParams = new URLSearchParams(sourceSearch);
281
+ if (sourceParams.toString() === '') {
282
+ return destinationPath; // No source params to merge
283
+ }
284
+
285
+ // Check if destination has query string
286
+ const [destPath, destSearch] = destinationPath.split('?');
287
+ const destParams = new URLSearchParams(destSearch || '');
288
+
289
+ // Merge: source params override destination params
290
+ for (const [key, value] of sourceParams) {
291
+ destParams.set(key, value);
292
+ }
293
+
294
+ const mergedSearch = destParams.toString();
295
+ return mergedSearch ? `${destPath}?${mergedSearch}` : destPath;
296
+ }
@@ -0,0 +1,23 @@
1
+ // DO NOT EDIT — this file is auto-synced from shared/. Edit the source in shared/ and run ./scripts/sync-shared.sh
2
+
3
+ /**
4
+ * Shared Redis Client Module
5
+ *
6
+ * Provides a singleton Upstash Redis client.
7
+ * Supports both UPSTASH_REDIS_* and KV_* environment variable naming conventions.
8
+ *
9
+ * SYNC TARGET: This file is the source of truth.
10
+ * Synced to: builder/build-service/lib, proxy/lib
11
+ */
12
+ import { Redis } from '@upstash/redis';
13
+
14
+ const redisUrl = process.env.UPSTASH_REDIS_REST_URL || process.env.KV_REST_API_URL;
15
+ const redisToken = process.env.UPSTASH_REDIS_REST_TOKEN || process.env.KV_REST_API_TOKEN;
16
+
17
+ export const redis = redisUrl && redisToken && redisUrl.startsWith('https://')
18
+ ? new Redis({ url: redisUrl, token: redisToken })
19
+ : null;
20
+
21
+ export function isRedisConfigured(): boolean {
22
+ return redis !== null;
23
+ }
@@ -0,0 +1,31 @@
1
+ import { visit } from 'unist-util-visit';
2
+ import type { Root, Element } from 'hast';
3
+
4
+ /**
5
+ * Rehype plugin to convert HTML `class` attributes to React `className`
6
+ *
7
+ * This fixes the React warning: "Invalid DOM property `class`. Did you mean `className`?"
8
+ * when MDX content contains raw HTML elements with class attributes.
9
+ */
10
+ export function rehypeClassToClassName() {
11
+ return (tree: Root) => {
12
+ visit(tree, 'element', (node: Element) => {
13
+ if (node.properties) {
14
+ // Check for both 'class' and 'className' as MDX might pass either
15
+ if ('class' in node.properties) {
16
+ const classValue = node.properties.class;
17
+ // Merge with existing className if present
18
+ if (node.properties.className) {
19
+ const existing = Array.isArray(node.properties.className)
20
+ ? node.properties.className.join(' ')
21
+ : node.properties.className;
22
+ node.properties.className = `${existing} ${classValue}`;
23
+ } else {
24
+ node.properties.className = classValue;
25
+ }
26
+ delete node.properties.class;
27
+ }
28
+ }
29
+ });
30
+ };
31
+ }
@@ -0,0 +1,275 @@
1
+ import { visit } from 'unist-util-visit';
2
+ import type { Root, Element } from 'hast';
3
+ import type { Plugin } from 'unified';
4
+
5
+ /**
6
+ * Parsed code fence metadata
7
+ */
8
+ export interface CodeMeta {
9
+ /** Custom icon class (e.g., "fa-solid fa-terminal") */
10
+ icon?: string;
11
+ /** Title/filename to display in header (e.g., "utils.js") */
12
+ title?: string;
13
+ /** Line numbers to highlight (e.g., [1, 3, 4, 5, 10]) */
14
+ highlightLines?: number[];
15
+ /** Whether to show line numbers */
16
+ showLineNumbers?: boolean;
17
+ /** Starting line number (default: 1) */
18
+ startLine?: number;
19
+ /** Remaining meta string (status codes, etc.) */
20
+ meta?: string;
21
+ }
22
+
23
+ /**
24
+ * Parse icon attribute from meta string
25
+ * Supports: icon="fa-solid fa-terminal" or icon='custom-icon'
26
+ */
27
+ function parseIcon(meta: string): string | undefined {
28
+ const match = meta.match(/icon=["']([^"']+)["']/);
29
+ return match ? match[1] : undefined;
30
+ }
31
+
32
+ /**
33
+ * Parse title attribute from meta string
34
+ * Supports: title="filename.js" or title='utils.ts'
35
+ */
36
+ function parseTitle(meta: string): string | undefined {
37
+ const match = meta.match(/title=["']([^"']+)["']/);
38
+ return match ? match[1] : undefined;
39
+ }
40
+
41
+ /**
42
+ * Parse line highlight ranges from meta string
43
+ * Supports: {1}, {1,3}, {1-5}, {1,3-5,10}
44
+ * Returns array of individual line numbers
45
+ */
46
+ function parseHighlightLines(meta: string): number[] | undefined {
47
+ const match = meta.match(/\{([^}]+)\}/);
48
+ if (!match) return undefined;
49
+
50
+ const lines: number[] = [];
51
+ const parts = match[1].split(',');
52
+
53
+ for (const part of parts) {
54
+ const trimmed = part.trim();
55
+ if (trimmed.includes('-')) {
56
+ // Range: "3-5" -> [3, 4, 5]
57
+ const [start, end] = trimmed.split('-').map(Number);
58
+ if (!isNaN(start) && !isNaN(end)) {
59
+ for (let i = start; i <= end; i++) {
60
+ lines.push(i);
61
+ }
62
+ }
63
+ } else {
64
+ // Single number: "3" -> [3]
65
+ const num = Number(trimmed);
66
+ if (!isNaN(num)) {
67
+ lines.push(num);
68
+ }
69
+ }
70
+ }
71
+
72
+ return lines.length > 0 ? lines : undefined;
73
+ }
74
+
75
+ /**
76
+ * Parse showLineNumbers flag from meta string
77
+ */
78
+ function parseShowLineNumbers(meta: string): boolean {
79
+ return /\bshowLineNumbers\b/.test(meta);
80
+ }
81
+
82
+ /**
83
+ * Parse startLine attribute from meta string
84
+ * Supports: startLine=10 or startLine="10"
85
+ */
86
+ function parseStartLine(meta: string): number | undefined {
87
+ const match = meta.match(/startLine=["']?(\d+)["']?/);
88
+ if (match) {
89
+ const num = Number(match[1]);
90
+ return !isNaN(num) ? num : undefined;
91
+ }
92
+ return undefined;
93
+ }
94
+
95
+ /**
96
+ * Remove parsed attributes from meta string
97
+ */
98
+ function cleanMeta(meta: string): string {
99
+ return meta
100
+ .replace(/\s*icon=["'][^"']+["']\s*/g, ' ')
101
+ .replace(/\s*title=["'][^"']+["']\s*/g, ' ')
102
+ .replace(/\s*\{[^}]+\}\s*/g, ' ')
103
+ .replace(/\s*showLineNumbers\s*/g, ' ')
104
+ .replace(/\s*startLine=["']?\d+["']?\s*/g, ' ')
105
+ .trim();
106
+ }
107
+
108
+ /**
109
+ * Parse all code fence metadata from meta string
110
+ */
111
+ export function parseCodeMeta(meta: string): CodeMeta {
112
+ const explicitTitle = parseTitle(meta);
113
+ const cleanedMeta = cleanMeta(meta);
114
+
115
+ // If no explicit title= attribute but there's remaining text after parsing,
116
+ // use that text as the title (e.g., "Header" in ```json Header)
117
+ const fallbackTitle = !explicitTitle && cleanedMeta ? cleanedMeta : undefined;
118
+
119
+ return {
120
+ icon: parseIcon(meta),
121
+ title: explicitTitle || fallbackTitle,
122
+ highlightLines: parseHighlightLines(meta),
123
+ showLineNumbers: parseShowLineNumbers(meta),
124
+ startLine: parseStartLine(meta),
125
+ // Only include meta if we didn't use it as the title
126
+ meta: explicitTitle ? cleanedMeta || undefined : undefined,
127
+ };
128
+ }
129
+
130
+ /**
131
+ * Rehype plugin to pass code fence meta strings as data attributes
132
+ *
133
+ * Parses:
134
+ * - icon="fa-solid fa-terminal" → data-icon
135
+ * - title="filename.js" → data-title
136
+ * - {1,3-5} → data-highlight-lines (JSON array)
137
+ * - showLineNumbers → data-show-line-numbers
138
+ * - startLine=10 → data-start-line
139
+ * - Remaining text → data-meta (e.g., "200: Success")
140
+ *
141
+ * Attributes are added to both the code element and parent pre element
142
+ * so they're accessible from both React component mappings.
143
+ */
144
+ export function rehypeCodeMeta() {
145
+ return (tree: Root) => {
146
+ visit(tree, 'element', (node: Element, _index, parent) => {
147
+ if (node.tagName === 'code' && node.data?.meta) {
148
+ const meta = node.data.meta as string;
149
+ const parsed = parseCodeMeta(meta);
150
+
151
+ // DEBUG: Log what we're parsing
152
+
153
+ node.properties = node.properties || {};
154
+
155
+ // Store parsed data in node.data so Shiki transformers can access it
156
+ node.data = node.data || {};
157
+ (node.data as any).parsedMeta = parsed;
158
+
159
+ if (parsed.icon) {
160
+ node.properties['data-icon'] = parsed.icon;
161
+ }
162
+ if (parsed.title) {
163
+ node.properties['data-title'] = parsed.title;
164
+ }
165
+ if (parsed.highlightLines) {
166
+ node.properties['data-highlight-lines'] = JSON.stringify(parsed.highlightLines);
167
+ }
168
+ if (parsed.showLineNumbers) {
169
+ node.properties['data-show-line-numbers'] = 'true';
170
+ }
171
+ if (parsed.startLine !== undefined) {
172
+ node.properties['data-start-line'] = String(parsed.startLine);
173
+ }
174
+ if (parsed.meta) {
175
+ node.properties['data-meta'] = parsed.meta;
176
+ }
177
+
178
+ // Also add title to parent pre element for easier access in MDX components
179
+ if (parsed.title && parent && (parent as Element).tagName === 'pre') {
180
+ const preNode = parent as Element;
181
+ preNode.properties = preNode.properties || {};
182
+ preNode.properties['data-title'] = parsed.title;
183
+ // Store in parent data as well
184
+ preNode.data = preNode.data || {};
185
+ (preNode.data as any).parsedTitle = parsed.title;
186
+ }
187
+ }
188
+ });
189
+ };
190
+ }
191
+
192
+ /**
193
+ * Common language names and their variants used in CodeGroup tabs
194
+ * These should NOT be converted to titles
195
+ */
196
+ const LANGUAGE_LABELS = new Set([
197
+ // Language names
198
+ 'javascript', 'typescript', 'python', 'java', 'ruby', 'php', 'go', 'rust',
199
+ 'c', 'cpp', 'csharp', 'c#', 'swift', 'kotlin', 'scala', 'r', 'perl',
200
+ 'bash', 'shell', 'sh', 'powershell', 'cmd',
201
+ 'html', 'css', 'scss', 'sass', 'less',
202
+ 'json', 'xml', 'yaml', 'yml', 'toml', 'ini', 'csv',
203
+ 'sql', 'graphql', 'markdown', 'md',
204
+ // Short forms and variants
205
+ 'js', 'ts', 'py', 'rb', 'cs', 'rs', 'kt',
206
+ // Tool names often used as labels
207
+ 'curl', 'wget', 'npm', 'yarn', 'pip', 'gem', 'cargo', 'gradle', 'maven',
208
+ 'docker', 'git', 'node', 'deno', 'bun',
209
+ ]);
210
+
211
+ /**
212
+ * Check if a meta string looks like a language/tool label vs. a title
213
+ */
214
+ function isLanguageLabel(meta: string, language?: string): boolean {
215
+ const normalized = meta.toLowerCase().trim();
216
+
217
+ // Check if it's in our language labels set
218
+ if (LANGUAGE_LABELS.has(normalized)) {
219
+ return true;
220
+ }
221
+
222
+ // Check if it matches the language (e.g., "JavaScript" for lang="javascript")
223
+ if (language && normalized === language.toLowerCase()) {
224
+ return true;
225
+ }
226
+
227
+ return false;
228
+ }
229
+
230
+ /**
231
+ * Rehype plugin that restores data-title attributes after Shiki processing
232
+ *
233
+ * This plugin runs AFTER Shiki and converts data-meta to data-title for standalone code blocks.
234
+ *
235
+ * IMPORTANT: Preserves data-meta as tab labels for CodeGroup by detecting when data-meta
236
+ * contains language/tool names (e.g., "JavaScript", "cURL", "Python") vs. actual titles
237
+ * (e.g., "Header", "Request Headers", "Configuration").
238
+ */
239
+ /**
240
+ * Check if meta string is a code fence feature (not a title)
241
+ * Features like showLineNumbers, {1,3-5}, startLine=N should not become titles
242
+ */
243
+ function isCodeFenceFeature(meta: string): boolean {
244
+ const trimmed = meta.trim();
245
+ // Line highlighting: {1}, {1,3-5}, etc.
246
+ if (/^\{[\d,\-\s]+\}$/.test(trimmed)) return true;
247
+ // showLineNumbers flag
248
+ if (/^showLineNumbers(\s|$)/.test(trimmed)) return true;
249
+ // startLine=N
250
+ if (/^startLine=/.test(trimmed)) return true;
251
+ // Multiple features combined (no actual title)
252
+ if (/^(showLineNumbers|\{[\d,\-\s]+\}|startLine=\d+)(\s+(showLineNumbers|\{[\d,\-\s]+\}|startLine=\d+))*$/.test(trimmed)) return true;
253
+ return false;
254
+ }
255
+
256
+ export const rehypeRestoreDataTitle: Plugin<[], Root> = () => {
257
+ return (tree: Root) => {
258
+ visit(tree, 'element', (node: Element) => {
259
+ if (node.tagName === 'pre' && node.properties) {
260
+ const dataMeta = node.properties['data-meta'] as string | undefined;
261
+ const dataLanguage = node.properties['data-language'] as string | undefined;
262
+
263
+ // Only convert data-meta to data-title if:
264
+ // 1. data-meta exists
265
+ // 2. It doesn't look like a status code (no colon)
266
+ // 3. It's not a language/tool label (which CodeGroup uses for tabs)
267
+ // 4. It's not just code fence features (showLineNumbers, {1,3-5}, startLine=N)
268
+ if (dataMeta && !dataMeta.includes(':') && !isLanguageLabel(dataMeta, dataLanguage) && !isCodeFenceFeature(dataMeta)) {
269
+ node.properties['data-title'] = dataMeta;
270
+ }
271
+ }
272
+ });
273
+ };
274
+ };
275
+
@@ -0,0 +1,45 @@
1
+ import { visit } from 'unist-util-visit';
2
+ import type { Root, Element } from 'hast';
3
+
4
+ /**
5
+ * Rehype plugin to convert custom image attributes to data attributes.
6
+ *
7
+ * Converts:
8
+ * - `noZoom` → `data-no-zoom` (disables image zoom on click)
9
+ * - `noStyle` → `data-no-style` (disables default image styling)
10
+ *
11
+ * Fixes React warning: "React does not recognize the `noZoom` prop on a DOM element"
12
+ * when MDX content uses <img noZoom ... /> or <img noStyle ... /> syntax.
13
+ *
14
+ * Note: This is a backup mechanism. The primary conversion happens in
15
+ * preprocess-mdx.ts at the text level before MDX parsing.
16
+ */
17
+ export function rehypeNoZoomToData() {
18
+ return (tree: Root) => {
19
+ visit(tree, 'element', (node: Element) => {
20
+ if (node.properties) {
21
+ // Convert noZoom to data-no-zoom
22
+ // Check both camelCase (JSX) and lowercase (HTML) versions
23
+ if ('noZoom' in node.properties) {
24
+ node.properties['data-no-zoom'] = node.properties.noZoom;
25
+ delete node.properties.noZoom;
26
+ }
27
+ if ('nozoom' in node.properties) {
28
+ node.properties['data-no-zoom'] = node.properties.nozoom;
29
+ delete node.properties.nozoom;
30
+ }
31
+
32
+ // Convert noStyle to data-no-style
33
+ // Check both camelCase (JSX) and lowercase (HTML) versions
34
+ if ('noStyle' in node.properties) {
35
+ node.properties['data-no-style'] = node.properties.noStyle;
36
+ delete node.properties.noStyle;
37
+ }
38
+ if ('nostyle' in node.properties) {
39
+ node.properties['data-no-style'] = node.properties.nostyle;
40
+ delete node.properties.nostyle;
41
+ }
42
+ }
43
+ });
44
+ };
45
+ }