zudoku 0.65.3 → 0.66.1

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 (274) hide show
  1. package/dist/app/sentry.js +1 -1
  2. package/dist/config/validators/BuildSchema.js +18 -3
  3. package/dist/config/validators/BuildSchema.js.map +1 -1
  4. package/dist/config/validators/validate.d.ts +45 -5
  5. package/dist/config/validators/validate.js +7 -2
  6. package/dist/config/validators/validate.js.map +1 -1
  7. package/dist/flat-config.d.ts +10 -3
  8. package/dist/lib/authentication/ui/ZudokuAuthUi.js +5 -1
  9. package/dist/lib/authentication/ui/ZudokuAuthUi.js.map +1 -1
  10. package/dist/lib/components/Mermaid.d.ts +7 -0
  11. package/dist/lib/components/Mermaid.js +42 -0
  12. package/dist/lib/components/Mermaid.js.map +1 -0
  13. package/dist/lib/components/PagefindSearchMeta.d.ts +8 -0
  14. package/dist/lib/components/PagefindSearchMeta.js +7 -0
  15. package/dist/lib/components/PagefindSearchMeta.js.map +1 -0
  16. package/dist/lib/components/Zudoku.js +2 -5
  17. package/dist/lib/components/Zudoku.js.map +1 -1
  18. package/dist/lib/core/RouteGuard.js +1 -1
  19. package/dist/lib/core/RouteGuard.js.map +1 -1
  20. package/dist/lib/core/plugins.d.ts +3 -3
  21. package/dist/lib/oas/parser/index.d.ts +1 -0
  22. package/dist/lib/oas/parser/index.js.map +1 -1
  23. package/dist/lib/plugins/openapi/DownloadSchemaButton.d.ts +3 -0
  24. package/dist/lib/plugins/openapi/DownloadSchemaButton.js +47 -0
  25. package/dist/lib/plugins/openapi/DownloadSchemaButton.js.map +1 -0
  26. package/dist/lib/plugins/openapi/Endpoint.js +3 -6
  27. package/dist/lib/plugins/openapi/Endpoint.js.map +1 -1
  28. package/dist/lib/plugins/openapi/OasProvider.js +22 -13
  29. package/dist/lib/plugins/openapi/OasProvider.js.map +1 -1
  30. package/dist/lib/plugins/openapi/OperationList.js +12 -6
  31. package/dist/lib/plugins/openapi/OperationList.js.map +1 -1
  32. package/dist/lib/plugins/openapi/OperationListItem.js +2 -2
  33. package/dist/lib/plugins/openapi/OperationListItem.js.map +1 -1
  34. package/dist/lib/plugins/openapi/SchemaList.js +2 -1
  35. package/dist/lib/plugins/openapi/SchemaList.js.map +1 -1
  36. package/dist/lib/plugins/openapi/index.js +11 -5
  37. package/dist/lib/plugins/openapi/index.js.map +1 -1
  38. package/dist/lib/plugins/openapi/interfaces.d.ts +16 -13
  39. package/dist/lib/plugins/openapi/playground/Playground.js +1 -1
  40. package/dist/lib/plugins/openapi/playground/Playground.js.map +1 -1
  41. package/dist/lib/plugins/openapi/schema/SchemaView.d.ts +1 -1
  42. package/dist/lib/plugins/openapi/schema/SchemaView.js +14 -6
  43. package/dist/lib/plugins/openapi/schema/SchemaView.js.map +1 -1
  44. package/dist/lib/plugins/openapi/schema/utils.d.ts +2 -2
  45. package/dist/lib/plugins/openapi/schema/utils.js.map +1 -1
  46. package/dist/lib/plugins/openapi/util/getRoutes.d.ts +6 -1
  47. package/dist/lib/plugins/openapi/util/getRoutes.js +29 -2
  48. package/dist/lib/plugins/openapi/util/getRoutes.js.map +1 -1
  49. package/dist/lib/plugins/search-pagefind/IndexingDialog.d.ts +3 -0
  50. package/dist/lib/plugins/search-pagefind/IndexingDialog.js +64 -0
  51. package/dist/lib/plugins/search-pagefind/IndexingDialog.js.map +1 -0
  52. package/dist/lib/plugins/search-pagefind/PagefindSearch.js +22 -5
  53. package/dist/lib/plugins/search-pagefind/PagefindSearch.js.map +1 -1
  54. package/dist/lib/plugins/search-pagefind/ResultList.js +5 -4
  55. package/dist/lib/plugins/search-pagefind/ResultList.js.map +1 -1
  56. package/dist/lib/shiki.d.ts +1 -1
  57. package/dist/lib/shiki.js +18 -12
  58. package/dist/lib/shiki.js.map +1 -1
  59. package/dist/lib/ui/Button.d.ts +2 -2
  60. package/dist/lib/ui/Button.js +9 -8
  61. package/dist/lib/ui/Button.js.map +1 -1
  62. package/dist/lib/ui/ButtonGroup.d.ts +11 -0
  63. package/dist/lib/ui/ButtonGroup.js +28 -0
  64. package/dist/lib/ui/ButtonGroup.js.map +1 -0
  65. package/dist/lib/ui/Command.js +2 -2
  66. package/dist/lib/ui/Command.js.map +1 -1
  67. package/dist/lib/ui/DropdownMenu.d.ts +21 -23
  68. package/dist/lib/ui/DropdownMenu.js +47 -32
  69. package/dist/lib/ui/DropdownMenu.js.map +1 -1
  70. package/dist/lib/ui/Kbd.d.ts +3 -0
  71. package/dist/lib/ui/Kbd.js +10 -0
  72. package/dist/lib/ui/Kbd.js.map +1 -0
  73. package/dist/lib/util/MdxComponents.d.ts +1 -0
  74. package/dist/lib/util/MdxComponents.js +2 -0
  75. package/dist/lib/util/MdxComponents.js.map +1 -1
  76. package/dist/lib/util/flattenAllOf.js +27 -4
  77. package/dist/lib/util/flattenAllOf.js.map +1 -1
  78. package/dist/lib/util/flattenAllOf.test.js +67 -12
  79. package/dist/lib/util/flattenAllOf.test.js.map +1 -1
  80. package/dist/vite/api/SchemaManager.d.ts +5 -0
  81. package/dist/vite/api/SchemaManager.js +24 -0
  82. package/dist/vite/api/SchemaManager.js.map +1 -1
  83. package/dist/vite/api/SchemaManager.test.js +67 -0
  84. package/dist/vite/api/SchemaManager.test.js.map +1 -1
  85. package/dist/vite/config.js +8 -2
  86. package/dist/vite/config.js.map +1 -1
  87. package/dist/vite/dev-server.js +25 -0
  88. package/dist/vite/dev-server.js.map +1 -1
  89. package/dist/vite/pagefind-dev-index.d.ts +16 -0
  90. package/dist/vite/pagefind-dev-index.js +68 -0
  91. package/dist/vite/pagefind-dev-index.js.map +1 -0
  92. package/dist/vite/plugin-api.js +41 -3
  93. package/dist/vite/plugin-api.js.map +1 -1
  94. package/dist/vite/prerender/prerender.js +1 -19
  95. package/dist/vite/prerender/prerender.js.map +1 -1
  96. package/dist/vite/prerender/utils.d.ts +2 -0
  97. package/dist/vite/prerender/utils.js +24 -0
  98. package/dist/vite/prerender/utils.js.map +1 -0
  99. package/lib/ActionButton-DUgvSylL.js +25 -0
  100. package/lib/ActionButton-DUgvSylL.js.map +1 -0
  101. package/lib/Button-CynVW1JV.js +53 -0
  102. package/lib/Button-CynVW1JV.js.map +1 -0
  103. package/lib/ClaudeLogo-B4Xxt-x_.js +69 -0
  104. package/lib/ClaudeLogo-B4Xxt-x_.js.map +1 -0
  105. package/lib/{Command-CUcrW3qs.js → Command-BpT1iBE6.js} +25 -25
  106. package/lib/Command-BpT1iBE6.js.map +1 -0
  107. package/lib/Drawer-Ci7XwhqT.js.map +1 -1
  108. package/lib/DropdownMenu-C8SX_-S_.js +104 -0
  109. package/lib/DropdownMenu-C8SX_-S_.js.map +1 -0
  110. package/lib/{ErrorAlert-D5LKLFOd.js → ErrorAlert-DrOR8w3f.js} +1017 -1015
  111. package/lib/{ErrorAlert-D5LKLFOd.js.map → ErrorAlert-DrOR8w3f.js.map} +1 -1
  112. package/lib/IndexingDialog-B5zCiUKr.js +100 -0
  113. package/lib/IndexingDialog-B5zCiUKr.js.map +1 -0
  114. package/lib/MdxPage-BagO2c-n.js +210 -0
  115. package/lib/MdxPage-BagO2c-n.js.map +1 -0
  116. package/lib/Mermaid-D_VSX7_Q.js +102 -0
  117. package/lib/Mermaid-D_VSX7_Q.js.map +1 -0
  118. package/lib/{OAuthErrorPage-oXnxcJg4.js → OAuthErrorPage-Fq54RLgt.js} +7 -7
  119. package/lib/{OAuthErrorPage-oXnxcJg4.js.map → OAuthErrorPage-Fq54RLgt.js.map} +1 -1
  120. package/lib/OasProvider-DPH8mwDa.js +40 -0
  121. package/lib/OasProvider-DPH8mwDa.js.map +1 -0
  122. package/lib/{OperationList-CmMoKpGu.js → OperationList-C0jiEaG5.js} +1670 -1573
  123. package/lib/OperationList-C0jiEaG5.js.map +1 -0
  124. package/lib/{RouteGuard-Brz95MSt.js → RouteGuard-9wjejsKm.js} +19 -19
  125. package/lib/{RouteGuard-Brz95MSt.js.map → RouteGuard-9wjejsKm.js.map} +1 -1
  126. package/lib/{RouterError-VGZB_wg4.js → RouterError-DSLXagd5.js} +3 -3
  127. package/lib/{RouterError-VGZB_wg4.js.map → RouterError-DSLXagd5.js.map} +1 -1
  128. package/lib/{SchemaList-BykD27ga.js → SchemaList-BU0zCHn9.js} +28 -27
  129. package/lib/SchemaList-BU0zCHn9.js.map +1 -0
  130. package/lib/{SchemaView-Dt6hbCAt.js → SchemaView-DVae4RO2.js} +198 -187
  131. package/lib/SchemaView-DVae4RO2.js.map +1 -0
  132. package/lib/Select-CkxXP5I7.js +243 -0
  133. package/lib/Select-CkxXP5I7.js.map +1 -0
  134. package/lib/Separator-CTPSeW1S.js +27 -0
  135. package/lib/Separator-CTPSeW1S.js.map +1 -0
  136. package/lib/{SignUp-D2mmQOkg.js → SignUp-BjS4ozA7.js} +13 -13
  137. package/lib/{SignUp-D2mmQOkg.js.map → SignUp-BjS4ozA7.js.map} +1 -1
  138. package/lib/{SyntaxHighlight-C19vH0V_.js → SyntaxHighlight-Kdyskw3C.js} +654 -622
  139. package/lib/SyntaxHighlight-Kdyskw3C.js.map +1 -0
  140. package/lib/{Toc-CBWfFCVf.js → Toc-DJxFPfcS.js} +2 -2
  141. package/lib/{Toc-CBWfFCVf.js.map → Toc-DJxFPfcS.js.map} +1 -1
  142. package/lib/{ZudokuContext-BUZ5hkWB.js → ZudokuContext-BXldanA8.js} +11 -11
  143. package/lib/{ZudokuContext-BUZ5hkWB.js.map → ZudokuContext-BXldanA8.js.map} +1 -1
  144. package/lib/___vite-browser-external_commonjs-proxy-Cga3HsWk.js +9 -0
  145. package/lib/___vite-browser-external_commonjs-proxy-Cga3HsWk.js.map +1 -0
  146. package/lib/{chunk-PVWAREVJ-BMhpCH5D.js → chunk-PVWAREVJ-dLIqswPy.js} +5 -5
  147. package/lib/{chunk-PVWAREVJ-BMhpCH5D.js.map → chunk-PVWAREVJ-dLIqswPy.js.map} +1 -1
  148. package/lib/{circular-CNHs4gAz.js → circular-CzWF1hj5.js} +2 -2
  149. package/lib/{circular-CNHs4gAz.js.map → circular-CzWF1hj5.js.map} +1 -1
  150. package/lib/createServer-BIr2_tGn.js +16693 -0
  151. package/lib/createServer-BIr2_tGn.js.map +1 -0
  152. package/lib/createVariantComponent-B9_dVBvu.js +35 -0
  153. package/lib/createVariantComponent-B9_dVBvu.js.map +1 -0
  154. package/lib/{errors-D7xzOd8X.js → errors-Bs4duWDy.js} +3 -3
  155. package/lib/{errors-D7xzOd8X.js.map → errors-Bs4duWDy.js.map} +1 -1
  156. package/lib/firebase-qUdSEL1p.js +7366 -0
  157. package/lib/firebase-qUdSEL1p.js.map +1 -0
  158. package/lib/{hook-CMeoxziF.js → hook-BNxidGQq.js} +3 -3
  159. package/lib/{hook-CMeoxziF.js.map → hook-BNxidGQq.js.map} +1 -1
  160. package/lib/{index-unv8c40u.js → index-0oT9beQN.js} +568 -576
  161. package/lib/index-0oT9beQN.js.map +1 -0
  162. package/lib/{index-CF7_erXq.js → index-Bh-MffiL.js} +2 -2
  163. package/lib/{index-CF7_erXq.js.map → index-Bh-MffiL.js.map} +1 -1
  164. package/lib/{index-CPws05Tb.js → index-CCmMJp02.js} +10 -10
  165. package/lib/{index-CPws05Tb.js.map → index-CCmMJp02.js.map} +1 -1
  166. package/lib/index-CrcNWbel.js.map +1 -1
  167. package/lib/index-Css56y3F.js +133 -0
  168. package/lib/index-Css56y3F.js.map +1 -0
  169. package/lib/{index.esm-BnYHxCYC.js → index.esm-DtzT_KoE.js} +20 -20
  170. package/lib/{index.esm-BnYHxCYC.js.map → index.esm-DtzT_KoE.js.map} +1 -1
  171. package/lib/index.esm-kW-Utcsi.js +32 -0
  172. package/lib/index.esm-kW-Utcsi.js.map +1 -0
  173. package/lib/{invariant-Bm-FVUQE.js → invariant-CGOLuIIz.js} +3 -3
  174. package/lib/{invariant-Bm-FVUQE.js.map → invariant-CGOLuIIz.js.map} +1 -1
  175. package/lib/{mutation-BSU0xu4m.js → mutation-BoVlx8yA.js} +2 -2
  176. package/lib/{mutation-BSU0xu4m.js.map → mutation-BoVlx8yA.js.map} +1 -1
  177. package/lib/ui/ActionButton.js +1 -1
  178. package/lib/ui/Button.js +25 -24
  179. package/lib/ui/Button.js.map +1 -1
  180. package/lib/ui/ButtonGroup.js +77 -0
  181. package/lib/ui/ButtonGroup.js.map +1 -0
  182. package/lib/ui/Command.js +3 -3
  183. package/lib/ui/Command.js.map +1 -1
  184. package/lib/ui/DropdownMenu.js +227 -140
  185. package/lib/ui/DropdownMenu.js.map +1 -1
  186. package/lib/ui/Kbd.js +32 -0
  187. package/lib/ui/Kbd.js.map +1 -0
  188. package/lib/ui/SyntaxHighlight.js +3 -3
  189. package/lib/useMutation-C6RqWmTS.js +97 -0
  190. package/lib/useMutation-C6RqWmTS.js.map +1 -0
  191. package/lib/zudoku.__internal.js +8 -8
  192. package/lib/zudoku.auth-auth0.js +1 -1
  193. package/lib/zudoku.auth-azureb2c.js +4 -4
  194. package/lib/zudoku.auth-clerk.js +2 -2
  195. package/lib/zudoku.auth-firebase.js +9 -0
  196. package/lib/zudoku.auth-firebase.js.map +1 -0
  197. package/lib/zudoku.auth-openid.js +5 -5
  198. package/lib/zudoku.auth-supabase.js +5 -5
  199. package/lib/zudoku.components.js +7 -7
  200. package/lib/zudoku.hooks.js +11 -24
  201. package/lib/zudoku.hooks.js.map +1 -1
  202. package/lib/zudoku.mermaid.js +10 -0
  203. package/lib/zudoku.mermaid.js.map +1 -0
  204. package/lib/zudoku.plugin-api-catalog.js +6 -6
  205. package/lib/zudoku.plugin-api-keys.js +224 -215
  206. package/lib/zudoku.plugin-api-keys.js.map +1 -1
  207. package/lib/zudoku.plugin-custom-pages.js +1 -1
  208. package/lib/zudoku.plugin-markdown.js +1 -1
  209. package/lib/zudoku.plugin-openapi.js +3 -3
  210. package/lib/zudoku.plugin-redirect.js +1 -1
  211. package/lib/zudoku.plugin-search-pagefind.js +184 -226
  212. package/lib/zudoku.plugin-search-pagefind.js.map +1 -1
  213. package/lib/zudoku.plugins.js.map +1 -1
  214. package/lib/zudoku.router.js +2 -2
  215. package/package.json +33 -21
  216. package/src/app/sentry.ts +1 -1
  217. package/src/lib/authentication/ui/ZudokuAuthUi.tsx +11 -1
  218. package/src/lib/components/Mermaid.tsx +68 -0
  219. package/src/lib/components/PagefindSearchMeta.tsx +14 -0
  220. package/src/lib/components/Zudoku.tsx +4 -7
  221. package/src/lib/core/RouteGuard.tsx +1 -1
  222. package/src/lib/core/plugins.ts +2 -2
  223. package/src/lib/oas/parser/index.ts +2 -0
  224. package/src/lib/plugins/openapi/DownloadSchemaButton.tsx +115 -0
  225. package/src/lib/plugins/openapi/Endpoint.tsx +20 -27
  226. package/src/lib/plugins/openapi/OasProvider.tsx +30 -17
  227. package/src/lib/plugins/openapi/OperationList.tsx +39 -21
  228. package/src/lib/plugins/openapi/OperationListItem.tsx +5 -5
  229. package/src/lib/plugins/openapi/SchemaList.tsx +4 -0
  230. package/src/lib/plugins/openapi/index.tsx +16 -7
  231. package/src/lib/plugins/openapi/interfaces.ts +16 -7
  232. package/src/lib/plugins/openapi/playground/Playground.tsx +1 -1
  233. package/src/lib/plugins/openapi/schema/SchemaView.tsx +36 -27
  234. package/src/lib/plugins/openapi/schema/utils.ts +5 -2
  235. package/src/lib/plugins/openapi/util/getRoutes.tsx +35 -3
  236. package/src/lib/plugins/search-pagefind/IndexingDialog.tsx +163 -0
  237. package/src/lib/plugins/search-pagefind/PagefindSearch.tsx +61 -22
  238. package/src/lib/plugins/search-pagefind/ResultList.tsx +8 -3
  239. package/src/lib/shiki.ts +21 -12
  240. package/src/lib/ui/Button.tsx +10 -10
  241. package/src/lib/ui/ButtonGroup.tsx +82 -0
  242. package/src/lib/ui/Command.tsx +3 -3
  243. package/src/lib/ui/DropdownMenu.tsx +226 -170
  244. package/src/lib/ui/Kbd.tsx +28 -0
  245. package/src/lib/util/MdxComponents.tsx +2 -0
  246. package/src/lib/util/flattenAllOf.test.ts +71 -19
  247. package/src/lib/util/flattenAllOf.ts +29 -8
  248. package/src/shiki/langs/markdown-nix.js +1 -0
  249. package/src/shiki/langs/openscad.js +1 -0
  250. package/dist/vite/create-pagefind-index.d.ts +0 -4
  251. package/dist/vite/create-pagefind-index.js +0 -12
  252. package/dist/vite/create-pagefind-index.js.map +0 -1
  253. package/lib/Button-B3ucvvQw.js +0 -52
  254. package/lib/Button-B3ucvvQw.js.map +0 -1
  255. package/lib/Command-CUcrW3qs.js.map +0 -1
  256. package/lib/DropdownMenu-BZ2NKQ3K.js +0 -126
  257. package/lib/DropdownMenu-BZ2NKQ3K.js.map +0 -1
  258. package/lib/MdxPage-hOCN-u-L.js +0 -240
  259. package/lib/MdxPage-hOCN-u-L.js.map +0 -1
  260. package/lib/OasProvider-CpniNNrW.js +0 -36
  261. package/lib/OasProvider-CpniNNrW.js.map +0 -1
  262. package/lib/OperationList-CmMoKpGu.js.map +0 -1
  263. package/lib/Pagination-lLSoHnxa.js +0 -37
  264. package/lib/Pagination-lLSoHnxa.js.map +0 -1
  265. package/lib/SchemaList-BykD27ga.js.map +0 -1
  266. package/lib/SchemaView-Dt6hbCAt.js.map +0 -1
  267. package/lib/Select-DFRCS31-.js +0 -399
  268. package/lib/Select-DFRCS31-.js.map +0 -1
  269. package/lib/SyntaxHighlight-C19vH0V_.js.map +0 -1
  270. package/lib/createServer-BmcVQAOQ.js +0 -13018
  271. package/lib/createServer-BmcVQAOQ.js.map +0 -1
  272. package/lib/index-unv8c40u.js.map +0 -1
  273. package/lib/useExposedProps-U3pmsHaG.js +0 -113
  274. package/lib/useExposedProps-U3pmsHaG.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"zudoku.plugins.js","sources":["../src/lib/core/plugins.ts"],"sourcesContent":["import type { LucideIcon } from \"lucide-react\";\nimport type { ReactElement } from \"react\";\nimport type { Location, RouteObject } from \"react-router\";\nimport type { Navigation } from \"../../config/validators/NavigationSchema.js\";\nimport type { ProtectedRoutesInput } from \"../../config/validators/ProtectedRoutesSchema.js\";\nimport type { AuthenticationPlugin } from \"../authentication/authentication.js\";\nimport type { MdxComponentsType } from \"../util/MdxComponents.js\";\nimport type {\n ApiIdentity,\n ZudokuContext,\n ZudokuEvents,\n} from \"./ZudokuContext.js\";\n\nexport type ZudokuPlugin =\n | CommonPlugin\n | ProfileMenuPlugin\n | NavigationPlugin\n | ApiIdentityPlugin\n | SearchProviderPlugin\n | EventConsumerPlugin\n | AuthenticationPlugin;\n\nexport type { AuthenticationPlugin, RouteObject };\n\nexport interface NavigationPlugin {\n getRoutes: () => RouteObject[];\n getNavigation?: (path: string, context: ZudokuContext) => Promise<Navigation>;\n getProtectedRoutes?: () => ProtectedRoutesInput;\n}\n\nexport const createApiIdentityPlugin = (\n plugin: ApiIdentityPlugin,\n): ApiIdentityPlugin => plugin;\n\nexport const createProfileMenuPlugin = (\n plugin: ProfileMenuPlugin,\n): ProfileMenuPlugin => plugin;\n\nexport interface ApiIdentityPlugin {\n getIdentities: (context: ZudokuContext) => Promise<ApiIdentity[]>;\n}\n\nexport interface SearchProviderPlugin {\n renderSearch: (o: {\n isOpen: boolean;\n onClose: () => void;\n }) => React.JSX.Element | null;\n}\n\nexport interface ProfileMenuPlugin {\n getProfileMenuItems: (context: ZudokuContext) => ProfileNavigationItem[];\n}\n\nexport type ProfileNavigationItem = {\n label: string;\n path?: string;\n weight?: number;\n category?: \"top\" | \"middle\" | \"bottom\";\n children?: ProfileNavigationItem[];\n icon?: LucideIcon;\n};\n\nexport interface CommonPlugin {\n initialize?: (\n context: ZudokuContext,\n ) => Promise<void | boolean> | void | boolean;\n getHead?: ({ location }: { location: Location }) => ReactElement | undefined;\n getMdxComponents?: () => MdxComponentsType;\n}\n\nexport type EventConsumerPlugin<Event extends ZudokuEvents = ZudokuEvents> = {\n events: { [K in keyof Event]?: Event[K] };\n};\n\nexport const isEventConsumerPlugin = (\n obj: ZudokuPlugin,\n): obj is EventConsumerPlugin =>\n \"events\" in obj && typeof obj.events === \"object\";\n\nexport const isProfileMenuPlugin = (\n obj: ZudokuPlugin,\n): obj is ProfileMenuPlugin =>\n \"getProfileMenuItems\" in obj && typeof obj.getProfileMenuItems === \"function\";\n\nexport const isNavigationPlugin = (\n obj: ZudokuPlugin,\n): obj is NavigationPlugin =>\n \"getRoutes\" in obj && typeof obj.getRoutes === \"function\";\n\nexport const isAuthenticationPlugin = (\n obj: ZudokuPlugin,\n): obj is AuthenticationPlugin =>\n \"signUp\" in obj && typeof obj.signUp === \"function\";\n\nexport const isSearchPlugin = (\n obj: ZudokuPlugin,\n): obj is SearchProviderPlugin =>\n \"renderSearch\" in obj && typeof obj.renderSearch === \"function\";\n\nexport const needsInitialization = (obj: ZudokuPlugin): obj is CommonPlugin =>\n \"initialize\" in obj && typeof obj.initialize === \"function\";\n\nexport const hasHead = (obj: ZudokuPlugin): obj is CommonPlugin =>\n \"getHead\" in obj && typeof obj.getHead === \"function\";\n\nexport const isMdxProviderPlugin = (obj: ZudokuPlugin): obj is CommonPlugin =>\n \"getMdxComponents\" in obj && typeof obj.getMdxComponents === \"function\";\n\nexport const isApiIdentityPlugin = (\n obj: ZudokuPlugin,\n): obj is ApiIdentityPlugin =>\n \"getIdentities\" in obj && typeof obj.getIdentities === \"function\";\n"],"names":["createApiIdentityPlugin","plugin","createProfileMenuPlugin","isEventConsumerPlugin","obj","isProfileMenuPlugin","isNavigationPlugin","isAuthenticationPlugin","isSearchPlugin","needsInitialization","hasHead","isMdxProviderPlugin","isApiIdentityPlugin"],"mappings":"AA8BO,MAAMA,IAA0B,CACrCC,MACsBA,GAEXC,IAA0B,CACrCD,MACsBA,GAsCXE,IAAwB,CACnCC,MAEA,YAAYA,KAAO,OAAOA,EAAI,UAAW,UAE9BC,IAAsB,CACjCD,MAEA,yBAAyBA,KAAO,OAAOA,EAAI,uBAAwB,YAExDE,IAAqB,CAChCF,MAEA,eAAeA,KAAO,OAAOA,EAAI,aAAc,YAEpCG,IAAyB,CACpCH,MAEA,YAAYA,KAAO,OAAOA,EAAI,UAAW,YAE9BI,IAAiB,CAC5BJ,MAEA,kBAAkBA,KAAO,OAAOA,EAAI,gBAAiB,YAE1CK,IAAsB,CAACL,MAClC,gBAAgBA,KAAO,OAAOA,EAAI,cAAe,YAEtCM,IAAU,CAACN,MACtB,aAAaA,KAAO,OAAOA,EAAI,WAAY,YAEhCO,IAAsB,CAACP,MAClC,sBAAsBA,KAAO,OAAOA,EAAI,oBAAqB,YAElDQ,IAAsB,CACjCR,MAEA,mBAAmBA,KAAO,OAAOA,EAAI,iBAAkB;"}
1
+ {"version":3,"file":"zudoku.plugins.js","sources":["../src/lib/core/plugins.ts"],"sourcesContent":["import type { LucideIcon } from \"lucide-react\";\nimport type { ReactNode } from \"react\";\nimport type { Location, RouteObject } from \"react-router\";\nimport type { Navigation } from \"../../config/validators/NavigationSchema.js\";\nimport type { ProtectedRoutesInput } from \"../../config/validators/ProtectedRoutesSchema.js\";\nimport type { AuthenticationPlugin } from \"../authentication/authentication.js\";\nimport type { MdxComponentsType } from \"../util/MdxComponents.js\";\nimport type {\n ApiIdentity,\n ZudokuContext,\n ZudokuEvents,\n} from \"./ZudokuContext.js\";\n\nexport type ZudokuPlugin =\n | CommonPlugin\n | ProfileMenuPlugin\n | NavigationPlugin\n | ApiIdentityPlugin\n | SearchProviderPlugin\n | EventConsumerPlugin\n | AuthenticationPlugin;\n\nexport type { AuthenticationPlugin, RouteObject };\n\nexport interface NavigationPlugin {\n getRoutes: () => RouteObject[];\n getNavigation?: (path: string, context: ZudokuContext) => Promise<Navigation>;\n getProtectedRoutes?: () => ProtectedRoutesInput;\n}\n\nexport const createApiIdentityPlugin = (\n plugin: ApiIdentityPlugin,\n): ApiIdentityPlugin => plugin;\n\nexport const createProfileMenuPlugin = (\n plugin: ProfileMenuPlugin,\n): ProfileMenuPlugin => plugin;\n\nexport interface ApiIdentityPlugin {\n getIdentities: (context: ZudokuContext) => Promise<ApiIdentity[]>;\n}\n\nexport interface SearchProviderPlugin {\n renderSearch: (o: {\n isOpen: boolean;\n onClose: () => void;\n }) => React.JSX.Element | null;\n}\n\nexport interface ProfileMenuPlugin {\n getProfileMenuItems: (context: ZudokuContext) => ProfileNavigationItem[];\n}\n\nexport type ProfileNavigationItem = {\n label: string;\n path?: string;\n weight?: number;\n category?: \"top\" | \"middle\" | \"bottom\";\n children?: ProfileNavigationItem[];\n icon?: LucideIcon;\n};\n\nexport interface CommonPlugin {\n initialize?: (\n context: ZudokuContext,\n ) => Promise<void | boolean> | void | boolean;\n getHead?: (args: { location: Location }) => ReactNode | undefined;\n getMdxComponents?: () => MdxComponentsType;\n}\n\nexport type EventConsumerPlugin<Event extends ZudokuEvents = ZudokuEvents> = {\n events: { [K in keyof Event]?: Event[K] };\n};\n\nexport const isEventConsumerPlugin = (\n obj: ZudokuPlugin,\n): obj is EventConsumerPlugin =>\n \"events\" in obj && typeof obj.events === \"object\";\n\nexport const isProfileMenuPlugin = (\n obj: ZudokuPlugin,\n): obj is ProfileMenuPlugin =>\n \"getProfileMenuItems\" in obj && typeof obj.getProfileMenuItems === \"function\";\n\nexport const isNavigationPlugin = (\n obj: ZudokuPlugin,\n): obj is NavigationPlugin =>\n \"getRoutes\" in obj && typeof obj.getRoutes === \"function\";\n\nexport const isAuthenticationPlugin = (\n obj: ZudokuPlugin,\n): obj is AuthenticationPlugin =>\n \"signUp\" in obj && typeof obj.signUp === \"function\";\n\nexport const isSearchPlugin = (\n obj: ZudokuPlugin,\n): obj is SearchProviderPlugin =>\n \"renderSearch\" in obj && typeof obj.renderSearch === \"function\";\n\nexport const needsInitialization = (obj: ZudokuPlugin): obj is CommonPlugin =>\n \"initialize\" in obj && typeof obj.initialize === \"function\";\n\nexport const hasHead = (obj: ZudokuPlugin): obj is CommonPlugin =>\n \"getHead\" in obj && typeof obj.getHead === \"function\";\n\nexport const isMdxProviderPlugin = (obj: ZudokuPlugin): obj is CommonPlugin =>\n \"getMdxComponents\" in obj && typeof obj.getMdxComponents === \"function\";\n\nexport const isApiIdentityPlugin = (\n obj: ZudokuPlugin,\n): obj is ApiIdentityPlugin =>\n \"getIdentities\" in obj && typeof obj.getIdentities === \"function\";\n"],"names":["createApiIdentityPlugin","plugin","createProfileMenuPlugin","isEventConsumerPlugin","obj","isProfileMenuPlugin","isNavigationPlugin","isAuthenticationPlugin","isSearchPlugin","needsInitialization","hasHead","isMdxProviderPlugin","isApiIdentityPlugin"],"mappings":"AA8BO,MAAMA,IAA0B,CACrCC,MACsBA,GAEXC,IAA0B,CACrCD,MACsBA,GAsCXE,IAAwB,CACnCC,MAEA,YAAYA,KAAO,OAAOA,EAAI,UAAW,UAE9BC,IAAsB,CACjCD,MAEA,yBAAyBA,KAAO,OAAOA,EAAI,uBAAwB,YAExDE,IAAqB,CAChCF,MAEA,eAAeA,KAAO,OAAOA,EAAI,aAAc,YAEpCG,IAAyB,CACpCH,MAEA,YAAYA,KAAO,OAAOA,EAAI,UAAW,YAE9BI,IAAiB,CAC5BJ,MAEA,kBAAkBA,KAAO,OAAOA,EAAI,gBAAiB,YAE1CK,IAAsB,CAACL,MAClC,gBAAgBA,KAAO,OAAOA,EAAI,cAAe,YAEtCM,IAAU,CAACN,MACtB,aAAaA,KAAO,OAAOA,EAAI,WAAY,YAEhCO,IAAsB,CAACP,MAClC,sBAAsBA,KAAO,OAAOA,EAAI,oBAAqB,YAElDQ,IAAsB,CACjCR,MAEA,mBAAmBA,KAAO,OAAOA,EAAI,iBAAkB;"}
@@ -1,5 +1,5 @@
1
- import { f as We, s as $, g as ve, F as j, R as qe, S as Se, h as Ge, c as Xe, E as D, j as Ee, k as X, l as U, n as Ye, o as oe, p as Je, q as Ke, t as _e, v as Qe, w as be, x as Ce, i as A, y as De, z as Ze, A as C, B as et, C as tt, D as rt, G as at, O as nt, H as L, I as ot, J as st, K as it, M as lt, P as T, Q as ut, T as dt, r as ct, U as Z, V as ft, W as ht, X as pt, Y as mt, Z as yt, _ as Rt, $ as wt, a0 as gt, a1 as vt } from "./chunk-PVWAREVJ-BMhpCH5D.js";
2
- import { a2 as Ur, a3 as Mr, a4 as Nr, a5 as Or, a6 as zr, a7 as Br, a8 as $r, L as jr, a9 as Vr, aa as Wr, ab as qr, ac as Gr, N as Xr, ad as Yr, ae as Jr, af as Kr, ag as Qr, ah as Zr, ai as ea, aj as ta, ak as ra, al as aa, am as na, an as oa, ao as sa, ap as ia, aq as la, ar as ua, as as da, at as ca, au as fa, av as ha, aw as pa, ax as ma, ay as ya, az as Ra, aA as wa, aB as ga, aC as va, aD as Sa, aE as Ea, aF as _a, aG as ba, aH as Ca, aI as Da, aJ as Aa, aK as xa, aL as Fa, m as ka, aM as La, aN as Ta, aO as Ha, aP as Ia, aQ as Pa, aR as Ua, aS as Ma, aT as Na, aU as Oa, aV as za, aW as Ba, aX as $a, aY as ja, aZ as Va, a_ as Wa, a$ as qa, b0 as Ga, d as Xa, e as Ya, b1 as Ja, u as Ka, b2 as Qa, b3 as Za, b4 as en, b5 as tn, b as rn, b6 as an, b7 as nn, b8 as on, b9 as sn, a as ln, ba as un, bb as dn } from "./chunk-PVWAREVJ-BMhpCH5D.js";
1
+ import { f as We, s as $, g as ve, F as j, R as qe, S as Se, h as Ge, d as Xe, E as D, j as Ee, k as X, l as U, n as Ye, o as oe, p as Je, q as Ke, t as _e, v as Qe, w as be, x as Ce, i as A, y as De, z as Ze, A as C, B as et, C as tt, D as rt, G as at, O as nt, H as L, I as ot, J as st, K as it, M as lt, P as T, Q as ut, T as dt, r as ct, U as Z, V as ft, W as ht, X as pt, Y as mt, Z as yt, _ as Rt, $ as wt, a0 as gt, a1 as vt } from "./chunk-PVWAREVJ-dLIqswPy.js";
2
+ import { a2 as Ur, a3 as Mr, a4 as Nr, a5 as Or, a6 as zr, a7 as Br, a8 as $r, L as jr, a9 as Vr, aa as Wr, ab as qr, ac as Gr, N as Xr, ad as Yr, ae as Jr, af as Kr, ag as Qr, ah as Zr, ai as ea, aj as ta, ak as ra, al as aa, am as na, an as oa, ao as sa, ap as ia, aq as la, ar as ua, as as da, at as ca, au as fa, av as ha, aw as pa, ax as ma, ay as ya, az as Ra, aA as wa, aB as ga, aC as va, aD as Sa, aE as Ea, aF as _a, aG as ba, aH as Ca, aI as Da, aJ as Aa, aK as xa, aL as Fa, m as ka, aM as La, aN as Ta, aO as Ha, aP as Ia, aQ as Pa, aR as Ua, aS as Ma, aT as Na, aU as Oa, aV as za, aW as Ba, aX as $a, aY as ja, aZ as Va, a_ as Wa, a$ as qa, b0 as Ga, a as Xa, e as Ya, b1 as Ja, u as Ka, b2 as Qa, b3 as Za, b4 as en, b5 as tn, c as rn, b6 as an, b7 as nn, b8 as on, b9 as sn, b as ln, ba as un, bb as dn } from "./chunk-PVWAREVJ-dLIqswPy.js";
3
3
  import * as g from "react";
4
4
  import E from "react";
5
5
  import * as St from "react-dom";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zudoku",
3
- "version": "0.65.3",
3
+ "version": "0.66.1",
4
4
  "type": "module",
5
5
  "homepage": "https://zudoku.dev",
6
6
  "repository": {
@@ -59,6 +59,10 @@
59
59
  "import": "./lib/zudoku.auth-azureb2c.js",
60
60
  "types": "./dist/lib/authentication/providers/azureb2c.d.ts"
61
61
  },
62
+ "./auth/firebase": {
63
+ "import": "./lib/zudoku.auth-firebase.js",
64
+ "types": "./dist/lib/authentication/providers/firebase.d.ts"
65
+ },
62
66
  "./plugins": {
63
67
  "import": "./lib/zudoku.plugins.js",
64
68
  "types": "./dist/lib/core/plugins.d.ts"
@@ -103,6 +107,10 @@
103
107
  "import": "./lib/zudoku.components.js",
104
108
  "types": "./dist/lib/components/index.d.ts"
105
109
  },
110
+ "./mermaid": {
111
+ "import": "./lib/zudoku.mermaid.js",
112
+ "types": "./dist/lib/components/Mermaid.d.ts"
113
+ },
106
114
  "./__internal": {
107
115
  "import": "./lib/zudoku.__internal.js",
108
116
  "types": "./dist/lib/__internal.d.ts"
@@ -171,19 +179,19 @@
171
179
  "@radix-ui/react-tooltip": "1.2.8",
172
180
  "@radix-ui/react-visually-hidden": "1.2.4",
173
181
  "@scalar/openapi-parser": "0.23.2",
174
- "@sentry/node": "9.26.0",
175
- "@shikijs/engine-javascript": "3.15.0",
176
- "@shikijs/langs": "3.15.0",
177
- "@shikijs/rehype": "3.15.0",
178
- "@shikijs/themes": "3.15.0",
179
- "@shikijs/transformers": "3.15.0",
182
+ "@sentry/node": "10.27.0",
183
+ "@shikijs/engine-javascript": "3.17.0",
184
+ "@shikijs/langs": "3.17.0",
185
+ "@shikijs/rehype": "3.17.0",
186
+ "@shikijs/themes": "3.17.0",
187
+ "@shikijs/transformers": "3.17.0",
180
188
  "@sindresorhus/slugify": "3.0.0",
181
189
  "@stefanprobst/rehype-extract-toc": "3.0.0",
182
190
  "@tailwindcss/typography": "0.5.19",
183
191
  "@tailwindcss/vite": "4.1.16",
184
192
  "@tanem/react-nprogress": "5.0.56",
185
193
  "@tanstack/react-query": "5.85.5",
186
- "@types/react": "19.2.0",
194
+ "@types/react": "19.2.7",
187
195
  "@types/react-dom": "19.2.0",
188
196
  "@vitejs/plugin-react": "5.1.0",
189
197
  "@x0k/json-schema-merge": "1.0.2",
@@ -195,9 +203,9 @@
195
203
  "cmdk": "1.1.1",
196
204
  "embla-carousel-react": "8.6.0",
197
205
  "estree-util-value-to-estree": "3.4.1",
198
- "express": "5.1.0",
206
+ "express": "5.2.0",
199
207
  "fast-equals": "5.2.2",
200
- "glob": "11.1.0",
208
+ "glob": "13.0.0",
201
209
  "glob-parent": "6.0.2",
202
210
  "graphql": "16.12.0",
203
211
  "graphql-type-json": "0.3.2",
@@ -210,15 +218,15 @@
210
218
  "json-schema-to-typescript-lite": "15.0.0",
211
219
  "loglevel": "1.9.2",
212
220
  "lucide-react": "0.548.0",
213
- "motion": "12.23.12",
221
+ "motion": "12.23.24",
214
222
  "nanoevents": "^9.1.0",
215
223
  "next-themes": "0.4.6",
216
224
  "oauth4webapi": "2.17.0",
217
225
  "openapi-types": "12.1.3",
218
- "pagefind": "1.4.0-alpha.1",
226
+ "pagefind": "1.4.0",
219
227
  "picocolors": "1.1.1",
220
- "piscina": "5.1.3",
221
- "posthog-node": "5.7.0",
228
+ "piscina": "5.1.4",
229
+ "posthog-node": "5.14.1",
222
230
  "react-error-boundary": "6.0.0",
223
231
  "react-hook-form": "7.66.0",
224
232
  "react-is": "19.2.0",
@@ -235,7 +243,7 @@
235
243
  "remark-mdx-frontmatter": "5.2.0",
236
244
  "rollup": "4.52.5",
237
245
  "semver": "7.7.2",
238
- "shiki": "3.15.0",
246
+ "shiki": "3.17.0",
239
247
  "sitemap": "9.0.0",
240
248
  "strip-ansi": "7.1.2",
241
249
  "tailwind-merge": "3.3.1",
@@ -252,13 +260,13 @@
252
260
  "zustand": "5.0.8"
253
261
  },
254
262
  "devDependencies": {
255
- "@graphql-codegen/cli": "6.0.1",
263
+ "@graphql-codegen/cli": "6.1.0",
256
264
  "@inkeep/cxkit-types": "0.5.101",
257
265
  "@testing-library/dom": "10.4.1",
258
266
  "@testing-library/jest-dom": "6.9.1",
259
267
  "@testing-library/react": "16.3.0",
260
268
  "@types/estree": "1.0.8",
261
- "@types/express": "5.0.3",
269
+ "@types/express": "5.0.5",
262
270
  "@types/glob-parent": "5.1.3",
263
271
  "@types/har-format": "1.2.16",
264
272
  "@types/hast": "^3.0.4",
@@ -271,24 +279,25 @@
271
279
  "@types/unist": "^3.0.3",
272
280
  "@types/yargs": "17.0.35",
273
281
  "@vitest/coverage-v8": "3.2.4",
274
- "esbuild": "0.25.11",
282
+ "esbuild": "0.27.0",
275
283
  "happy-dom": "20.0.10",
276
284
  "mdast-util-mdx": "3.0.0",
277
285
  "react": "19.2.0",
278
286
  "react-dom": "19.2.0",
279
- "rollup-plugin-visualizer": "6.0.3",
280
- "tsx": "4.20.4",
287
+ "rollup-plugin-visualizer": "6.0.5",
288
+ "tsx": "4.20.6",
281
289
  "typescript": "5.9.3",
282
290
  "vitest": "4.0.6"
283
291
  },
284
292
  "peerDependencies": {
285
293
  "@azure/msal-browser": "^4.13.0",
286
294
  "@clerk/clerk-js": "^5.63.1",
287
- "@sentry/react": "^9.12.0",
295
+ "@sentry/react": "^10.0.0",
288
296
  "@supabase/auth-ui-react": "^0.4.0",
289
297
  "@supabase/auth-ui-shared": "^0.1.0",
290
298
  "@supabase/supabase-js": "^2.49.4",
291
299
  "firebase": "^12.6.0",
300
+ "mermaid": "^11.0.0",
292
301
  "react": ">=19.2.0",
293
302
  "react-dom": ">=19.2.0"
294
303
  },
@@ -313,6 +322,9 @@
313
322
  },
314
323
  "firebase": {
315
324
  "optional": true
325
+ },
326
+ "mermaid": {
327
+ "optional": true
316
328
  }
317
329
  },
318
330
  "scripts": {
package/src/app/sentry.ts CHANGED
@@ -11,7 +11,7 @@ export const initSentry = ({ dsn }: { dsn: string }) => {
11
11
  Sentry.init({
12
12
  dsn,
13
13
  integrations: [
14
- Sentry.reactRouterV6BrowserTracingIntegration({
14
+ Sentry.reactRouterV7BrowserTracingIntegration({
15
15
  useEffect,
16
16
  useLocation,
17
17
  useNavigationType,
@@ -146,8 +146,18 @@ export const ZudokuSignInUi = ({
146
146
  const [searchParams] = useSearchParams();
147
147
  const redirectTo = searchParams.get("redirectTo");
148
148
 
149
+ const invalidProviders = providers.filter(
150
+ (provider) => !isValidAuthProviderId(provider),
151
+ );
152
+
153
+ if (invalidProviders.length > 0) {
154
+ throw new Error(
155
+ `Unsupported auth provider: ${invalidProviders.join(", ")}`,
156
+ );
157
+ }
158
+
149
159
  if (!isAuthProviderIdArray(providers)) {
150
- throw new Error("Invalid auth provider IDs");
160
+ throw new Error(`Unsupported auth provider: ${providers.join(", ")}`);
151
161
  }
152
162
 
153
163
  const signInUsernameMutation = useMutation({
@@ -0,0 +1,68 @@
1
+ import { useQuery } from "@tanstack/react-query";
2
+ import type { MermaidConfig } from "mermaid";
3
+ import type { ComponentProps } from "react";
4
+ import { useId } from "react";
5
+ import { Alert, AlertDescription, AlertTitle } from "zudoku/ui/Alert.js";
6
+ import { useTheme } from "../hooks/index.js";
7
+ import { Spinner } from "./Spinner.js";
8
+
9
+ export type MermaidProps = {
10
+ chart: string;
11
+ config?: MermaidConfig;
12
+ } & ComponentProps<"div">;
13
+
14
+ let mermaidPromise: Promise<typeof import("mermaid").default> | null = null;
15
+
16
+ const loadMermaid = () => {
17
+ if (!mermaidPromise) {
18
+ mermaidPromise = import("mermaid")
19
+ .then((mod) => mod.default)
20
+ .catch((error) => {
21
+ throw new Error(
22
+ "Mermaid is not installed. Please install it with: npm install mermaid",
23
+ { cause: error },
24
+ );
25
+ });
26
+ }
27
+ return mermaidPromise;
28
+ };
29
+
30
+ export const Mermaid = ({ chart, config, ...props }: MermaidProps) => {
31
+ const id = useId();
32
+ const theme = useTheme();
33
+
34
+ const {
35
+ data: svg,
36
+ error,
37
+ isPending,
38
+ } = useQuery({
39
+ queryKey: ["mermaid", chart, config, theme.resolvedTheme],
40
+ queryFn: async () => {
41
+ const mermaid = await loadMermaid();
42
+ mermaid.initialize({
43
+ theme: theme.resolvedTheme === "dark" ? "dark" : "base",
44
+ ...config,
45
+ });
46
+
47
+ const { svg } = await mermaid.render(id, chart);
48
+ return svg;
49
+ },
50
+ enabled: typeof window !== "undefined",
51
+ retry: false,
52
+ });
53
+
54
+ if (error)
55
+ return (
56
+ <Alert className="flex flex-col gap-2" variant="destructive">
57
+ <AlertTitle>Mermaid Error</AlertTitle>
58
+ <AlertDescription className="overflow-auto wrap-break-word whitespace-pre-wrap font-mono text-xs">
59
+ {error.message}
60
+ </AlertDescription>
61
+ </Alert>
62
+ );
63
+
64
+ if (isPending) return <Spinner />;
65
+
66
+ // biome-ignore lint/security/noDangerouslySetInnerHtml: Mermaid generates valid SVG
67
+ return <div {...props} dangerouslySetInnerHTML={{ __html: svg }} />;
68
+ };
@@ -0,0 +1,14 @@
1
+ import type { PropsWithChildren } from "react";
2
+
3
+ /**
4
+ * Adds metadata to be captured by Pagefind for search results.
5
+ * Content is visually hidden but indexed by the search engine.
6
+ */
7
+ export const PagefindSearchMeta = ({
8
+ name,
9
+ children,
10
+ }: PropsWithChildren<{ name?: string }>) => (
11
+ <span data-pagefind-meta={name} className="sr-only">
12
+ {children}
13
+ </span>
14
+ );
@@ -74,16 +74,13 @@ const ZudokuInner = memo(
74
74
 
75
75
  zudokuContext ??= new ZudokuContext(props, queryClient);
76
76
 
77
- const heads = props.plugins
78
- ?.flatMap((plugin) =>
79
- hasHead(plugin) ? (plugin.getHead?.({ location }) ?? []) : [],
80
- )
81
- // biome-ignore lint/suspicious/noArrayIndexKey: No other key is available
82
- .map((entry, i) => <Helmet key={i}>{entry}</Helmet>);
77
+ const heads = props.plugins?.flatMap((plugin) =>
78
+ hasHead(plugin) ? (plugin.getHead?.({ location }) ?? []) : [],
79
+ );
83
80
 
84
81
  return (
85
82
  <>
86
- {heads}
83
+ <Helmet>{heads}</Helmet>
87
84
  <StaggeredRenderContext.Provider value={staggeredValue}>
88
85
  <ZudokuProvider context={zudokuContext}>
89
86
  <RouterEventsEmitter />
@@ -101,7 +101,7 @@ export const RouteGuard = () => {
101
101
 
102
102
  return (
103
103
  <>
104
- {shouldBypass && (
104
+ {shouldBypass && isProtectedRoute && (
105
105
  <Helmet>
106
106
  <meta
107
107
  name="pagefind"
@@ -1,5 +1,5 @@
1
1
  import type { LucideIcon } from "lucide-react";
2
- import type { ReactElement } from "react";
2
+ import type { ReactNode } from "react";
3
3
  import type { Location, RouteObject } from "react-router";
4
4
  import type { Navigation } from "../../config/validators/NavigationSchema.js";
5
5
  import type { ProtectedRoutesInput } from "../../config/validators/ProtectedRoutesSchema.js";
@@ -64,7 +64,7 @@ export interface CommonPlugin {
64
64
  initialize?: (
65
65
  context: ZudokuContext,
66
66
  ) => Promise<void | boolean> | void | boolean;
67
- getHead?: ({ location }: { location: Location }) => ReactElement | undefined;
67
+ getHead?: (args: { location: Location }) => ReactNode | undefined;
68
68
  getMdxComponents?: () => MdxComponentsType;
69
69
  }
70
70
 
@@ -25,6 +25,8 @@ export type TagObject = DeepOmitReference<OpenAPIV3_1.TagObject>;
25
25
  export type ExampleObject = DeepOmitReference<OpenAPIV3_1.ExampleObject>;
26
26
  export type EncodingObject = DeepOmitReference<OpenAPIV3_1.EncodingObject>;
27
27
  export type SchemaObject = DeepOmitReference<OpenAPIV3_1.SchemaObject>;
28
+ export type ArraySchemaObject =
29
+ DeepOmitReference<OpenAPIV3_1.ArraySchemaObject>;
28
30
  export type ServerObject = DeepOmitReference<OpenAPIV3_1.ServerObject>;
29
31
 
30
32
  export const HttpMethods = Object.values(OpenAPIV3.HttpMethods);
@@ -0,0 +1,115 @@
1
+ import {
2
+ ChevronDownIcon,
3
+ CopyIcon,
4
+ DownloadIcon,
5
+ ExternalLinkIcon,
6
+ } from "lucide-react";
7
+ import type { MouseEventHandler } from "react";
8
+ import { Button } from "zudoku/components";
9
+ import { ButtonGroup } from "zudoku/ui/ButtonGroup.js";
10
+ import {
11
+ DropdownMenu,
12
+ DropdownMenuContent,
13
+ DropdownMenuItem,
14
+ DropdownMenuTrigger,
15
+ } from "zudoku/ui/DropdownMenu.js";
16
+ import { useCopyToClipboard } from "../../util/useCopyToClipboard.js";
17
+ import { ChatGPTLogo } from "../markdown/assets/ChatGPTLogo.js";
18
+ import { ClaudeLogo } from "../markdown/assets/ClaudeLogo.js";
19
+
20
+ export const DownloadSchemaButton = ({
21
+ downloadUrl,
22
+ }: {
23
+ downloadUrl: string;
24
+ }) => {
25
+ const [, copyToClipboard] = useCopyToClipboard();
26
+
27
+ const handleDownload: MouseEventHandler<HTMLAnchorElement> = async (e) => {
28
+ const isExternal = downloadUrl.includes("://");
29
+
30
+ if (!isExternal) return;
31
+
32
+ e.preventDefault();
33
+ try {
34
+ const response = await fetch(downloadUrl);
35
+ if (!response.ok)
36
+ throw new Error(`Failed to fetch: ${response.statusText}`);
37
+
38
+ const blob = await response.blob();
39
+ const url = window.URL.createObjectURL(blob);
40
+ const a = document.createElement("a");
41
+ a.href = url;
42
+ a.download = downloadUrl.split("/").pop() || "schema.json";
43
+ document.body.appendChild(a);
44
+ a.click();
45
+ document.body.removeChild(a);
46
+ window.URL.revokeObjectURL(url);
47
+ } catch (error) {
48
+ // biome-ignore lint/suspicious/noConsole: Logging error
49
+ console.error("Failed to download schema:", error);
50
+ }
51
+ };
52
+
53
+ return (
54
+ <ButtonGroup>
55
+ <Button
56
+ variant="outline"
57
+ size="sm"
58
+ className="flex items-center gap-1.5"
59
+ asChild
60
+ >
61
+ <a href={downloadUrl} download onClick={handleDownload}>
62
+ <DownloadIcon size={14} />
63
+ Download schema
64
+ </a>
65
+ </Button>
66
+ <DropdownMenu>
67
+ <DropdownMenuTrigger asChild>
68
+ <Button size="sm" variant="outline" className="px-1.5">
69
+ <ChevronDownIcon size={14} />
70
+ </Button>
71
+ </DropdownMenuTrigger>
72
+ <DropdownMenuContent align="end">
73
+ <DropdownMenuItem asChild>
74
+ <a href={downloadUrl} target="_blank" rel="noopener noreferrer">
75
+ <ExternalLinkIcon size={14} />
76
+ Open in new tab
77
+ </a>
78
+ </DropdownMenuItem>
79
+ <DropdownMenuItem
80
+ onClick={async () => {
81
+ const response = await fetch(downloadUrl);
82
+ const schema = await response.text();
83
+ copyToClipboard(schema);
84
+ }}
85
+ >
86
+ <CopyIcon size={14} />
87
+ Copy to clipboard
88
+ </DropdownMenuItem>
89
+ <DropdownMenuItem
90
+ onClick={() => {
91
+ const prompt = encodeURIComponent(
92
+ `Help me understand this API: ${new URL(downloadUrl, window.location.href).href}`,
93
+ );
94
+ window.open(`https://claude.ai/new?q=${prompt}`, "_blank");
95
+ }}
96
+ >
97
+ <ClaudeLogo className="size-4" />
98
+ Use in Claude
99
+ </DropdownMenuItem>
100
+ <DropdownMenuItem
101
+ onClick={() => {
102
+ const prompt = encodeURIComponent(
103
+ `Help me understand this API: ${new URL(downloadUrl, window.location.href).href}`,
104
+ );
105
+ window.open(`https://chatgpt.com/?q=${prompt}`, "_blank");
106
+ }}
107
+ >
108
+ <ChatGPTLogo className="size-4" />
109
+ Use in ChatGPT
110
+ </DropdownMenuItem>
111
+ </DropdownMenuContent>
112
+ </DropdownMenu>
113
+ </ButtonGroup>
114
+ );
115
+ };
@@ -32,7 +32,7 @@ const CopyButton = ({ url }: { url: string }) => {
32
32
  });
33
33
  }}
34
34
  variant="ghost"
35
- size="icon"
35
+ size="icon-xs"
36
36
  >
37
37
  {isCopied ? (
38
38
  <CheckIcon className="text-green-600" size={14} />
@@ -53,40 +53,33 @@ export const Endpoint = () => {
53
53
  );
54
54
 
55
55
  const { servers } = result.data.schema;
56
-
57
56
  const firstServer = servers.at(0);
58
57
 
59
58
  if (!firstServer) return null;
60
59
 
61
- if (servers.length === 1) {
62
- return (
63
- <div className="flex items-center gap-2">
64
- <span className="font-medium text-sm">Endpoint:</span>
60
+ return (
61
+ <div className="flex items-center gap-1.5 flex-nowrap">
62
+ <span className="font-medium text-sm">Endpoint</span>
63
+ {servers.length > 1 ? (
64
+ <SimpleSelect
65
+ className="font-mono text-xs border-input bg-transparent dark:bg-input/30 dark:hover:bg-input/50 py-1.5 max-w-[450px] truncate"
66
+ onChange={(e) =>
67
+ startTransition(() => setSelectedServer(e.target.value))
68
+ }
69
+ value={selectedServer}
70
+ showChevrons={servers.length > 1}
71
+ options={servers.map((server) => ({
72
+ value: server.url,
73
+ label: server.url,
74
+ }))}
75
+ />
76
+ ) : (
65
77
  <InlineCode className="text-xs px-2 py-1.5" selectOnClick>
66
78
  {firstServer.url}
67
79
  </InlineCode>
68
- <CopyButton url={firstServer.url} />
69
- </div>
70
- );
71
- }
72
-
73
- return (
74
- <div className="flex flex-wrap items-center gap-2">
75
- <span className="font-medium text-sm">Endpoint</span>
80
+ )}
76
81
 
77
- <SimpleSelect
78
- className="font-mono text-xs bg-border/50 dark:bg-border/70 py-1.5 max-w-[450px] truncate"
79
- onChange={(e) =>
80
- startTransition(() => setSelectedServer(e.target.value))
81
- }
82
- value={selectedServer}
83
- showChevrons={servers.length > 1}
84
- options={servers.map((server) => ({
85
- value: server.url,
86
- label: server.url,
87
- }))}
88
- />
89
- <CopyButton url={selectedServer} />
82
+ <CopyButton url={servers.length > 1 ? selectedServer : firstServer.url} />
90
83
  </div>
91
84
  );
92
85
  };
@@ -1,11 +1,11 @@
1
1
  import { useMemo } from "react";
2
2
  import { Outlet } from "react-router";
3
- import { joinPath } from "../../util/joinPath.js";
3
+ import { joinUrl } from "../../util/joinUrl.js";
4
4
  import type { GraphQLClient } from "./client/GraphQLClient.js";
5
5
  import { GraphQLProvider } from "./client/GraphQLContext.js";
6
6
  import { OasConfigProvider } from "./context.js";
7
7
  import type { OasPluginConfig } from "./interfaces.js";
8
- import { getVersions } from "./util/getRoutes.js";
8
+ import { getVersionMetadata } from "./util/getRoutes.js";
9
9
 
10
10
  export const OasProvider = ({
11
11
  basePath,
@@ -19,25 +19,38 @@ export const OasProvider = ({
19
19
  client: GraphQLClient;
20
20
  }) => {
21
21
  const value = useMemo(() => {
22
- const versions = getVersions(config);
23
- const firstVersion = Object.values(config.input).at(0);
24
- const input =
25
- config.type === "file"
26
- ? {
27
- type: config.type,
28
- // biome-ignore lint/style/noNonNullAssertion: is guaranteed to be defined
29
- input: version ? config.input[version]! : firstVersion!,
30
- }
31
- : { type: config.type, input: config.input };
22
+ const { versions: availableVersions, labels } = getVersionMetadata(config);
23
+ const currentVersion = version ?? availableVersions.at(0);
24
+
25
+ const versionLinks = Object.fromEntries(
26
+ availableVersions.map((id) => [
27
+ id,
28
+ { path: joinUrl(basePath, id), label: labels[id] ?? id },
29
+ ]),
30
+ );
31
+
32
+ const resolveInput = (): string | (() => Promise<unknown>) => {
33
+ if (!Array.isArray(config.input)) {
34
+ return config.input;
35
+ }
36
+
37
+ const versionConfig = currentVersion
38
+ ? config.input.find((v) => v.path === currentVersion)
39
+ : config.input[0];
40
+
41
+ if (!versionConfig) {
42
+ throw new Error(`No input found for version: ${currentVersion}`);
43
+ }
44
+
45
+ return versionConfig.input;
46
+ };
32
47
 
33
48
  return {
34
49
  config: {
35
50
  ...config,
36
- version: version ?? versions.at(0),
37
- versions: Object.fromEntries(
38
- versions.map((version) => [version, joinPath(basePath, version)]),
39
- ),
40
- ...input,
51
+ version: currentVersion,
52
+ versions: versionLinks,
53
+ input: resolveInput(),
41
54
  },
42
55
  };
43
56
  }, [config, basePath, version]);