zudoku 0.64.1 → 0.64.2

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 (223) hide show
  1. package/dist/config/config.d.ts +15 -46
  2. package/dist/config/validators/InputNavigationSchema.d.ts +53 -53
  3. package/dist/config/validators/ProtectedRoutesSchema.d.ts +1 -1
  4. package/dist/config/validators/validate.d.ts +105 -1
  5. package/dist/config/validators/validate.js +30 -0
  6. package/dist/config/validators/validate.js.map +1 -1
  7. package/dist/flat-config.d.ts +16 -0
  8. package/dist/lib/auth/issuer.js +3 -0
  9. package/dist/lib/auth/issuer.js.map +1 -1
  10. package/dist/lib/authentication/authentication.d.ts +1 -1
  11. package/dist/lib/authentication/providers/firebase.d.ts +4 -0
  12. package/dist/lib/authentication/providers/firebase.js +215 -0
  13. package/dist/lib/authentication/providers/firebase.js.map +1 -0
  14. package/dist/lib/authentication/providers/supabase.js +1 -6
  15. package/dist/lib/authentication/providers/supabase.js.map +1 -1
  16. package/dist/lib/authentication/ui/ZudokuAuthUi.d.ts +24 -0
  17. package/dist/lib/authentication/ui/ZudokuAuthUi.js +124 -0
  18. package/dist/lib/authentication/ui/ZudokuAuthUi.js.map +1 -0
  19. package/dist/lib/authentication/ui/icons/Apple.d.ts +3 -0
  20. package/dist/lib/authentication/ui/icons/Apple.js +4 -0
  21. package/dist/lib/authentication/ui/icons/Apple.js.map +1 -0
  22. package/dist/lib/authentication/ui/icons/Facebook.d.ts +3 -0
  23. package/dist/lib/authentication/ui/icons/Facebook.js +4 -0
  24. package/dist/lib/authentication/ui/icons/Facebook.js.map +1 -0
  25. package/dist/lib/authentication/ui/icons/Github.d.ts +3 -0
  26. package/dist/lib/authentication/ui/icons/Github.js +4 -0
  27. package/dist/lib/authentication/ui/icons/Github.js.map +1 -0
  28. package/dist/lib/authentication/ui/icons/Google.d.ts +3 -0
  29. package/dist/lib/authentication/ui/icons/Google.js +4 -0
  30. package/dist/lib/authentication/ui/icons/Google.js.map +1 -0
  31. package/dist/lib/authentication/ui/icons/Microsoft.d.ts +3 -0
  32. package/dist/lib/authentication/ui/icons/Microsoft.js +4 -0
  33. package/dist/lib/authentication/ui/icons/Microsoft.js.map +1 -0
  34. package/dist/lib/authentication/ui/icons/X.d.ts +3 -0
  35. package/dist/lib/authentication/ui/icons/X.js +4 -0
  36. package/dist/lib/authentication/ui/icons/X.js.map +1 -0
  37. package/dist/lib/components/Heading.d.ts +1 -1
  38. package/dist/lib/core/RouteGuard.js +6 -6
  39. package/dist/lib/core/RouteGuard.js.map +1 -1
  40. package/dist/lib/oas/parser/index.js +7 -3
  41. package/dist/lib/oas/parser/index.js.map +1 -1
  42. package/dist/lib/plugins/api-keys/ProtectedRoute.js +4 -1
  43. package/dist/lib/plugins/api-keys/ProtectedRoute.js.map +1 -1
  44. package/dist/lib/plugins/openapi/CollapsibleCode.d.ts +1 -0
  45. package/dist/lib/plugins/openapi/CollapsibleCode.js +2 -1
  46. package/dist/lib/plugins/openapi/CollapsibleCode.js.map +1 -1
  47. package/dist/lib/plugins/openapi/GeneratedExampleSidecarBox.d.ts +5 -0
  48. package/dist/lib/plugins/openapi/GeneratedExampleSidecarBox.js +10 -0
  49. package/dist/lib/plugins/openapi/GeneratedExampleSidecarBox.js.map +1 -0
  50. package/dist/lib/plugins/openapi/OperationList.js +4 -1
  51. package/dist/lib/plugins/openapi/OperationList.js.map +1 -1
  52. package/dist/lib/plugins/openapi/OperationListItem.d.ts +2 -1
  53. package/dist/lib/plugins/openapi/OperationListItem.js +2 -2
  54. package/dist/lib/plugins/openapi/OperationListItem.js.map +1 -1
  55. package/dist/lib/plugins/openapi/RequestBodySidecarBox.d.ts +9 -2
  56. package/dist/lib/plugins/openapi/RequestBodySidecarBox.js +2 -2
  57. package/dist/lib/plugins/openapi/RequestBodySidecarBox.js.map +1 -1
  58. package/dist/lib/plugins/openapi/ResponsesSidecarBox.d.ts +3 -1
  59. package/dist/lib/plugins/openapi/ResponsesSidecarBox.js +14 -2
  60. package/dist/lib/plugins/openapi/ResponsesSidecarBox.js.map +1 -1
  61. package/dist/lib/plugins/openapi/Sidecar.d.ts +2 -1
  62. package/dist/lib/plugins/openapi/Sidecar.js +33 -30
  63. package/dist/lib/plugins/openapi/Sidecar.js.map +1 -1
  64. package/dist/lib/plugins/openapi/SidecarExamples.d.ts +9 -2
  65. package/dist/lib/plugins/openapi/SidecarExamples.js +15 -33
  66. package/dist/lib/plugins/openapi/SidecarExamples.js.map +1 -1
  67. package/dist/lib/plugins/openapi/components/NonHighlightedCode.d.ts +4 -0
  68. package/dist/lib/plugins/openapi/components/NonHighlightedCode.js +5 -0
  69. package/dist/lib/plugins/openapi/components/NonHighlightedCode.js.map +1 -0
  70. package/dist/lib/plugins/openapi/components/ResponseContent.js +1 -1
  71. package/dist/lib/plugins/openapi/components/ResponseContent.js.map +1 -1
  72. package/dist/lib/plugins/openapi/playground/InlineInput.d.ts +1 -1
  73. package/dist/lib/plugins/openapi/playground/ParamsGrid.d.ts +2 -2
  74. package/dist/lib/plugins/openapi/schema/SchemaPropertyItem.js +1 -2
  75. package/dist/lib/plugins/openapi/schema/SchemaPropertyItem.js.map +1 -1
  76. package/dist/lib/plugins/openapi/schema/SchemaView.js +0 -4
  77. package/dist/lib/plugins/openapi/schema/SchemaView.js.map +1 -1
  78. package/dist/lib/plugins/openapi/schema/union-helpers.js +0 -1
  79. package/dist/lib/plugins/openapi/schema/union-helpers.js.map +1 -1
  80. package/dist/lib/plugins/openapi/util/generateSchemaExample.js +5 -14
  81. package/dist/lib/plugins/openapi/util/generateSchemaExample.js.map +1 -1
  82. package/dist/lib/ui/CodeBlock.d.ts +0 -1
  83. package/dist/lib/ui/CodeBlock.js.map +1 -1
  84. package/dist/lib/ui/Command.d.ts +3 -3
  85. package/dist/lib/ui/EmbeddedCodeBlock.d.ts +0 -1
  86. package/dist/lib/ui/EmbeddedCodeBlock.js +1 -1
  87. package/dist/lib/ui/EmbeddedCodeBlock.js.map +1 -1
  88. package/dist/lib/ui/Separator.d.ts +4 -0
  89. package/dist/lib/ui/Separator.js +8 -0
  90. package/dist/lib/ui/Separator.js.map +1 -0
  91. package/dist/lib/ui/Tooltip.d.ts +7 -7
  92. package/dist/lib/ui/Tooltip.js +16 -10
  93. package/dist/lib/ui/Tooltip.js.map +1 -1
  94. package/dist/lib/util/createVariantComponent.d.ts +5 -2
  95. package/dist/lib/util/createVariantComponent.js +5 -2
  96. package/dist/lib/util/createVariantComponent.js.map +1 -1
  97. package/dist/lib/util/flattenAllOf.d.ts +4 -0
  98. package/dist/lib/util/flattenAllOf.js +65 -0
  99. package/dist/lib/util/flattenAllOf.js.map +1 -0
  100. package/dist/lib/util/flattenAllOf.test.d.ts +1 -0
  101. package/dist/lib/util/flattenAllOf.test.js +532 -0
  102. package/dist/lib/util/flattenAllOf.test.js.map +1 -0
  103. package/dist/vite/api/SchemaManager.js +6 -18
  104. package/dist/vite/api/SchemaManager.js.map +1 -1
  105. package/dist/vite/plugin-theme.js +10 -1
  106. package/dist/vite/plugin-theme.js.map +1 -1
  107. package/lib/{ErrorAlert-DE3Sf66a.js → ErrorAlert--3alJ_-b.js} +1340 -1311
  108. package/lib/{ErrorAlert-DE3Sf66a.js.map → ErrorAlert--3alJ_-b.js.map} +1 -1
  109. package/lib/{MdxPage-DZfeC0QY.js → MdxPage-Bpa9tL63.js} +5 -5
  110. package/lib/{MdxPage-DZfeC0QY.js.map → MdxPage-Bpa9tL63.js.map} +1 -1
  111. package/lib/{OAuthErrorPage-BycMozgn.js → OAuthErrorPage-B79J86Fo.js} +4 -4
  112. package/lib/{OAuthErrorPage-BycMozgn.js.map → OAuthErrorPage-B79J86Fo.js.map} +1 -1
  113. package/lib/{OasProvider-1XEOsIiW.js → OasProvider-jr0oDSFy.js} +2 -2
  114. package/lib/{OasProvider-1XEOsIiW.js.map → OasProvider-jr0oDSFy.js.map} +1 -1
  115. package/lib/OperationList-DLEAg4qw.js +5465 -0
  116. package/lib/OperationList-DLEAg4qw.js.map +1 -0
  117. package/lib/{Pagination-CJszmeSA.js → Pagination-H2HW9-Er.js} +2 -2
  118. package/lib/{Pagination-CJszmeSA.js.map → Pagination-H2HW9-Er.js.map} +1 -1
  119. package/lib/RouteGuard-CjzxosTf.js +77 -0
  120. package/lib/RouteGuard-CjzxosTf.js.map +1 -0
  121. package/lib/{RouterError-VDLnrFqF.js → RouterError-DZS2d6Sc.js} +2 -2
  122. package/lib/{RouterError-VDLnrFqF.js.map → RouterError-DZS2d6Sc.js.map} +1 -1
  123. package/lib/{SchemaList-qOHkDzSz.js → SchemaList-CSDSazqV.js} +6 -6
  124. package/lib/{SchemaList-qOHkDzSz.js.map → SchemaList-CSDSazqV.js.map} +1 -1
  125. package/lib/SchemaView-DJiBd0_5.js +397 -0
  126. package/lib/SchemaView-DJiBd0_5.js.map +1 -0
  127. package/lib/{SignUp-6SGx9Yyq.js → SignUp-Fycafbyg.js} +2 -2
  128. package/lib/{SignUp-6SGx9Yyq.js.map → SignUp-Fycafbyg.js.map} +1 -1
  129. package/lib/{SyntaxHighlight-zvlnSnHB.js → SyntaxHighlight-C19vH0V_.js} +525 -509
  130. package/lib/SyntaxHighlight-C19vH0V_.js.map +1 -0
  131. package/lib/{Toc-Da9yp7lo.js → Toc-ChkOg2UU.js} +2 -2
  132. package/lib/{Toc-Da9yp7lo.js.map → Toc-ChkOg2UU.js.map} +1 -1
  133. package/lib/{circular-CSSuz-LS.js → circular-DGfd8SGc.js} +2 -2
  134. package/lib/{circular-CSSuz-LS.js.map → circular-DGfd8SGc.js.map} +1 -1
  135. package/lib/{createServer-CLbcVLbK.js → createServer-DGD8hEzT.js} +4662 -4238
  136. package/lib/createServer-DGD8hEzT.js.map +1 -0
  137. package/lib/{errors-CuGgh3hf.js → errors-BTpjwHS6.js} +2 -2
  138. package/lib/{errors-CuGgh3hf.js.map → errors-BTpjwHS6.js.map} +1 -1
  139. package/lib/{index-rYHsvtTo.js → index-Bvas0H4x.js} +2 -2
  140. package/lib/{index-rYHsvtTo.js.map → index-Bvas0H4x.js.map} +1 -1
  141. package/lib/{index-RNAxx6IF.js → index-DP1xZgfJ.js} +9 -9
  142. package/lib/index-DP1xZgfJ.js.map +1 -0
  143. package/lib/{index-B1rmok4X.js → index-FNRZUtwo.js} +2 -2
  144. package/lib/{index-B1rmok4X.js.map → index-FNRZUtwo.js.map} +1 -1
  145. package/lib/ui/CodeBlock.js.map +1 -1
  146. package/lib/ui/EmbeddedCodeBlock.js +9 -9
  147. package/lib/ui/EmbeddedCodeBlock.js.map +1 -1
  148. package/lib/ui/Separator.js +27 -0
  149. package/lib/ui/Separator.js.map +1 -0
  150. package/lib/ui/SyntaxHighlight.js +1 -1
  151. package/lib/ui/Tooltip.js +55 -28
  152. package/lib/ui/Tooltip.js.map +1 -1
  153. package/lib/zudoku.__internal.js +4 -4
  154. package/lib/zudoku.auth-azureb2c.js +3 -3
  155. package/lib/zudoku.auth-clerk.js +1 -1
  156. package/lib/zudoku.auth-openid.js +3 -3
  157. package/lib/zudoku.auth-supabase.js +30 -33
  158. package/lib/zudoku.auth-supabase.js.map +1 -1
  159. package/lib/zudoku.components.js +2 -2
  160. package/lib/zudoku.plugin-api-catalog.js +3 -3
  161. package/lib/zudoku.plugin-api-keys.js +3 -3
  162. package/lib/zudoku.plugin-api-keys.js.map +1 -1
  163. package/lib/zudoku.plugin-markdown.js +1 -1
  164. package/lib/zudoku.plugin-openapi.js +1 -1
  165. package/lib/zudoku.plugin-search-pagefind.js +1 -1
  166. package/package.json +15 -10
  167. package/src/app/main.css +1 -1
  168. package/src/lib/auth/issuer.ts +3 -0
  169. package/src/lib/authentication/authentication.ts +1 -1
  170. package/src/lib/authentication/providers/firebase.tsx +284 -0
  171. package/src/lib/authentication/providers/supabase.tsx +2 -7
  172. package/src/lib/authentication/ui/ZudokuAuthUi.tsx +335 -0
  173. package/src/lib/authentication/ui/icons/Apple.tsx +10 -0
  174. package/src/lib/authentication/ui/icons/Facebook.tsx +15 -0
  175. package/src/lib/authentication/ui/icons/Github.tsx +16 -0
  176. package/src/lib/authentication/ui/icons/Google.tsx +16 -0
  177. package/src/lib/authentication/ui/icons/Microsoft.tsx +12 -0
  178. package/src/lib/authentication/ui/icons/X.tsx +10 -0
  179. package/src/lib/core/RouteGuard.tsx +8 -8
  180. package/src/lib/oas/parser/index.ts +8 -3
  181. package/src/lib/plugins/api-keys/ProtectedRoute.tsx +11 -7
  182. package/src/lib/plugins/openapi/CollapsibleCode.tsx +5 -3
  183. package/src/lib/plugins/openapi/GeneratedExampleSidecarBox.tsx +52 -0
  184. package/src/lib/plugins/openapi/OperationList.tsx +5 -0
  185. package/src/lib/plugins/openapi/OperationListItem.tsx +3 -0
  186. package/src/lib/plugins/openapi/RequestBodySidecarBox.tsx +20 -2
  187. package/src/lib/plugins/openapi/ResponsesSidecarBox.tsx +26 -1
  188. package/src/lib/plugins/openapi/Sidecar.tsx +84 -63
  189. package/src/lib/plugins/openapi/SidecarExamples.tsx +38 -48
  190. package/src/lib/plugins/openapi/components/NonHighlightedCode.tsx +22 -0
  191. package/src/lib/plugins/openapi/components/ResponseContent.tsx +1 -1
  192. package/src/lib/plugins/openapi/schema/SchemaPropertyItem.tsx +1 -4
  193. package/src/lib/plugins/openapi/schema/SchemaView.tsx +0 -5
  194. package/src/lib/plugins/openapi/schema/union-helpers.ts +0 -1
  195. package/src/lib/plugins/openapi/util/generateSchemaExample.ts +5 -15
  196. package/src/lib/ui/CodeBlock.tsx +0 -1
  197. package/src/lib/ui/EmbeddedCodeBlock.tsx +1 -2
  198. package/src/lib/ui/Separator.tsx +25 -0
  199. package/src/lib/ui/Tooltip.tsx +54 -32
  200. package/src/lib/util/createVariantComponent.tsx +31 -5
  201. package/src/lib/util/flattenAllOf.test.ts +637 -0
  202. package/src/lib/util/flattenAllOf.ts +101 -0
  203. package/dist/lib/plugins/openapi/schema/AllOfGroup/AllOfGroupConnector.d.ts +0 -5
  204. package/dist/lib/plugins/openapi/schema/AllOfGroup/AllOfGroupConnector.js +0 -7
  205. package/dist/lib/plugins/openapi/schema/AllOfGroup/AllOfGroupConnector.js.map +0 -1
  206. package/dist/lib/plugins/openapi/schema/AllOfGroup/AllOfGroupItem.d.ts +0 -4
  207. package/dist/lib/plugins/openapi/schema/AllOfGroup/AllOfGroupItem.js +0 -10
  208. package/dist/lib/plugins/openapi/schema/AllOfGroup/AllOfGroupItem.js.map +0 -1
  209. package/dist/lib/plugins/openapi/schema/AllOfGroup/AllOfGroupView.d.ts +0 -5
  210. package/dist/lib/plugins/openapi/schema/AllOfGroup/AllOfGroupView.js +0 -16
  211. package/dist/lib/plugins/openapi/schema/AllOfGroup/AllOfGroupView.js.map +0 -1
  212. package/lib/OperationList-DCJw6wXL.js +0 -5450
  213. package/lib/OperationList-DCJw6wXL.js.map +0 -1
  214. package/lib/RouteGuard-DhU3LRr1.js +0 -81
  215. package/lib/RouteGuard-DhU3LRr1.js.map +0 -1
  216. package/lib/SchemaView-D3hm65cc.js +0 -458
  217. package/lib/SchemaView-D3hm65cc.js.map +0 -1
  218. package/lib/SyntaxHighlight-zvlnSnHB.js.map +0 -1
  219. package/lib/createServer-CLbcVLbK.js.map +0 -1
  220. package/lib/index-RNAxx6IF.js.map +0 -1
  221. package/src/lib/plugins/openapi/schema/AllOfGroup/AllOfGroupConnector.tsx +0 -36
  222. package/src/lib/plugins/openapi/schema/AllOfGroup/AllOfGroupItem.tsx +0 -25
  223. package/src/lib/plugins/openapi/schema/AllOfGroup/AllOfGroupView.tsx +0 -42
@@ -0,0 +1,16 @@
1
+ import type { SVGProps } from "react";
2
+
3
+ const GoogleIcon = (props: SVGProps<SVGSVGElement>) => (
4
+ <svg
5
+ viewBox="0 0 24 24"
6
+ xmlns="http://www.w3.org/2000/svg"
7
+ width="1em"
8
+ height="1em"
9
+ {...props}
10
+ >
11
+ <title>{"Google"}</title>
12
+ <path d="M12.48 10.92v3.28h7.84c-.24 1.84-.853 3.187-1.787 4.133-1.147 1.147-2.933 2.4-6.053 2.4-4.827 0-8.6-3.893-8.6-8.72s3.773-8.72 8.6-8.72c2.6 0 4.507 1.027 5.907 2.347l2.307-2.307C18.747 1.44 16.133 0 12.48 0 5.867 0 .307 5.387.307 12s5.56 12 12.173 12c3.573 0 6.267-1.173 8.373-3.36 2.16-2.16 2.84-5.213 2.84-7.667 0-.76-.053-1.467-.173-2.053H12.48z" />
13
+ </svg>
14
+ );
15
+
16
+ export default GoogleIcon;
@@ -0,0 +1,12 @@
1
+ import type { SVGProps } from "react";
2
+
3
+ const MicrosoftIcon = (props: SVGProps<SVGSVGElement>) => (
4
+ <svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" {...props}>
5
+ <path fill="#f25022" d="M1 1h9v9H1z" />
6
+ <path fill="#00a4ef" d="M1 11h9v9H1z" />
7
+ <path fill="#7fba00" d="M11 1h9v9h-9z" />
8
+ <path fill="#ffb900" d="M11 11h9v9h-9z" />
9
+ </svg>
10
+ );
11
+
12
+ export default MicrosoftIcon;
@@ -0,0 +1,10 @@
1
+ import type { SVGProps } from "react";
2
+
3
+ const XIcon = (props: SVGProps<SVGSVGElement>) => (
4
+ <svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" {...props}>
5
+ <title>{"X"}</title>
6
+ <path d="M14.234 10.162 22.977 0h-2.072l-7.591 8.824L7.251 0H.258l9.168 13.343L.258 24H2.33l8.016-9.318L16.749 24h6.993zm-2.837 3.299-.929-1.329L3.076 1.56h3.182l5.965 8.532.929 1.329 7.754 11.09h-3.182z" />
7
+ </svg>
8
+ );
9
+
10
+ export default XIcon;
@@ -38,6 +38,14 @@ export const RouteGuard = () => {
38
38
  const needsToSignIn =
39
39
  isProtectedRoute && !authCheckFn({ auth, context: zudoku });
40
40
 
41
+ if (isProtectedRoute && !auth.isAuthEnabled) {
42
+ throw new ZudokuError("Authentication is not enabled", {
43
+ title: "Authentication is not enabled",
44
+ developerHint:
45
+ "To use protectedRoutes you need authentication to be enabled",
46
+ });
47
+ }
48
+
41
49
  if (needsToSignIn && auth.isPending && typeof window !== "undefined") {
42
50
  return null;
43
51
  }
@@ -91,14 +99,6 @@ export const RouteGuard = () => {
91
99
  );
92
100
  }
93
101
 
94
- if (isProtectedRoute && !auth.isAuthEnabled) {
95
- throw new ZudokuError("Authentication is not enabled", {
96
- title: "Authentication is not enabled",
97
- developerHint:
98
- "To use protectedRoutes you need authentication to be enabled",
99
- });
100
- }
101
-
102
102
  return (
103
103
  <>
104
104
  {shouldBypass && (
@@ -1,6 +1,6 @@
1
- import { merge as mergeAllOf } from "allof-merge";
2
1
  import { GraphQLError } from "graphql/error/index.js";
3
2
  import { OpenAPIV3, type OpenAPIV3_1 } from "openapi-types";
3
+ import { flattenAllOfProcessor } from "../../util/flattenAllOf.js";
4
4
  import { dereference, type JSONSchema } from "./dereference/index.js";
5
5
  import { upgradeSchema } from "./upgrade/index.js";
6
6
 
@@ -101,7 +101,12 @@ export const validate = async (schemaInput: unknown) => {
101
101
 
102
102
  const dereferenced = await dereference(schema);
103
103
  const upgraded = upgradeSchema(dereferenced);
104
- const merged = mergeAllOf(upgraded) as OpenAPIDocument;
105
104
 
106
- return merged;
105
+ const flattened = await flattenAllOfProcessor({
106
+ schema: upgraded,
107
+ file: "schema.json",
108
+ dereference: async (schema) => schema,
109
+ });
110
+
111
+ return flattened;
107
112
  };
@@ -11,15 +11,19 @@ export const ProtectedRoute = () => {
11
11
  return null;
12
12
  }
13
13
 
14
+ if (!auth.isAuthEnabled) {
15
+ return (
16
+ <div className="flex flex-col justify-center gap-2 items-center h-1/2">
17
+ <DeveloperHint className="max-w-[600px]">
18
+ Authentication needs to be enabled for API keys to work. Enable it in
19
+ your Zudoku configuration under <code>authentication</code>.
20
+ </DeveloperHint>
21
+ </div>
22
+ );
23
+ }
24
+
14
25
  return auth.isAuthenticated ? (
15
26
  <Outlet />
16
- ) : !auth.isAuthEnabled ? (
17
- <div className="flex flex-col justify-center gap-2 items-center h-1/2">
18
- <DeveloperHint className="max-w-[600px]">
19
- Authentication needs to be enabled for API keys to work. Enable it in
20
- your Zudoku configuration under <code>authentication</code>.
21
- </DeveloperHint>
22
- </div>
23
27
  ) : (
24
28
  <div className="flex flex-col justify-center gap-2 items-center h-1/2">
25
29
  Please login first to view this page
@@ -9,6 +9,10 @@ import {
9
9
  import { cn } from "../../util/cn.js";
10
10
  import useIsomorphicLayoutEffect from "../../util/useIsomorphicLayoutEffect.js";
11
11
 
12
+ export const OverflowOverlay = () => (
13
+ <div className="absolute inset-0 bg-linear-to-b from-transparent to-zinc-50/60 dark:to-zinc-950/90 z-10 transition-all group-hover:to-transparent" />
14
+ );
15
+
12
16
  export const CollapsibleCode = ({
13
17
  children,
14
18
  maxHeight = 250,
@@ -48,9 +52,7 @@ export const CollapsibleCode = ({
48
52
  !open && isOverflowing && "max-h-(--max-height)",
49
53
  )}
50
54
  >
51
- {!open && isOverflowing && (
52
- <div className=" absolute inset-0 bg-gradient-to-b from-transparent to-zinc-50/60 dark:to-zinc-950/90 z-10 transition-all group-hover:to-transparent"></div>
53
- )}
55
+ {!open && isOverflowing && <OverflowOverlay />}
54
56
  <div ref={contentRef}>{children}</div>
55
57
  {!open && isOverflowing && (
56
58
  <CollapsibleTrigger
@@ -0,0 +1,52 @@
1
+ import { InfoIcon } from "lucide-react";
2
+ import { SyntaxHighlight } from "zudoku/ui/SyntaxHighlight.js";
3
+ import {
4
+ Tooltip,
5
+ TooltipContent,
6
+ TooltipProvider,
7
+ TooltipTrigger,
8
+ } from "zudoku/ui/Tooltip.js";
9
+ import { NonHighlightedCode } from "./components/NonHighlightedCode.js";
10
+ import * as SidecarBox from "./SidecarBox.js";
11
+
12
+ export const GeneratedExampleSidecarBox = ({
13
+ code,
14
+ isOnScreen,
15
+ shouldLazyHighlight,
16
+ }: {
17
+ code: string;
18
+ isOnScreen: boolean;
19
+ shouldLazyHighlight?: boolean;
20
+ }) => {
21
+ return (
22
+ <SidecarBox.Root>
23
+ <SidecarBox.Head className="text-xs flex justify-between items-center">
24
+ <div className="flex items-center gap-1.5 font-mono">
25
+ Request Body Example
26
+ <TooltipProvider>
27
+ <Tooltip>
28
+ <TooltipTrigger asChild>
29
+ <InfoIcon size={13} />
30
+ </TooltipTrigger>
31
+ <TooltipContent>
32
+ This example is auto-generated from the schema.
33
+ </TooltipContent>
34
+ </Tooltip>
35
+ </TooltipProvider>
36
+ </div>
37
+ </SidecarBox.Head>
38
+ <SidecarBox.Body className="p-0">
39
+ {shouldLazyHighlight && !isOnScreen ? (
40
+ <NonHighlightedCode code={code} />
41
+ ) : (
42
+ <SyntaxHighlight
43
+ embedded
44
+ language="json"
45
+ code={code}
46
+ className="[--scrollbar-color:gray] rounded-none text-xs max-h-[200px]"
47
+ />
48
+ )}
49
+ </SidecarBox.Body>
50
+ </SidecarBox.Root>
51
+ );
52
+ };
@@ -200,6 +200,10 @@ export const OperationList = ({
200
200
 
201
201
  const { operations, next, prev, description: tagDescription } = schema.tag;
202
202
 
203
+ // Simple heuristic to determine if we should lazy highlight the code
204
+ // This is to avoid the performance issues when there are a lot of operations
205
+ const shouldLazyHighlight = operations.length > 30;
206
+
203
207
  // The summary property is preferable here as it is a short description of
204
208
  // the API, whereas the description property is typically longer and supports
205
209
  // commonmark formatting, making it ill-suited for use in the meta description
@@ -337,6 +341,7 @@ export const OperationList = ({
337
341
  <OperationListItem
338
342
  operationFragment={fragment}
339
343
  globalSelectedServer={globalSelectedServer}
344
+ shouldLazyHighlight={shouldLazyHighlight}
340
345
  />
341
346
  <hr className="my-10" />
342
347
  </div>
@@ -23,9 +23,11 @@ export type ParameterGroup = (typeof PARAM_GROUPS)[number];
23
23
  export const OperationListItem = ({
24
24
  operationFragment,
25
25
  globalSelectedServer,
26
+ shouldLazyHighlight,
26
27
  }: {
27
28
  operationFragment: FragmentType<typeof OperationsFragment>;
28
29
  globalSelectedServer?: string;
30
+ shouldLazyHighlight?: boolean;
29
31
  }) => {
30
32
  const operation = useFragment(OperationsFragment, operationFragment);
31
33
  const groupedParameters = groupBy(
@@ -173,6 +175,7 @@ export const OperationListItem = ({
173
175
  onSelectResponse={setSelectedResponse}
174
176
  operation={operation}
175
177
  globalSelectedServer={globalSelectedServer}
178
+ shouldLazyHighlight={shouldLazyHighlight}
176
179
  />
177
180
  ))}
178
181
  </div>
@@ -5,9 +5,20 @@ import { SidecarExamples } from "./SidecarExamples.js";
5
5
  export const RequestBodySidecarBox = ({
6
6
  content,
7
7
  onExampleChange,
8
+ isOnScreen,
9
+ shouldLazyHighlight,
10
+ selectedContentIndex,
11
+ selectedExampleIndex,
8
12
  }: {
9
13
  content: MediaTypeObject[];
10
- onExampleChange?: (example: unknown) => void;
14
+ onExampleChange?: (selected: {
15
+ contentTypeIndex: number;
16
+ exampleIndex: number;
17
+ }) => void;
18
+ isOnScreen: boolean;
19
+ shouldLazyHighlight?: boolean;
20
+ selectedContentIndex: number;
21
+ selectedExampleIndex: number;
11
22
  }) => {
12
23
  if (content.length === 0) return null;
13
24
 
@@ -16,7 +27,14 @@ export const RequestBodySidecarBox = ({
16
27
  <SidecarBox.Head className="text-xs flex justify-between items-center">
17
28
  <span className="font-mono">Request Body Example</span>
18
29
  </SidecarBox.Head>
19
- <SidecarExamples content={content} onExampleChange={onExampleChange} />
30
+ <SidecarExamples
31
+ selectedContentIndex={selectedContentIndex}
32
+ selectedExampleIndex={selectedExampleIndex}
33
+ content={content}
34
+ onExampleChange={onExampleChange}
35
+ isOnScreen={isOnScreen}
36
+ shouldLazyHighlight={shouldLazyHighlight}
37
+ />
20
38
  </SidecarBox.Root>
21
39
  );
22
40
  };
@@ -1,4 +1,5 @@
1
1
  import * as Tabs from "@radix-ui/react-tabs";
2
+ import { useEffect, useState } from "react";
2
3
  import { cn } from "../../util/cn.js";
3
4
  import type { ResponseItem } from "./graphql/graphql.js";
4
5
  import * as SidecarBox from "./SidecarBox.js";
@@ -8,11 +9,25 @@ export const ResponsesSidecarBox = ({
8
9
  responses,
9
10
  selectedResponse,
10
11
  onSelectResponse,
12
+ isOnScreen,
13
+ shouldLazyHighlight,
11
14
  }: {
12
15
  responses: ResponseItem[];
13
16
  selectedResponse?: string;
14
17
  onSelectResponse: (response: string) => void;
18
+ isOnScreen: boolean;
19
+ shouldLazyHighlight?: boolean;
15
20
  }) => {
21
+ const [selectedContentIndex, setSelectedContentIndex] = useState(0);
22
+ const [selectedExampleIndex, setSelectedExampleIndex] = useState(0);
23
+
24
+ useEffect(() => {
25
+ if (!selectedResponse) return;
26
+
27
+ setSelectedContentIndex(0);
28
+ setSelectedExampleIndex(0);
29
+ }, [selectedResponse]);
30
+
16
31
  return (
17
32
  <SidecarBox.Root>
18
33
  <Tabs.Root
@@ -40,7 +55,17 @@ export const ResponsesSidecarBox = ({
40
55
  </SidecarBox.Head>
41
56
  {responses.map((response) => (
42
57
  <Tabs.Content key={response.statusCode} value={response.statusCode}>
43
- <SidecarExamples content={response.content ?? []} />
58
+ <SidecarExamples
59
+ selectedContentIndex={selectedContentIndex}
60
+ selectedExampleIndex={selectedExampleIndex}
61
+ onExampleChange={(selected) => {
62
+ setSelectedContentIndex(selected.contentTypeIndex);
63
+ setSelectedExampleIndex(selected.exampleIndex);
64
+ }}
65
+ content={response.content ?? []}
66
+ isOnScreen={isOnScreen}
67
+ shouldLazyHighlight={shouldLazyHighlight}
68
+ />
44
69
  </Tabs.Content>
45
70
  ))}
46
71
  </Tabs.Root>
@@ -1,15 +1,15 @@
1
1
  import { useMemo, useState, useTransition } from "react";
2
2
  import { useSearchParams } from "react-router";
3
3
  import { useZudoku } from "zudoku/hooks";
4
+ import { SyntaxHighlight } from "zudoku/ui/SyntaxHighlight.js";
4
5
  import { useAuthState } from "../../authentication/state.js";
5
6
  import { PathRenderer } from "../../components/PathRenderer.js";
6
- import type { SchemaObject } from "../../oas/parser/index.js";
7
- import { SyntaxHighlight } from "../../ui/SyntaxHighlight.js";
8
7
  import { cn } from "../../util/cn.js";
9
8
  import { useOnScreen } from "../../util/useOnScreen.js";
10
- import { CollapsibleCode } from "./CollapsibleCode.js";
11
9
  import { ColorizedParam } from "./ColorizedParam.js";
10
+ import { NonHighlightedCode } from "./components/NonHighlightedCode.js";
12
11
  import { useOasConfig } from "./context.js";
12
+ import { GeneratedExampleSidecarBox } from "./GeneratedExampleSidecarBox.js";
13
13
  import type { OperationsFragmentFragment } from "./graphql/graphql.js";
14
14
  import { graphql } from "./graphql/index.js";
15
15
  import { PlaygroundDialogWrapper } from "./PlaygroundDialogWrapper.js";
@@ -51,11 +51,13 @@ export const Sidecar = ({
51
51
  selectedResponse,
52
52
  onSelectResponse,
53
53
  globalSelectedServer,
54
+ shouldLazyHighlight,
54
55
  }: {
55
56
  operation: OperationsFragmentFragment;
56
57
  selectedResponse?: string;
57
58
  onSelectResponse: (response: string) => void;
58
59
  globalSelectedServer?: string;
60
+ shouldLazyHighlight?: boolean;
59
61
  }) => {
60
62
  const { options } = useOasConfig();
61
63
  const auth = useAuthState();
@@ -65,13 +67,8 @@ export const Sidecar = ({
65
67
 
66
68
  const [searchParams, setSearchParams] = useSearchParams();
67
69
  const [, startTransition] = useTransition();
68
- const [selectedExample, setSelectedExample] = useState<unknown>();
69
-
70
- const selectedLang =
71
- searchParams.get("lang") ?? options?.examplesLanguage ?? "shell";
72
70
 
73
71
  const requestBodyContent = operation.requestBody?.content;
74
-
75
72
  const transformedRequestBodyContent =
76
73
  requestBodyContent && options?.transformExamples
77
74
  ? options.transformExamples({
@@ -83,6 +80,30 @@ export const Sidecar = ({
83
80
  })
84
81
  : requestBodyContent;
85
82
 
83
+ const [selectedRequestExample, setSelectedRequestExample] = useState<{
84
+ contentTypeIndex: number;
85
+ exampleIndex: number;
86
+ }>({
87
+ contentTypeIndex: 0,
88
+ exampleIndex: 0,
89
+ });
90
+
91
+ const selectedContent = transformedRequestBodyContent?.at(
92
+ selectedRequestExample.contentTypeIndex,
93
+ );
94
+ const currentExample = selectedContent?.examples?.at(
95
+ selectedRequestExample.exampleIndex,
96
+ );
97
+
98
+ const selectedLang =
99
+ searchParams.get("lang") ?? options?.examplesLanguage ?? "shell";
100
+
101
+ const currentExampleCode = currentExample
102
+ ? (currentExample?.value ?? currentExample)
103
+ : selectedContent?.schema
104
+ ? generateSchemaExample(selectedContent?.schema)
105
+ : undefined;
106
+
86
107
  const path = (
87
108
  <PathRenderer
88
109
  path={operation.path}
@@ -104,34 +125,21 @@ export const Sidecar = ({
104
125
  const selectedServer =
105
126
  globalSelectedServer || operation.servers.at(0)?.url || "";
106
127
 
107
- const code = useMemo(() => {
108
- const exampleBody =
109
- selectedExample ??
110
- (transformedRequestBodyContent?.[0]?.schema
111
- ? generateSchemaExample(
112
- transformedRequestBodyContent[0].schema as SchemaObject,
113
- )
114
- : undefined);
115
-
128
+ const httpSnippetCode = useMemo<string | undefined>(() => {
116
129
  const snippet = createHttpSnippet({
117
130
  operation,
118
131
  selectedServer,
119
- exampleBody: exampleBody
132
+ exampleBody: currentExampleCode
120
133
  ? {
121
134
  mimeType: "application/json",
122
- text: JSON.stringify(exampleBody, null, 2),
135
+ text: JSON.stringify(currentExampleCode, null, 2),
123
136
  }
124
137
  : { mimeType: "application/json" },
125
138
  });
126
139
 
127
140
  return getConverted(snippet, selectedLang);
128
- }, [
129
- selectedExample,
130
- transformedRequestBodyContent,
131
- operation,
132
- selectedServer,
133
- selectedLang,
134
- ]);
141
+ }, [operation, selectedServer, selectedLang, currentExampleCode]);
142
+
135
143
  const [ref, isOnScreen] = useOnScreen({ rootMargin: "200px 0px 200px 0px" });
136
144
 
137
145
  const showPlayground =
@@ -150,7 +158,7 @@ export const Sidecar = ({
150
158
  >
151
159
  <SidecarBox.Root>
152
160
  <SidecarBox.Head className="flex justify-between items-center flex-nowrap py-2.5 gap-2 text-xs">
153
- <span className="font-mono break-words leading-6">
161
+ <span className="font-mono wrap-break-word leading-6">
154
162
  <span className={cn("font-semibold", methodTextColor)}>
155
163
  {operation.method.toUpperCase()}
156
164
  </span>
@@ -165,47 +173,60 @@ export const Sidecar = ({
165
173
  />
166
174
  )}
167
175
  </SidecarBox.Head>
168
- {isOnScreen && (
169
- <>
170
- <SidecarBox.Body className="p-0">
171
- <CollapsibleCode>
172
- <SyntaxHighlight
173
- embedded
174
- language={selectedLang}
175
- noBackground
176
- className="[--scrollbar-color:gray] rounded-none text-xs max-h-[500px]"
177
- // biome-ignore lint/style/noNonNullAssertion: code is guaranteed to be defined
178
- code={code!}
179
- />
180
- </CollapsibleCode>
181
- </SidecarBox.Body>
182
- <SidecarBox.Footer className="flex items-center text-xs gap-2 justify-end py-2.5">
183
- <span>Show example in</span>
184
- <SimpleSelect
185
- className="self-start max-w-[150px]"
186
- value={selectedLang}
187
- onChange={(e) => {
188
- startTransition(() => {
189
- setSearchParams((prev) => {
190
- prev.set("lang", e.target.value);
191
- return prev;
192
- });
193
- });
194
- }}
195
- options={EXAMPLE_LANGUAGES}
196
- />
197
- </SidecarBox.Footer>
198
- </>
199
- )}
176
+ <SidecarBox.Body className="p-0">
177
+ {shouldLazyHighlight && !isOnScreen ? (
178
+ <NonHighlightedCode code={httpSnippetCode ?? ""} />
179
+ ) : (
180
+ <SyntaxHighlight
181
+ embedded
182
+ language={selectedLang}
183
+ className="[--scrollbar-color:gray] rounded-none text-xs max-h-[200px]"
184
+ // biome-ignore lint/style/noNonNullAssertion: code is guaranteed to be defined
185
+ code={httpSnippetCode!}
186
+ />
187
+ )}
188
+ </SidecarBox.Body>
189
+ <SidecarBox.Footer className="flex items-center text-xs gap-2 justify-end py-2.5">
190
+ <span>Show example in</span>
191
+ <SimpleSelect
192
+ className="self-start max-w-[150px]"
193
+ value={selectedLang}
194
+ onChange={(e) => {
195
+ startTransition(() => {
196
+ setSearchParams((prev) => {
197
+ prev.set("lang", e.target.value);
198
+ return prev;
199
+ });
200
+ });
201
+ }}
202
+ options={EXAMPLE_LANGUAGES}
203
+ />
204
+ </SidecarBox.Footer>
200
205
  </SidecarBox.Root>
201
- {isOnScreen && transformedRequestBodyContent && (
206
+
207
+ {transformedRequestBodyContent && currentExample ? (
202
208
  <RequestBodySidecarBox
203
209
  content={transformedRequestBodyContent}
204
- onExampleChange={setSelectedExample}
210
+ onExampleChange={(selected) => {
211
+ setSelectedRequestExample(selected);
212
+ }}
213
+ selectedContentIndex={selectedRequestExample.contentTypeIndex}
214
+ selectedExampleIndex={selectedRequestExample.exampleIndex}
215
+ isOnScreen={isOnScreen}
216
+ shouldLazyHighlight={shouldLazyHighlight}
205
217
  />
206
- )}
207
- {isOnScreen && operation.responses.length > 0 && (
218
+ ) : transformedRequestBodyContent && currentExampleCode ? (
219
+ <GeneratedExampleSidecarBox
220
+ isOnScreen={isOnScreen}
221
+ shouldLazyHighlight={shouldLazyHighlight}
222
+ code={JSON.stringify(currentExampleCode, null, 2)}
223
+ />
224
+ ) : null}
225
+
226
+ {operation.responses.length > 0 && (
208
227
  <ResponsesSidecarBox
228
+ isOnScreen={isOnScreen}
229
+ shouldLazyHighlight={shouldLazyHighlight}
209
230
  selectedResponse={selectedResponse}
210
231
  onSelectResponse={onSelectResponse}
211
232
  responses={operation.responses.map((response) => ({