zudoku 0.17.0 → 0.18.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 (275) hide show
  1. package/dist/app/demo.js +0 -2
  2. package/dist/app/demo.js.map +1 -1
  3. package/dist/app/entry.client.js +14 -0
  4. package/dist/app/entry.client.js.map +1 -1
  5. package/dist/app/entry.server.js +5 -4
  6. package/dist/app/entry.server.js.map +1 -1
  7. package/dist/app/standalone.js +0 -2
  8. package/dist/app/standalone.js.map +1 -1
  9. package/dist/codegen.d.ts +3 -0
  10. package/dist/codegen.js +45 -0
  11. package/dist/codegen.js.map +1 -0
  12. package/dist/config/validators/InputSidebarSchema.d.ts +10 -10
  13. package/dist/config/validators/validate.d.ts +74 -74
  14. package/dist/lib/authentication/hook.d.ts +5 -4
  15. package/dist/lib/authentication/hook.js +1 -3
  16. package/dist/lib/authentication/hook.js.map +1 -1
  17. package/dist/lib/authentication/providers/auth0.js +11 -11
  18. package/dist/lib/authentication/providers/auth0.js.map +1 -1
  19. package/dist/lib/authentication/providers/openid.d.ts +0 -1
  20. package/dist/lib/authentication/providers/openid.js +11 -26
  21. package/dist/lib/authentication/providers/openid.js.map +1 -1
  22. package/dist/lib/authentication/state.d.ts +25 -4
  23. package/dist/lib/authentication/state.js +28 -5
  24. package/dist/lib/authentication/state.js.map +1 -1
  25. package/dist/lib/components/Bootstrap.d.ts +3 -1
  26. package/dist/lib/components/Bootstrap.js +11 -3
  27. package/dist/lib/components/Bootstrap.js.map +1 -1
  28. package/dist/lib/components/DeveloperHint.js +2 -1
  29. package/dist/lib/components/DeveloperHint.js.map +1 -1
  30. package/dist/lib/components/Header.js +3 -7
  31. package/dist/lib/components/Header.js.map +1 -1
  32. package/dist/lib/components/Heading.d.ts +1 -1
  33. package/dist/lib/components/Layout.js +11 -3
  34. package/dist/lib/components/Layout.js.map +1 -1
  35. package/dist/lib/components/MobileTopNavigation.js +6 -7
  36. package/dist/lib/components/MobileTopNavigation.js.map +1 -1
  37. package/dist/lib/components/SyntaxHighlight.js +16 -12
  38. package/dist/lib/components/SyntaxHighlight.js.map +1 -1
  39. package/dist/lib/components/ThemeSwitch.d.ts +1 -0
  40. package/dist/lib/components/ThemeSwitch.js +13 -0
  41. package/dist/lib/components/ThemeSwitch.js.map +1 -0
  42. package/dist/lib/components/TopNavigation.d.ts +2 -0
  43. package/dist/lib/components/TopNavigation.js +13 -7
  44. package/dist/lib/components/TopNavigation.js.map +1 -1
  45. package/dist/lib/components/Zudoku.js +4 -5
  46. package/dist/lib/components/Zudoku.js.map +1 -1
  47. package/dist/lib/components/context/ZudokuContext.d.ts +3 -3
  48. package/dist/lib/components/context/ZudokuContext.js +7 -12
  49. package/dist/lib/components/context/ZudokuContext.js.map +1 -1
  50. package/dist/lib/components/index.d.ts +14 -3
  51. package/dist/lib/components/navigation/Sidebar.js +1 -1
  52. package/dist/lib/components/navigation/Sidebar.js.map +1 -1
  53. package/dist/lib/components/navigation/utils.js +2 -2
  54. package/dist/lib/components/navigation/utils.js.map +1 -1
  55. package/dist/lib/core/ZudokuContext.d.ts +0 -4
  56. package/dist/lib/core/ZudokuContext.js +0 -5
  57. package/dist/lib/core/ZudokuContext.js.map +1 -1
  58. package/dist/lib/errors/ErrorAlert.js +1 -1
  59. package/dist/lib/errors/ErrorAlert.js.map +1 -1
  60. package/dist/lib/plugins/openapi/ColorizedParam.js +13 -9
  61. package/dist/lib/plugins/openapi/ColorizedParam.js.map +1 -1
  62. package/dist/lib/plugins/openapi/Endpoint.d.ts +1 -1
  63. package/dist/lib/plugins/openapi/Endpoint.js +5 -9
  64. package/dist/lib/plugins/openapi/Endpoint.js.map +1 -1
  65. package/dist/lib/plugins/openapi/OperationList.d.ts +2 -2
  66. package/dist/lib/plugins/openapi/OperationList.js +6 -21
  67. package/dist/lib/plugins/openapi/OperationList.js.map +1 -1
  68. package/dist/lib/plugins/openapi/Route.d.ts +4 -4
  69. package/dist/lib/plugins/openapi/Route.js +2 -4
  70. package/dist/lib/plugins/openapi/Route.js.map +1 -1
  71. package/dist/lib/plugins/openapi/Sidecar.d.ts +1 -1
  72. package/dist/lib/plugins/openapi/Sidecar.js +8 -11
  73. package/dist/lib/plugins/openapi/Sidecar.js.map +1 -1
  74. package/dist/lib/plugins/openapi/client/GraphQLClient.d.ts +8 -0
  75. package/dist/lib/plugins/openapi/client/GraphQLClient.js +102 -0
  76. package/dist/lib/plugins/openapi/client/GraphQLClient.js.map +1 -0
  77. package/dist/lib/plugins/openapi/client/GraphQLContext.d.ts +7 -0
  78. package/dist/lib/plugins/openapi/client/GraphQLContext.js +5 -0
  79. package/dist/lib/plugins/openapi/client/GraphQLContext.js.map +1 -0
  80. package/dist/lib/plugins/openapi/client/createServer.d.ts +1 -0
  81. package/dist/lib/plugins/openapi/client/useCreateQuery.d.ts +5 -0
  82. package/dist/lib/plugins/openapi/client/useCreateQuery.js +13 -0
  83. package/dist/lib/plugins/openapi/client/useCreateQuery.js.map +1 -0
  84. package/dist/lib/plugins/openapi/client/worker.d.ts +4 -1
  85. package/dist/lib/plugins/openapi/client/worker.js +23 -14
  86. package/dist/lib/plugins/openapi/client/worker.js.map +1 -1
  87. package/dist/lib/plugins/openapi/graphql/fragment-masking.d.ts +3 -3
  88. package/dist/lib/plugins/openapi/graphql/fragment-masking.js +3 -4
  89. package/dist/lib/plugins/openapi/graphql/fragment-masking.js.map +1 -1
  90. package/dist/lib/plugins/openapi/graphql/gql.d.ts +5 -52
  91. package/dist/lib/plugins/openapi/graphql/gql.js +2 -1
  92. package/dist/lib/plugins/openapi/graphql/gql.js.map +1 -1
  93. package/dist/lib/plugins/openapi/graphql/graphql.d.ts +134 -9
  94. package/dist/lib/plugins/openapi/graphql/graphql.js +194 -778
  95. package/dist/lib/plugins/openapi/graphql/graphql.js.map +1 -1
  96. package/dist/lib/plugins/openapi/index.js +40 -53
  97. package/dist/lib/plugins/openapi/index.js.map +1 -1
  98. package/dist/lib/plugins/openapi/schema/SchemaView.js.map +1 -1
  99. package/dist/lib/plugins/openapi-worker.d.ts +1 -1
  100. package/dist/lib/plugins/openapi-worker.js +7 -1
  101. package/dist/lib/plugins/openapi-worker.js.map +1 -1
  102. package/dist/lib/util/MdxComponents.d.ts +1 -1
  103. package/dist/vite/config.js +0 -1
  104. package/dist/vite/config.js.map +1 -1
  105. package/dist/vite/html.js +0 -2
  106. package/dist/vite/html.js.map +1 -1
  107. package/dist/vite/plugin-component.js +1 -1
  108. package/dist/vite/plugin-component.js.map +1 -1
  109. package/dist/vite/plugin-mdx.js +3 -2
  110. package/dist/vite/plugin-mdx.js.map +1 -1
  111. package/dist/vite/plugin.js +0 -2
  112. package/dist/vite/plugin.js.map +1 -1
  113. package/dist/vite/remarkStaticGeneration.d.ts +3 -0
  114. package/dist/vite/remarkStaticGeneration.js +125 -0
  115. package/dist/vite/remarkStaticGeneration.js.map +1 -0
  116. package/lib/{AnchorLink-DYbUOP9U.js → AnchorLink-CDlhr8gL.js} +11 -10
  117. package/lib/{AnchorLink-DYbUOP9U.js.map → AnchorLink-CDlhr8gL.js.map} +1 -1
  118. package/lib/{AuthenticationPlugin-bqGAKfot.js → AuthenticationPlugin-DeGDVa1r.js} +6 -5
  119. package/lib/{AuthenticationPlugin-bqGAKfot.js.map → AuthenticationPlugin-DeGDVa1r.js.map} +1 -1
  120. package/lib/{Spinner-ChOGyPls.js → Button-jK0EsymC.js} +12 -15
  121. package/lib/Button-jK0EsymC.js.map +1 -0
  122. package/lib/Markdown-ievDDhFT.js +15192 -0
  123. package/lib/Markdown-ievDDhFT.js.map +1 -0
  124. package/lib/{MdxPage-DRKqyn2b.js → MdxPage-Bwn-VSsH.js} +5 -5
  125. package/lib/{MdxPage-DRKqyn2b.js.map → MdxPage-Bwn-VSsH.js.map} +1 -1
  126. package/lib/OperationList-BwBl1xrD.js +4691 -0
  127. package/lib/OperationList-BwBl1xrD.js.map +1 -0
  128. package/lib/Route-DlG_HTMu.js +11 -0
  129. package/lib/Route-DlG_HTMu.js.map +1 -0
  130. package/lib/{Select-DYKDahHt.js → Select-O9ZM3ZgX.js} +7 -7
  131. package/lib/Select-O9ZM3ZgX.js.map +1 -0
  132. package/lib/SidebarBadge-DxFJcJ6V.js +51 -0
  133. package/lib/SidebarBadge-DxFJcJ6V.js.map +1 -0
  134. package/lib/SlotletProvider-DyomlzGx.js +252 -0
  135. package/lib/SlotletProvider-DyomlzGx.js.map +1 -0
  136. package/lib/Spinner-3cQDBVGr.js +7 -0
  137. package/lib/Spinner-3cQDBVGr.js.map +1 -0
  138. package/lib/SyntaxHighlight-DkLOsjHS.js +2983 -0
  139. package/lib/SyntaxHighlight-DkLOsjHS.js.map +1 -0
  140. package/lib/assets/{worker-YA-aCP3P.js → worker-CPsGZsve.js} +24 -22
  141. package/lib/assets/{worker-YA-aCP3P.js.map → worker-CPsGZsve.js.map} +1 -1
  142. package/lib/context-D1nXWxm7.js +22 -0
  143. package/lib/context-D1nXWxm7.js.map +1 -0
  144. package/lib/createServer-DK-g7kbB.js +16089 -0
  145. package/lib/createServer-DK-g7kbB.js.map +1 -0
  146. package/lib/{hook-CjQERPa7.js → hook-hEqe7fPB.js} +12 -14
  147. package/lib/hook-hEqe7fPB.js.map +1 -0
  148. package/lib/index-Czzd9rjU.js +899 -0
  149. package/lib/index-Czzd9rjU.js.map +1 -0
  150. package/lib/index-DNxQ_rCt.js +1273 -0
  151. package/lib/index-DNxQ_rCt.js.map +1 -0
  152. package/lib/index-Yn8c3UWE.js +921 -0
  153. package/lib/index-Yn8c3UWE.js.map +1 -0
  154. package/lib/{router-BsfSoK2j.js → router-lfyopgBI.js} +23 -23
  155. package/lib/{router-BsfSoK2j.js.map → router-lfyopgBI.js.map} +1 -1
  156. package/lib/state-tsXBLONe.js +203 -0
  157. package/lib/state-tsXBLONe.js.map +1 -0
  158. package/lib/ui/ActionButton.js +11 -10
  159. package/lib/ui/ActionButton.js.map +1 -1
  160. package/lib/useExposedProps-CTPtylCV.js +10 -0
  161. package/lib/{useExposedProps-BxyHjPNN.js.map → useExposedProps-CTPtylCV.js.map} +1 -1
  162. package/lib/{utils-DNAltzXc.js → utils-DcpDOncX.js} +197 -202
  163. package/lib/utils-DcpDOncX.js.map +1 -0
  164. package/lib/zudoku.auth-auth0.js +24 -18
  165. package/lib/zudoku.auth-auth0.js.map +1 -1
  166. package/lib/zudoku.auth-clerk.js +2 -2
  167. package/lib/zudoku.auth-openid.js +124 -138
  168. package/lib/zudoku.auth-openid.js.map +1 -1
  169. package/lib/zudoku.components.js +1133 -992
  170. package/lib/zudoku.components.js.map +1 -1
  171. package/lib/zudoku.openapi-worker.js +10 -16346
  172. package/lib/zudoku.openapi-worker.js.map +1 -1
  173. package/lib/zudoku.plugin-api-keys.js +18 -18
  174. package/lib/zudoku.plugin-custom-pages.js +2 -2
  175. package/lib/zudoku.plugin-markdown.js +1 -1
  176. package/lib/zudoku.plugin-openapi.js +5 -9
  177. package/lib/zudoku.plugin-openapi.js.map +1 -1
  178. package/lib/zudoku.plugin-redirect.js +1 -1
  179. package/package.json +14 -4
  180. package/src/app/demo.tsx +0 -3
  181. package/src/app/entry.client.tsx +14 -0
  182. package/src/app/entry.server.tsx +59 -57
  183. package/src/app/standalone.tsx +0 -3
  184. package/src/lib/authentication/hook.ts +1 -3
  185. package/src/lib/authentication/providers/auth0.tsx +16 -11
  186. package/src/lib/authentication/providers/openid.tsx +12 -30
  187. package/src/lib/authentication/state.ts +44 -10
  188. package/src/lib/components/Bootstrap.tsx +36 -9
  189. package/src/lib/components/DeveloperHint.tsx +6 -1
  190. package/src/lib/components/Header.tsx +31 -42
  191. package/src/lib/components/Layout.tsx +48 -36
  192. package/src/lib/components/MobileTopNavigation.tsx +15 -18
  193. package/src/lib/components/SyntaxHighlight.tsx +81 -46
  194. package/src/lib/components/ThemeSwitch.tsx +26 -0
  195. package/src/lib/components/TopNavigation.tsx +27 -19
  196. package/src/lib/components/Zudoku.tsx +5 -10
  197. package/src/lib/components/context/ZudokuContext.ts +8 -13
  198. package/src/lib/components/navigation/Sidebar.tsx +3 -3
  199. package/src/lib/components/navigation/utils.ts +2 -2
  200. package/src/lib/core/ZudokuContext.ts +0 -8
  201. package/src/lib/errors/ErrorAlert.tsx +2 -1
  202. package/src/lib/plugins/openapi/ColorizedParam.tsx +23 -14
  203. package/src/lib/plugins/openapi/Endpoint.tsx +5 -10
  204. package/src/lib/plugins/openapi/OperationList.tsx +5 -40
  205. package/src/lib/plugins/openapi/Route.tsx +11 -12
  206. package/src/lib/plugins/openapi/Sidecar.tsx +10 -13
  207. package/src/lib/plugins/openapi/client/GraphQLClient.tsx +140 -0
  208. package/src/lib/plugins/openapi/client/GraphQLContext.tsx +16 -0
  209. package/src/lib/plugins/openapi/client/createServer.ts +2 -0
  210. package/src/lib/plugins/openapi/client/useCreateQuery.ts +18 -0
  211. package/src/lib/plugins/openapi/client/worker.ts +38 -24
  212. package/src/lib/plugins/openapi/graphql/fragment-masking.ts +11 -18
  213. package/src/lib/plugins/openapi/graphql/gql.ts +7 -25
  214. package/src/lib/plugins/openapi/graphql/graphql.ts +351 -782
  215. package/src/lib/plugins/openapi/index.tsx +40 -63
  216. package/src/lib/plugins/openapi/schema/SchemaView.tsx +1 -1
  217. package/src/lib/plugins/openapi-worker.ts +11 -1
  218. package/dist/lib/components/context/ThemeContext.d.ts +0 -2
  219. package/dist/lib/components/context/ThemeContext.js +0 -7
  220. package/dist/lib/components/context/ThemeContext.js.map +0 -1
  221. package/dist/lib/components/context/ThemeProvider.d.ts +0 -4
  222. package/dist/lib/components/context/ThemeProvider.js +0 -23
  223. package/dist/lib/components/context/ThemeProvider.js.map +0 -1
  224. package/dist/lib/plugins/openapi/client/createMemoryClient.d.ts +0 -9
  225. package/dist/lib/plugins/openapi/client/createMemoryClient.js +0 -54
  226. package/dist/lib/plugins/openapi/client/createMemoryClient.js.map +0 -1
  227. package/dist/lib/plugins/openapi/client/createWorkerClient.d.ts +0 -10
  228. package/dist/lib/plugins/openapi/client/createWorkerClient.js +0 -62
  229. package/dist/lib/plugins/openapi/client/createWorkerClient.js.map +0 -1
  230. package/dist/lib/plugins/openapi/client/interfaces.d.ts +0 -4
  231. package/dist/lib/plugins/openapi/client/interfaces.js +0 -2
  232. package/dist/lib/plugins/openapi/client/interfaces.js.map +0 -1
  233. package/dist/lib/themeToggle.d.ts +0 -1
  234. package/dist/lib/themeToggle.js +0 -7
  235. package/dist/lib/themeToggle.js.map +0 -1
  236. package/dist/lib/util/createWaitForNotify.d.ts +0 -1
  237. package/dist/lib/util/createWaitForNotify.js +0 -15
  238. package/dist/lib/util/createWaitForNotify.js.map +0 -1
  239. package/dist/vite/plugin-html-transform.d.ts +0 -2
  240. package/dist/vite/plugin-html-transform.js +0 -15
  241. package/dist/vite/plugin-html-transform.js.map +0 -1
  242. package/lib/DeveloperHint-DHdLXGHA.js +0 -16
  243. package/lib/DeveloperHint-DHdLXGHA.js.map +0 -1
  244. package/lib/Markdown-D6UxMbZm.js +0 -18059
  245. package/lib/Markdown-D6UxMbZm.js.map +0 -1
  246. package/lib/OperationList-BHUBGM0c.js +0 -621
  247. package/lib/OperationList-BHUBGM0c.js.map +0 -1
  248. package/lib/Route-B0XuN1oC.js +0 -13
  249. package/lib/Route-B0XuN1oC.js.map +0 -1
  250. package/lib/Select-DYKDahHt.js.map +0 -1
  251. package/lib/SidebarBadge-Bbt92M5K.js +0 -38
  252. package/lib/SidebarBadge-Bbt92M5K.js.map +0 -1
  253. package/lib/SlotletProvider-mhjLPG44.js +0 -241
  254. package/lib/SlotletProvider-mhjLPG44.js.map +0 -1
  255. package/lib/Spinner-ChOGyPls.js.map +0 -1
  256. package/lib/StaggeredRender-DDHSzQKE.js +0 -17
  257. package/lib/StaggeredRender-DDHSzQKE.js.map +0 -1
  258. package/lib/hook-CjQERPa7.js.map +0 -1
  259. package/lib/index-BRg5pi5D.js +0 -5902
  260. package/lib/index-BRg5pi5D.js.map +0 -1
  261. package/lib/index-DM9hrcCG.js +0 -1783
  262. package/lib/index-DM9hrcCG.js.map +0 -1
  263. package/lib/state-BsPrOUAh.js +0 -252
  264. package/lib/state-BsPrOUAh.js.map +0 -1
  265. package/lib/urql-core-35Qt_U4i.js +0 -1511
  266. package/lib/urql-core-35Qt_U4i.js.map +0 -1
  267. package/lib/useExposedProps-BxyHjPNN.js +0 -9
  268. package/lib/utils-DNAltzXc.js.map +0 -1
  269. package/src/lib/components/context/ThemeContext.tsx +0 -8
  270. package/src/lib/components/context/ThemeProvider.tsx +0 -27
  271. package/src/lib/plugins/openapi/client/createMemoryClient.ts +0 -65
  272. package/src/lib/plugins/openapi/client/createWorkerClient.ts +0 -79
  273. package/src/lib/plugins/openapi/client/interfaces.ts +0 -5
  274. package/src/lib/themeToggle.ts +0 -7
  275. package/src/lib/util/createWaitForNotify.ts +0 -18
@@ -1,6 +1,6 @@
1
1
  import { MDXProvider } from "@mdx-js/react";
2
- import { QueryClientProvider } from "@tanstack/react-query";
3
2
  import { Helmet } from "@zudoku/react-helmet-async";
3
+ import { ThemeProvider } from "next-themes";
4
4
  import {
5
5
  Fragment,
6
6
  memo,
@@ -13,11 +13,7 @@ import {
13
13
  import { ErrorBoundary } from "react-error-boundary";
14
14
  import { Outlet, useNavigation } from "react-router-dom";
15
15
  import { hasHead, isMdxProviderPlugin } from "../core/plugins.js";
16
- import {
17
- queryClient,
18
- ZudokuContext,
19
- ZudokuContextOptions,
20
- } from "../core/ZudokuContext.js";
16
+ import { ZudokuContext, ZudokuContextOptions } from "../core/ZudokuContext.js";
21
17
  import { TopLevelError } from "../errors/TopLevelError.js";
22
18
  import { StaggeredRenderContext } from "../plugins/openapi/StaggeredRender.js";
23
19
  import { MdxComponents } from "../util/MdxComponents.js";
@@ -26,7 +22,6 @@ import {
26
22
  ComponentsProvider,
27
23
  DEFAULT_COMPONENTS,
28
24
  } from "./context/ComponentsContext.js";
29
- import { ThemeProvider } from "./context/ThemeProvider.js";
30
25
  import { ViewportAnchorProvider } from "./context/ViewportAnchorContext.js";
31
26
  import { ZudokuProvider } from "./context/ZudokuProvider.js";
32
27
  import { SlotletProvider } from "./SlotletProvider.js";
@@ -77,12 +72,12 @@ const ZudokoInner = memo(
77
72
  .map((plugin, i) => <Fragment key={i}>{plugin.getHead?.()}</Fragment>);
78
73
 
79
74
  return (
80
- <QueryClientProvider client={queryClient}>
75
+ <>
81
76
  <Helmet>{heads}</Helmet>
82
77
  <StaggeredRenderContext.Provider value={staggeredValue}>
83
78
  <ZudokuProvider context={zudokuContext}>
84
79
  <MDXProvider components={mdxComponents}>
85
- <ThemeProvider>
80
+ <ThemeProvider attribute="class" disableTransitionOnChange>
86
81
  <ComponentsProvider value={components}>
87
82
  <SlotletProvider slotlets={props.slotlets}>
88
83
  <ViewportAnchorProvider>
@@ -94,7 +89,7 @@ const ZudokoInner = memo(
94
89
  </MDXProvider>
95
90
  </ZudokuProvider>
96
91
  </StaggeredRenderContext.Provider>
97
- </QueryClientProvider>
92
+ </>
98
93
  );
99
94
  },
100
95
  );
@@ -49,18 +49,13 @@ export const useCurrentNavigation = () => {
49
49
  topNavigation.find((t) => t.id === currentSidebarItem?.[0]) ??
50
50
  topNavigation.find((item) => matchPath(item.id, location.pathname));
51
51
 
52
- return useSuspenseQuery({
53
- queryFn: async () => {
54
- const pluginSidebar = await getPluginSidebar(location.pathname);
55
-
56
- return {
57
- sidebar: [
58
- ...(currentSidebarItem ? currentSidebarItem[1] : []),
59
- ...pluginSidebar,
60
- ],
61
- topNavItem: currentTopNavItem,
62
- };
63
- },
64
- queryKey: ["navigation", location.pathname],
52
+ const { data } = useSuspenseQuery({
53
+ queryFn: () => getPluginSidebar(location.pathname),
54
+ queryKey: ["plugin-sidebar", location.pathname],
65
55
  });
56
+
57
+ return {
58
+ sidebar: [...(currentSidebarItem ? currentSidebarItem[1] : []), ...data],
59
+ topNavItem: currentTopNavItem,
60
+ };
66
61
  };
@@ -15,10 +15,10 @@ export const Sidebar = () => {
15
15
  <>
16
16
  <SidebarWrapper
17
17
  ref={navRef}
18
- pushMainContent={navigation.data.sidebar.length > 0}
18
+ pushMainContent={navigation.sidebar.length > 0}
19
19
  >
20
20
  <Slotlet name="zudoku-before-navigation" />
21
- {navigation.data.sidebar.map((item) => (
21
+ {navigation.sidebar.map((item) => (
22
22
  <SidebarItem key={item.label} item={item} />
23
23
  ))}
24
24
  <Slotlet name="zudoku-after-navigation" />
@@ -30,7 +30,7 @@ export const Sidebar = () => {
30
30
  <VisuallyHidden>
31
31
  <DrawerTitle>Sidebar</DrawerTitle>
32
32
  </VisuallyHidden>
33
- {navigation.data.sidebar.map((item) => (
33
+ {navigation.sidebar.map((item) => (
34
34
  <SidebarItem key={item.label} item={item} />
35
35
  ))}
36
36
  </DrawerContent>
@@ -44,7 +44,7 @@ export const useCurrentItem = () => {
44
44
  const location = useLocation();
45
45
  const nav = useCurrentNavigation();
46
46
 
47
- const currentSidebar = nav.data.sidebar;
47
+ const currentSidebar = nav.sidebar;
48
48
 
49
49
  return traverseSidebar(currentSidebar, (item) => {
50
50
  if (item.type === "doc" && joinPath(item.id) === location.pathname) {
@@ -79,7 +79,7 @@ export const usePrevNext = (): {
79
79
  } => {
80
80
  const currentId = useLocation().pathname;
81
81
  const nav = useCurrentNavigation();
82
- const currentSidebar = nav.data.sidebar;
82
+ const currentSidebar = nav.sidebar;
83
83
 
84
84
  let prev;
85
85
  let next;
@@ -1,4 +1,3 @@
1
- import { QueryClient } from "@tanstack/react-query";
2
1
  import { ReactNode } from "react";
3
2
  import type { SidebarConfig } from "../../config/validators/SidebarSchema.js";
4
3
  import { TopNavigationItem } from "../../config/validators/validate.js";
@@ -21,10 +20,7 @@ export interface ApiIdentity {
21
20
  id: string;
22
21
  }
23
22
 
24
- export const queryClient = new QueryClient();
25
-
26
23
  export type ApiKeyCache = "api-keys";
27
- export type ZudokuCacheKey = ApiKeyCache | string;
28
24
 
29
25
  type Metadata = Partial<{
30
26
  title: string;
@@ -98,10 +94,6 @@ export class ZudokuContext {
98
94
  );
99
95
  };
100
96
 
101
- invalidateCache = async (key: ZudokuCacheKey[]) => {
102
- await queryClient.invalidateQueries({ queryKey: key });
103
- };
104
-
105
97
  getApiIdentities = async () => {
106
98
  const keys = await Promise.all(
107
99
  this.plugins
@@ -5,6 +5,7 @@ import { ZudokuError } from "../util/invariant.js";
5
5
  export function ErrorAlert({ error }: { error: unknown }) {
6
6
  const message =
7
7
  error instanceof Error ? error.message : "Something went wrong";
8
+
8
9
  const hint = error instanceof ZudokuError ? error.developerHint : undefined;
9
10
  const title =
10
11
  error instanceof ZudokuError ? error.title : "Something went wrong";
@@ -12,7 +13,7 @@ export function ErrorAlert({ error }: { error: unknown }) {
12
13
  const cause = error instanceof Error ? error.cause : undefined;
13
14
 
14
15
  return (
15
- <div className="flex h-screen max-h-screen min-h-full items-center justify-center bg-primary-background px-4 py-16 lg:px-8">
16
+ <div className="flex h-screen max-h-[calc(100vh-var(--header-height))] min-h-full items-center justify-center bg-primary-background px-4 py-16 lg:px-8">
16
17
  <div className="mx-auto max-w-[85%] sm:max-w-[50%]">
17
18
  <h1 className="text-4xl font-bold tracking-tight text-h1-text sm:text-5xl">
18
19
  {title}
@@ -1,15 +1,15 @@
1
- import { useEffect, useRef, type ReactNode } from "react";
2
- import { useTheme } from "../../components/context/ThemeContext.js";
1
+ import { useTheme } from "next-themes";
2
+ import { useEffect, useRef, type CSSProperties, type ReactNode } from "react";
3
3
  import { cn } from "../../util/cn.js";
4
4
  import { pastellize } from "../../util/pastellize.js";
5
5
 
6
6
  export const DATA_ATTR = "data-linked-param";
7
7
 
8
8
  export const usePastellizedColor = (name: string) => {
9
- const [isDark] = useTheme();
9
+ const { resolvedTheme } = useTheme();
10
10
  return pastellize(
11
11
  name,
12
- !isDark ? { saturation: 85, lightness: 50 } : undefined,
12
+ resolvedTheme === "light" ? { saturation: 85, lightness: 50 } : undefined,
13
13
  );
14
14
  };
15
15
 
@@ -61,27 +61,36 @@ export const ColorizedParam = ({
61
61
  });
62
62
  };
63
63
 
64
- ref.current.addEventListener("mouseenter", onMouseEnter);
65
- ref.current.addEventListener("mouseleave", onMouseLeave);
64
+ const el = ref.current;
65
+
66
+ el.addEventListener("mouseenter", onMouseEnter);
67
+ el.addEventListener("mouseleave", onMouseLeave);
66
68
 
67
69
  return () => {
68
- ref.current?.removeEventListener("mouseenter", onMouseEnter);
69
- ref.current?.removeEventListener("mouseleave", onMouseLeave);
70
+ el.removeEventListener("mouseenter", onMouseEnter);
71
+ el.removeEventListener("mouseleave", onMouseLeave);
70
72
  };
71
73
  }, [normalizedSlug]);
72
74
 
73
75
  return (
74
76
  <span
75
- className={cn("inline-flex relative rounded group", className)}
76
77
  {...{ [DATA_ATTR]: normalizedSlug }}
78
+ className={cn(
79
+ "relative after:rounded after:absolute after:inset-0 after:-bottom-0.5 after:border-b-2 after:transition-opacity after:duration-200",
80
+ "after:pointer-events-none after:border-[--border-color] after:opacity-30 after:data-[active=true]:opacity-100",
81
+ className,
82
+ )}
83
+ suppressHydrationWarning
77
84
  ref={ref}
78
85
  onClick={onClick}
86
+ style={
87
+ {
88
+ "--border-color": borderColor,
89
+ "--background-color": backgroundColor,
90
+ } as CSSProperties
91
+ }
79
92
  >
80
- <span
81
- className="absolute inset-0 border-b-2 transition-opacity duration-200 opacity-30 group-data-[active=true]:opacity-100"
82
- style={{ borderColor, backgroundColor }}
83
- />
84
- <span className="relative">{children ?? name}</span>
93
+ {children ?? name}
85
94
  </span>
86
95
  );
87
96
  };
@@ -1,9 +1,10 @@
1
+ import { useSuspenseQuery } from "@tanstack/react-query";
1
2
  import { CheckIcon, CopyIcon } from "lucide-react";
2
3
  import { useState, useTransition } from "react";
3
- import { useQuery } from "urql";
4
4
  import { useSelectedServerStore } from "../../authentication/state.js";
5
5
  import { InlineCode } from "../../components/InlineCode.js";
6
6
  import { Button } from "../../ui/Button.js";
7
+ import { useCreateQuery } from "./client/useCreateQuery.js";
7
8
  import { useOasConfig } from "./context.js";
8
9
  import { graphql } from "./graphql/index.js";
9
10
  import { SimpleSelect } from "./SimpleSelect.js";
@@ -42,19 +43,13 @@ const CopyButton = ({ url }: { url: string }) => {
42
43
  );
43
44
  };
44
45
 
45
- const context = { suspense: true } as const;
46
-
47
46
  export const Endpoint = () => {
48
- const [result] = useQuery({
49
- query: ServersQuery,
50
- variables: useOasConfig(),
51
- context,
52
- });
47
+ const { input, type } = useOasConfig();
48
+ const query = useCreateQuery(ServersQuery, { input, type });
49
+ const result = useSuspenseQuery(query);
53
50
  const [, startTransition] = useTransition();
54
51
  const { selectedServer, setSelectedServer } = useSelectedServerStore();
55
52
 
56
- if (!result.data) return null;
57
-
58
53
  const { servers } = result.data.schema;
59
54
 
60
55
  if (servers.length === 1) {
@@ -1,17 +1,13 @@
1
1
  import { ResultOf } from "@graphql-typed-document-node/core";
2
- import type { CSSProperties } from "react";
3
- import { useQuery } from "urql";
2
+ import { useSuspenseQuery } from "@tanstack/react-query";
4
3
  import { CategoryHeading } from "../../components/CategoryHeading.js";
5
- import { DeveloperHint } from "../../components/DeveloperHint.js";
6
- import { ErrorPage } from "../../components/ErrorPage.js";
7
4
  import { Heading } from "../../components/Heading.js";
8
- import { InlineCode } from "../../components/InlineCode.js";
9
5
  import { Markdown, ProseClasses } from "../../components/Markdown.js";
10
- import { SyntaxHighlight } from "../../components/SyntaxHighlight.js";
11
6
  import { cn } from "../../util/cn.js";
12
7
  import { Endpoint } from "./Endpoint.js";
13
8
  import { OperationListItem } from "./OperationListItem.js";
14
9
  import StaggeredRender from "./StaggeredRender.js";
10
+ import { useCreateQuery } from "./client/useCreateQuery.js";
15
11
  import { useOasConfig } from "./context.js";
16
12
  import { graphql } from "./graphql/index.js";
17
13
 
@@ -100,41 +96,10 @@ const AllOperationsQuery = graphql(/* GraphQL */ `
100
96
  }
101
97
  `);
102
98
 
103
- const suspenseContext = { suspense: true };
104
-
105
99
  export const OperationList = () => {
106
- const { type, input } = useOasConfig();
107
-
108
- const [result] = useQuery({
109
- query: AllOperationsQuery,
110
- variables: { type, input },
111
- context: suspenseContext,
112
- });
113
-
114
- const error = result.error?.graphQLErrors.at(0);
115
-
116
- // Looks like there is no Suspense level error handling (yet)?
117
- // So we handle the error case in the component directly
118
- if (error) {
119
- return (
120
- <ErrorPage
121
- category="Error"
122
- title="Schema cannot be displayed"
123
- message={
124
- <>
125
- <DeveloperHint className="mb-4">
126
- Check your configuration value <InlineCode>apis.type</InlineCode>{" "}
127
- and <InlineCode>apis.input</InlineCode> in the Zudoku config.
128
- </DeveloperHint>
129
- An error occurred while trying to fetch the API reference:
130
- <SyntaxHighlight code={error.toString()} language="plain" />
131
- </>
132
- }
133
- />
134
- );
135
- }
136
-
137
- if (!result.data) return null;
100
+ const { input, type } = useOasConfig();
101
+ const query = useCreateQuery(AllOperationsQuery, { input, type });
102
+ const result = useSuspenseQuery(query);
138
103
 
139
104
  return (
140
105
  <div className="pt-[--padding-content-top]">
@@ -1,20 +1,19 @@
1
1
  import { Outlet } from "react-router-dom";
2
- import { Provider, Client as UrqlClient } from "urql";
2
+ import type { GraphQLClient } from "./client/GraphQLClient.js";
3
+ import { GraphQLProvider } from "./client/GraphQLContext.js";
3
4
  import { OasConfigProvider } from "./context.js";
4
5
  import { OasPluginConfig } from "./interfaces.js";
5
6
 
6
- export function OpenApiRoute({
7
+ export const OpenApiRoute = ({
7
8
  config,
8
9
  client,
9
10
  }: {
10
11
  config: OasPluginConfig;
11
- client: typeof UrqlClient;
12
- }) {
13
- return (
14
- <Provider value={client}>
15
- <OasConfigProvider value={{ config }}>
16
- <Outlet />
17
- </OasConfigProvider>
18
- </Provider>
19
- );
20
- }
12
+ client: GraphQLClient;
13
+ }) => (
14
+ <OasConfigProvider value={{ config }}>
15
+ <GraphQLProvider client={client}>
16
+ <Outlet />
17
+ </GraphQLProvider>
18
+ </OasConfigProvider>
19
+ );
@@ -1,13 +1,14 @@
1
+ import { useSuspenseQuery } from "@tanstack/react-query";
1
2
  import { HTTPSnippet } from "@zudoku/httpsnippet";
2
3
  import { Fragment, useMemo, useTransition } from "react";
3
4
  import { useSearchParams } from "react-router-dom";
4
- import { useQuery } from "urql";
5
5
  import { useSelectedServerStore } from "../../authentication/state.js";
6
6
  import { TextColorMap } from "../../components/navigation/SidebarBadge.js";
7
7
  import { SyntaxHighlight } from "../../components/SyntaxHighlight.js";
8
8
  import type { SchemaObject } from "../../oas/parser/index.js";
9
9
  import { cn } from "../../util/cn.js";
10
10
  import { useOnScreen } from "../../util/useOnScreen.js";
11
+ import { useCreateQuery } from "./client/useCreateQuery.js";
11
12
  import { CollapsibleCode } from "./CollapsibleCode.js";
12
13
  import { ColorizedParam } from "./ColorizedParam.js";
13
14
  import { useOasConfig } from "./context.js";
@@ -75,8 +76,6 @@ export const GetServerQuery = graphql(/* GraphQL */ `
75
76
  }
76
77
  `);
77
78
 
78
- const context = { suspense: true };
79
-
80
79
  const methodToColor = {
81
80
  get: TextColorMap.green,
82
81
  post: TextColorMap.blue,
@@ -111,12 +110,10 @@ export const Sidecar = ({
111
110
  selectedResponse?: string;
112
111
  onSelectResponse: (response: string) => void;
113
112
  }) => {
114
- const oasConfig = useOasConfig();
115
- const [result] = useQuery({
116
- query: GetServerQuery,
117
- variables: oasConfig,
118
- context,
119
- });
113
+ const { input, type } = useOasConfig();
114
+ const query = useCreateQuery(GetServerQuery, { input, type });
115
+ const result = useSuspenseQuery(query);
116
+
120
117
  const methodTextColor =
121
118
  methodToColor[
122
119
  operation.method.toLocaleLowerCase() as keyof typeof methodToColor
@@ -165,7 +162,7 @@ export const Sidecar = ({
165
162
  const snippet = new HTTPSnippet({
166
163
  method: operation.method.toLocaleUpperCase(),
167
164
  url:
168
- (selectedServer ?? result.data?.schema.url ?? "") +
165
+ (selectedServer ?? result.data.schema.url ?? "") +
169
166
  operation.path.replaceAll("{", ":").replaceAll("}", ""),
170
167
  postData: example
171
168
  ? {
@@ -187,7 +184,7 @@ export const Sidecar = ({
187
184
  operation.method,
188
185
  operation.path,
189
186
  selectedServer,
190
- result.data?.schema.url,
187
+ result.data.schema.url,
191
188
  selectedLang,
192
189
  ]);
193
190
  const [ref, isOnScreen] = useOnScreen({ rootMargin: "200px 0px 200px 0px" });
@@ -208,9 +205,9 @@ export const Sidecar = ({
208
205
  </span>
209
206
  {isOnScreen && (
210
207
  <PlaygroundDialogWrapper
211
- server={result.data?.schema.url ?? ""}
208
+ server={result.data.schema.url ?? ""}
212
209
  servers={
213
- result.data?.schema.servers.map((server) => server.url) ?? []
210
+ result.data.schema.servers.map((server) => server.url) ?? []
214
211
  }
215
212
  operation={operation}
216
213
  />
@@ -0,0 +1,140 @@
1
+ import type { GraphQLError } from "graphql/error/index.js";
2
+ import { ulid } from "ulidx";
3
+ import { initializeWorker } from "zudoku/openapi-worker";
4
+ import { ZudokuError } from "../../../util/invariant.js";
5
+ import type { TypedDocumentString } from "../graphql/graphql.js";
6
+ import type { OpenApiPluginOptions } from "../index.js";
7
+ import type { LocalServer } from "./createServer.js";
8
+ import type { WorkerGraphQLMessage } from "./worker.js";
9
+
10
+ let localServerPromise: Promise<LocalServer> | undefined;
11
+ let worker: SharedWorker | undefined;
12
+
13
+ type GraphQLResponse<TResult> = {
14
+ errors?: GraphQLError[];
15
+ data: TResult;
16
+ };
17
+
18
+ const throwIfError = (response: GraphQLResponse<unknown>) => {
19
+ if (!response.errors?.[0]) return;
20
+
21
+ throw new ZudokuError(response.errors[0].message, {
22
+ developerHint:
23
+ "Check your configuration value `apis.type` and `apis.input` in the Zudoku config.",
24
+ });
25
+ };
26
+
27
+ export class GraphQLClient {
28
+ readonly #mode: "remote" | "in-memory" | "worker";
29
+ #pendingRequests = new Map<string, (value: any) => void>();
30
+ #port: MessagePort | undefined;
31
+
32
+ constructor(private config: OpenApiPluginOptions) {
33
+ if (config.server) {
34
+ this.#mode = "remote";
35
+ } else if (config.inMemory || typeof SharedWorker === "undefined") {
36
+ this.#mode = "in-memory";
37
+ } else {
38
+ this.#mode = "worker";
39
+ }
40
+ }
41
+
42
+ #initializeLocalServer = () =>
43
+ import("./createServer.js").then((m) => m.createServer());
44
+
45
+ fetch = async <TResult, TVariables>(
46
+ query: TypedDocumentString<TResult, TVariables>,
47
+ ...[variables]: TVariables extends Record<string, never> ? [] : [TVariables]
48
+ ) => {
49
+ const operationName = query.match(/query (\w+)/)?.[1];
50
+ const body = JSON.stringify({ query, variables, operationName });
51
+
52
+ switch (this.#mode) {
53
+ case "remote": {
54
+ const response = await fetch(this.config.server!, {
55
+ method: "POST",
56
+ body,
57
+ headers: { "Content-Type": "application/json" },
58
+ });
59
+
60
+ if (!response.ok) {
61
+ throw new Error("Network response was not ok");
62
+ }
63
+
64
+ const result = (await response.json()) as GraphQLResponse<TResult>;
65
+ throwIfError(result);
66
+
67
+ return result.data;
68
+ }
69
+
70
+ case "in-memory": {
71
+ if (!localServerPromise) {
72
+ localServerPromise = this.#initializeLocalServer();
73
+ }
74
+
75
+ const localServer = await localServerPromise;
76
+ if (!localServer) throw new Error("Local server not initialized");
77
+
78
+ const response = await localServer.fetch(
79
+ new Request("http://localhost/graphql", {
80
+ method: "POST",
81
+ body,
82
+ headers: { "Content-Type": "application/json" },
83
+ }),
84
+ );
85
+
86
+ if (!response.ok) {
87
+ throw new Error("Network response was not ok");
88
+ }
89
+
90
+ const result = (await response.json()) as GraphQLResponse<TResult>;
91
+ throwIfError(result);
92
+
93
+ return result.data;
94
+ }
95
+
96
+ case "worker": {
97
+ if (!worker) {
98
+ worker = initializeWorker();
99
+ }
100
+
101
+ if (!this.#port) {
102
+ const channel = new MessageChannel();
103
+
104
+ worker.port.postMessage({ port: channel.port2 }, [channel.port2]);
105
+
106
+ this.#port = channel.port1;
107
+
108
+ this.#port.onmessage = (e: MessageEvent<WorkerGraphQLMessage>) => {
109
+ const { id, body } = e.data;
110
+ const resolve = this.#pendingRequests.get(id);
111
+ if (resolve) {
112
+ const result = JSON.parse(body);
113
+ resolve(result);
114
+ this.#pendingRequests.delete(id);
115
+ } else {
116
+ // eslint-disable-next-line no-console
117
+ console.error(`No pending request found for id: ${id}`);
118
+ }
119
+ };
120
+
121
+ this.#port.start();
122
+ }
123
+
124
+ const id = ulid();
125
+
126
+ const resultPromise = new Promise<GraphQLResponse<TResult>>(
127
+ (resolve) => {
128
+ this.#pendingRequests.set(id, resolve);
129
+ this.#port!.postMessage({ id, body } as WorkerGraphQLMessage);
130
+ },
131
+ );
132
+
133
+ const result = await resultPromise;
134
+ throwIfError(result);
135
+
136
+ return result.data;
137
+ }
138
+ }
139
+ };
140
+ }
@@ -0,0 +1,16 @@
1
+ import { createContext, type ReactNode } from "react";
2
+ import { GraphQLClient } from "./GraphQLClient.js";
3
+
4
+ export const GraphQLContext = createContext<GraphQLClient | undefined>(
5
+ undefined,
6
+ );
7
+
8
+ export const GraphQLProvider = ({
9
+ children,
10
+ client,
11
+ }: {
12
+ children: ReactNode;
13
+ client: GraphQLClient;
14
+ }) => (
15
+ <GraphQLContext.Provider value={client}>{children}</GraphQLContext.Provider>
16
+ );
@@ -31,3 +31,5 @@ export const createServer = () =>
31
31
  }),
32
32
  ],
33
33
  });
34
+
35
+ export type LocalServer = ReturnType<typeof createServer>;
@@ -0,0 +1,18 @@
1
+ import { useContext } from "react";
2
+ import type { TypedDocumentString } from "../graphql/graphql.js";
3
+ import { GraphQLContext } from "./GraphQLContext.js";
4
+
5
+ export const useCreateQuery = <TResult, TVariables>(
6
+ query: TypedDocumentString<TResult, TVariables>,
7
+ ...variables: TVariables extends Record<string, never> ? [] : [TVariables]
8
+ ) => {
9
+ const graphQLClient = useContext(GraphQLContext);
10
+ if (graphQLClient === undefined) {
11
+ throw new Error("useGraphQL must be used within a GraphQLProvider");
12
+ }
13
+
14
+ return {
15
+ queryFn: () => graphQLClient.fetch(query, ...variables),
16
+ queryKey: [query, variables[0]],
17
+ } as const;
18
+ };