zudoku 0.26.1 → 0.28.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 (264) hide show
  1. package/dist/app/main.d.ts +1 -1
  2. package/dist/app/main.js +19 -7
  3. package/dist/app/main.js.map +1 -1
  4. package/dist/config/loader.js +1 -1
  5. package/dist/config/loader.js.map +1 -1
  6. package/dist/config/validators/InputSidebarSchema.d.ts +2 -2
  7. package/dist/config/validators/common.d.ts +67 -0
  8. package/dist/config/validators/common.js +5 -0
  9. package/dist/config/validators/common.js.map +1 -1
  10. package/dist/config/validators/validate.d.ts +29 -0
  11. package/dist/lib/components/AnchorLink.js +5 -2
  12. package/dist/lib/components/AnchorLink.js.map +1 -1
  13. package/dist/lib/components/Header.js +1 -1
  14. package/dist/lib/components/Header.js.map +1 -1
  15. package/dist/lib/components/Heading.d.ts +1 -1
  16. package/dist/lib/components/Markdown.d.ts +2 -2
  17. package/dist/lib/components/Markdown.js +3 -1
  18. package/dist/lib/components/Markdown.js.map +1 -1
  19. package/dist/lib/components/StatusPage.d.ts +7 -0
  20. package/dist/lib/components/StatusPage.js +71 -0
  21. package/dist/lib/components/StatusPage.js.map +1 -0
  22. package/dist/lib/components/SyntaxHighlight.d.ts +2 -1
  23. package/dist/lib/components/SyntaxHighlight.js +2 -2
  24. package/dist/lib/components/SyntaxHighlight.js.map +1 -1
  25. package/dist/lib/components/ThemeSwitch.js +4 -4
  26. package/dist/lib/components/ThemeSwitch.js.map +1 -1
  27. package/dist/lib/components/cache.d.ts +6 -0
  28. package/dist/lib/components/cache.js +13 -0
  29. package/dist/lib/components/cache.js.map +1 -0
  30. package/dist/lib/components/context/ViewportAnchorContext.js +16 -4
  31. package/dist/lib/components/context/ViewportAnchorContext.js.map +1 -1
  32. package/dist/lib/components/context/ZudokuContext.js +2 -1
  33. package/dist/lib/components/context/ZudokuContext.js.map +1 -1
  34. package/dist/lib/components/index.d.ts +9 -2
  35. package/dist/lib/components/index.js +3 -0
  36. package/dist/lib/components/index.js.map +1 -1
  37. package/dist/lib/components/navigation/SidebarCategory.js +3 -3
  38. package/dist/lib/components/navigation/SidebarCategory.js.map +1 -1
  39. package/dist/lib/core/RouteGuard.d.ts +1 -0
  40. package/dist/lib/core/RouteGuard.js +28 -0
  41. package/dist/lib/core/RouteGuard.js.map +1 -0
  42. package/dist/lib/core/ZudokuContext.d.ts +4 -2
  43. package/dist/lib/core/ZudokuContext.js +9 -7
  44. package/dist/lib/core/ZudokuContext.js.map +1 -1
  45. package/dist/lib/oas/graphql/circular.d.ts +3 -0
  46. package/dist/lib/oas/graphql/circular.js +27 -0
  47. package/dist/lib/oas/graphql/circular.js.map +1 -0
  48. package/dist/lib/oas/graphql/index.d.ts +1 -0
  49. package/dist/lib/oas/graphql/index.js +46 -29
  50. package/dist/lib/oas/graphql/index.js.map +1 -1
  51. package/dist/lib/oas/parser/dereference/index.d.ts +0 -1
  52. package/dist/lib/oas/parser/dereference/index.js +1 -1
  53. package/dist/lib/oas/parser/dereference/index.js.map +1 -1
  54. package/dist/lib/plugins/openapi/Endpoint.js +2 -2
  55. package/dist/lib/plugins/openapi/Endpoint.js.map +1 -1
  56. package/dist/lib/plugins/openapi/{Route.d.ts → OpenApiRoute.d.ts} +2 -1
  57. package/dist/lib/plugins/openapi/{Route.js → OpenApiRoute.js} +3 -4
  58. package/dist/lib/plugins/openapi/OpenApiRoute.js.map +1 -0
  59. package/dist/lib/plugins/openapi/OperationList.d.ts +4 -1
  60. package/dist/lib/plugins/openapi/OperationList.js +20 -14
  61. package/dist/lib/plugins/openapi/OperationList.js.map +1 -1
  62. package/dist/lib/plugins/openapi/OperationListItem.js +1 -1
  63. package/dist/lib/plugins/openapi/OperationListItem.js.map +1 -1
  64. package/dist/lib/plugins/openapi/ParameterListItem.js +1 -1
  65. package/dist/lib/plugins/openapi/ParameterListItem.js.map +1 -1
  66. package/dist/lib/plugins/openapi/RequestBodySidecarBox.d.ts +1 -1
  67. package/dist/lib/plugins/openapi/RequestBodySidecarBox.js +2 -0
  68. package/dist/lib/plugins/openapi/RequestBodySidecarBox.js.map +1 -1
  69. package/dist/lib/plugins/openapi/Sidecar.js +3 -3
  70. package/dist/lib/plugins/openapi/Sidecar.js.map +1 -1
  71. package/dist/lib/plugins/openapi/SidecarExamples.js +17 -14
  72. package/dist/lib/plugins/openapi/SidecarExamples.js.map +1 -1
  73. package/dist/lib/plugins/openapi/graphql/gql.d.ts +6 -2
  74. package/dist/lib/plugins/openapi/graphql/gql.js +3 -2
  75. package/dist/lib/plugins/openapi/graphql/gql.js.map +1 -1
  76. package/dist/lib/plugins/openapi/graphql/graphql.d.ts +47 -26
  77. package/dist/lib/plugins/openapi/graphql/graphql.js +20 -16
  78. package/dist/lib/plugins/openapi/graphql/graphql.js.map +1 -1
  79. package/dist/lib/plugins/openapi/index.js +101 -65
  80. package/dist/lib/plugins/openapi/index.js.map +1 -1
  81. package/dist/lib/plugins/openapi/interfaces.d.ts +8 -2
  82. package/dist/lib/plugins/openapi/playground/ExamplesDropdown.js +5 -5
  83. package/dist/lib/plugins/openapi/playground/ExamplesDropdown.js.map +1 -1
  84. package/dist/lib/plugins/openapi/playground/Headers.js +17 -16
  85. package/dist/lib/plugins/openapi/playground/Headers.js.map +1 -1
  86. package/dist/lib/plugins/openapi/playground/ParamsGrid.d.ts +5 -0
  87. package/dist/lib/plugins/openapi/playground/ParamsGrid.js +4 -0
  88. package/dist/lib/plugins/openapi/playground/ParamsGrid.js.map +1 -0
  89. package/dist/lib/plugins/openapi/playground/PathParams.js +4 -12
  90. package/dist/lib/plugins/openapi/playground/PathParams.js.map +1 -1
  91. package/dist/lib/plugins/openapi/playground/Playground.d.ts +13 -0
  92. package/dist/lib/plugins/openapi/playground/Playground.js +19 -31
  93. package/dist/lib/plugins/openapi/playground/Playground.js.map +1 -1
  94. package/dist/lib/plugins/openapi/playground/PlaygroundDialog.js +1 -1
  95. package/dist/lib/plugins/openapi/playground/PlaygroundDialog.js.map +1 -1
  96. package/dist/lib/plugins/openapi/playground/QueryParams.js +4 -3
  97. package/dist/lib/plugins/openapi/playground/QueryParams.js.map +1 -1
  98. package/dist/lib/plugins/openapi/playground/SubmitButton.d.ts +7 -0
  99. package/dist/lib/plugins/openapi/playground/SubmitButton.js +22 -0
  100. package/dist/lib/plugins/openapi/playground/SubmitButton.js.map +1 -0
  101. package/dist/lib/plugins/openapi/playground/result-panel/RequestTab.d.ts +7 -0
  102. package/dist/lib/plugins/openapi/playground/result-panel/RequestTab.js +11 -0
  103. package/dist/lib/plugins/openapi/playground/result-panel/RequestTab.js.map +1 -0
  104. package/dist/lib/plugins/openapi/playground/result-panel/ResponseTab.d.ts +8 -0
  105. package/dist/lib/plugins/openapi/playground/result-panel/ResponseTab.js +95 -0
  106. package/dist/lib/plugins/openapi/playground/result-panel/ResponseTab.js.map +1 -0
  107. package/dist/lib/plugins/openapi/playground/result-panel/ResultPanel.d.ts +7 -0
  108. package/dist/lib/plugins/openapi/playground/result-panel/ResultPanel.js +16 -0
  109. package/dist/lib/plugins/openapi/playground/result-panel/ResultPanel.js.map +1 -0
  110. package/dist/lib/plugins/openapi/playground/result-panel/convertToTypes.d.ts +10 -0
  111. package/dist/lib/plugins/openapi/playground/result-panel/convertToTypes.js +32 -0
  112. package/dist/lib/plugins/openapi/playground/result-panel/convertToTypes.js.map +1 -0
  113. package/dist/lib/plugins/openapi/playground/result-panel/convertToTypes.test.d.ts +1 -0
  114. package/dist/lib/plugins/openapi/playground/result-panel/convertToTypes.test.js +56 -0
  115. package/dist/lib/plugins/openapi/playground/result-panel/convertToTypes.test.js.map +1 -0
  116. package/dist/lib/plugins/openapi/schema/SchemaComponents.js +1 -1
  117. package/dist/lib/plugins/openapi/schema/SchemaComponents.js.map +1 -1
  118. package/dist/lib/ui/Command.js +1 -1
  119. package/dist/lib/ui/Command.js.map +1 -1
  120. package/dist/lib/ui/Select.js +2 -2
  121. package/dist/lib/ui/Select.js.map +1 -1
  122. package/dist/lib/util/MdxComponents.js +2 -2
  123. package/dist/lib/util/MdxComponents.js.map +1 -1
  124. package/dist/lib/util/joinUrl.js +1 -1
  125. package/dist/lib/util/joinUrl.js.map +1 -1
  126. package/dist/lib/util/joinUrl.test.d.ts +1 -0
  127. package/dist/lib/util/joinUrl.test.js +43 -0
  128. package/dist/lib/util/joinUrl.test.js.map +1 -0
  129. package/dist/lib/util/useScrollToAnchor.d.ts +1 -0
  130. package/dist/lib/util/useScrollToAnchor.js +26 -15
  131. package/dist/lib/util/useScrollToAnchor.js.map +1 -1
  132. package/dist/vite/plugin-api.js +15 -3
  133. package/dist/vite/plugin-api.js.map +1 -1
  134. package/dist/vite/prerender.js +1 -0
  135. package/dist/vite/prerender.js.map +1 -1
  136. package/dist/zuplo/enrich-with-zuplo.js +1 -1
  137. package/dist/zuplo/enrich-with-zuplo.js.map +1 -1
  138. package/dist/zuplo/with-zuplo.d.ts +2 -1
  139. package/dist/zuplo/with-zuplo.js +3 -1
  140. package/dist/zuplo/with-zuplo.js.map +1 -1
  141. package/lib/{AuthenticationPlugin-C9SwOxkc.js → AuthenticationPlugin-Du8cLBSr.js} +3 -3
  142. package/lib/{AuthenticationPlugin-C9SwOxkc.js.map → AuthenticationPlugin-Du8cLBSr.js.map} +1 -1
  143. package/lib/{Markdown-DFN6p0J-.js → Markdown-Cyrx_JrO.js} +1195 -1185
  144. package/lib/{Markdown-DFN6p0J-.js.map → Markdown-Cyrx_JrO.js.map} +1 -1
  145. package/lib/{MdxPage-D9c4z09Q.js → MdxPage-DewragjB.js} +6 -6
  146. package/lib/{MdxPage-D9c4z09Q.js.map → MdxPage-DewragjB.js.map} +1 -1
  147. package/lib/OpenApiRoute-UrC_t0e5.js +36 -0
  148. package/lib/OpenApiRoute-UrC_t0e5.js.map +1 -0
  149. package/lib/{OperationList-DGJWDx1G.js → OperationList-D_ejrepA.js} +1970 -1957
  150. package/lib/OperationList-D_ejrepA.js.map +1 -0
  151. package/lib/{Select-D3O7wISy.js → Select-CnCZ4WhS.js} +61 -61
  152. package/lib/Select-CnCZ4WhS.js.map +1 -0
  153. package/lib/{SlotletProvider-_3zzX_g_.js → SlotletProvider-mQiPDQIH.js} +4 -4
  154. package/lib/{SlotletProvider-_3zzX_g_.js.map → SlotletProvider-mQiPDQIH.js.map} +1 -1
  155. package/lib/{SyntaxHighlight-CJCSPG1F.js → SyntaxHighlight-B0L4SC_N.js} +309 -298
  156. package/lib/SyntaxHighlight-B0L4SC_N.js.map +1 -0
  157. package/lib/{ZudokuContext-DeQZEp-x.js → ZudokuContext-BTUJPpQl.js} +257 -246
  158. package/lib/ZudokuContext-BTUJPpQl.js.map +1 -0
  159. package/lib/{chunk-SYFQ2XB5-BF5IDYrB.js → chunk-SYFQ2XB5-BPvC-soB.js} +5 -5
  160. package/lib/{chunk-SYFQ2XB5-BF5IDYrB.js.map → chunk-SYFQ2XB5-BPvC-soB.js.map} +1 -1
  161. package/lib/circular-Dgpd6AN-.js +15397 -0
  162. package/lib/circular-Dgpd6AN-.js.map +1 -0
  163. package/lib/{createServer-BcaswoFO.js → createServer-BydbkTsd.js} +3487 -5601
  164. package/lib/createServer-BydbkTsd.js.map +1 -0
  165. package/lib/{hook-BRQEDRbn.js → hook-FT3SJLe_.js} +2 -2
  166. package/lib/{hook-BRQEDRbn.js.map → hook-FT3SJLe_.js.map} +1 -1
  167. package/lib/{index-LNp6rxyU.js → index-CjJS0l4l.js} +2 -2
  168. package/lib/{index-LNp6rxyU.js.map → index-CjJS0l4l.js.map} +1 -1
  169. package/lib/index-DGugJOLc.js +1974 -0
  170. package/lib/index-DGugJOLc.js.map +1 -0
  171. package/lib/{joinUrl-BTy9bvoK.js → joinUrl-nLx9pD-Z.js} +2 -2
  172. package/lib/joinUrl-nLx9pD-Z.js.map +1 -0
  173. package/lib/ui/Command.js +27 -27
  174. package/lib/ui/Command.js.map +1 -1
  175. package/lib/ui/Select.js +2 -2
  176. package/lib/ui/Select.js.map +1 -1
  177. package/lib/{useExposedProps-CetwhZpP.js → useExposedProps-BLKFBylA.js} +2 -2
  178. package/lib/{useExposedProps-CetwhZpP.js.map → useExposedProps-BLKFBylA.js.map} +1 -1
  179. package/lib/useScrollToAnchor-eRM9tVvD.js +289 -0
  180. package/lib/useScrollToAnchor-eRM9tVvD.js.map +1 -0
  181. package/lib/zudoku.auth-clerk.js +1 -1
  182. package/lib/zudoku.auth-openid.js +4 -4
  183. package/lib/zudoku.components.js +740 -979
  184. package/lib/zudoku.components.js.map +1 -1
  185. package/lib/zudoku.plugin-api-catalog.js +4 -4
  186. package/lib/zudoku.plugin-api-keys.js +5 -5
  187. package/lib/zudoku.plugin-custom-pages.js +2 -2
  188. package/lib/zudoku.plugin-markdown.js +1 -1
  189. package/lib/zudoku.plugin-openapi.js +6 -5
  190. package/lib/zudoku.plugin-openapi.js.map +1 -1
  191. package/lib/zudoku.plugin-redirect.js +1 -1
  192. package/package.json +2 -2
  193. package/src/app/main.tsx +26 -7
  194. package/src/lib/components/AnchorLink.tsx +5 -2
  195. package/src/lib/components/Header.tsx +1 -1
  196. package/src/lib/components/Markdown.tsx +14 -15
  197. package/src/lib/components/StatusPage.tsx +91 -0
  198. package/src/lib/components/SyntaxHighlight.tsx +14 -0
  199. package/src/lib/components/ThemeSwitch.tsx +14 -15
  200. package/src/lib/components/cache.ts +15 -0
  201. package/src/lib/components/context/ViewportAnchorContext.tsx +20 -6
  202. package/src/lib/components/context/ZudokuContext.ts +3 -1
  203. package/src/lib/components/index.ts +7 -0
  204. package/src/lib/components/navigation/SidebarCategory.tsx +3 -2
  205. package/src/lib/core/RouteGuard.tsx +35 -0
  206. package/src/lib/core/ZudokuContext.ts +9 -8
  207. package/src/lib/oas/graphql/circular.ts +29 -0
  208. package/src/lib/oas/graphql/index.ts +72 -44
  209. package/src/lib/oas/parser/dereference/index.ts +1 -2
  210. package/src/lib/plugins/openapi/Endpoint.tsx +2 -2
  211. package/src/lib/plugins/openapi/{Route.tsx → OpenApiRoute.tsx} +3 -3
  212. package/src/lib/plugins/openapi/OperationList.tsx +34 -12
  213. package/src/lib/plugins/openapi/OperationListItem.tsx +0 -2
  214. package/src/lib/plugins/openapi/ParameterListItem.tsx +1 -0
  215. package/src/lib/plugins/openapi/RequestBodySidecarBox.tsx +2 -0
  216. package/src/lib/plugins/openapi/Sidecar.tsx +4 -3
  217. package/src/lib/plugins/openapi/SidecarExamples.tsx +24 -24
  218. package/src/lib/plugins/openapi/graphql/gql.ts +12 -4
  219. package/src/lib/plugins/openapi/graphql/graphql.ts +66 -43
  220. package/src/lib/plugins/openapi/index.tsx +134 -82
  221. package/src/lib/plugins/openapi/interfaces.ts +11 -2
  222. package/src/lib/plugins/openapi/playground/ExamplesDropdown.tsx +30 -27
  223. package/src/lib/plugins/openapi/playground/Headers.tsx +65 -65
  224. package/src/lib/plugins/openapi/playground/ParamsGrid.tsx +8 -0
  225. package/src/lib/plugins/openapi/playground/PathParams.tsx +34 -74
  226. package/src/lib/plugins/openapi/playground/Playground.tsx +64 -116
  227. package/src/lib/plugins/openapi/playground/PlaygroundDialog.tsx +1 -1
  228. package/src/lib/plugins/openapi/playground/QueryParams.tsx +46 -45
  229. package/src/lib/plugins/openapi/playground/SubmitButton.tsx +75 -0
  230. package/src/lib/plugins/openapi/playground/result-panel/RequestTab.tsx +73 -0
  231. package/src/lib/plugins/openapi/playground/result-panel/ResponseTab.tsx +210 -0
  232. package/src/lib/plugins/openapi/playground/result-panel/ResultPanel.tsx +101 -0
  233. package/src/lib/plugins/openapi/playground/result-panel/convertToTypes.test.ts +64 -0
  234. package/src/lib/plugins/openapi/playground/result-panel/convertToTypes.ts +36 -0
  235. package/src/lib/plugins/openapi/schema/SchemaComponents.tsx +1 -1
  236. package/src/lib/ui/Command.tsx +1 -1
  237. package/src/lib/ui/Select.tsx +1 -1
  238. package/src/lib/util/MdxComponents.tsx +2 -1
  239. package/src/lib/util/joinUrl.test.ts +62 -0
  240. package/src/lib/util/joinUrl.ts +1 -1
  241. package/src/lib/util/useScrollToAnchor.ts +32 -15
  242. package/dist/lib/plugins/openapi/Route.js.map +0 -1
  243. package/dist/lib/plugins/openapi/playground/ResponseTab.d.ts +0 -4
  244. package/dist/lib/plugins/openapi/playground/ResponseTab.js +0 -42
  245. package/dist/lib/plugins/openapi/playground/ResponseTab.js.map +0 -1
  246. package/lib/AnchorLink-bObQitZv.js +0 -34
  247. package/lib/AnchorLink-bObQitZv.js.map +0 -1
  248. package/lib/OperationList-DGJWDx1G.js.map +0 -1
  249. package/lib/Route-VdmEyOD0.js +0 -35
  250. package/lib/Route-VdmEyOD0.js.map +0 -1
  251. package/lib/Select-D3O7wISy.js.map +0 -1
  252. package/lib/StaggeredRender-DgsamH_G.js +0 -17
  253. package/lib/StaggeredRender-DgsamH_G.js.map +0 -1
  254. package/lib/SyntaxHighlight-CJCSPG1F.js.map +0 -1
  255. package/lib/ZudokuContext-DeQZEp-x.js.map +0 -1
  256. package/lib/createServer-BcaswoFO.js.map +0 -1
  257. package/lib/index-Bn6Lc9tq.js +0 -9
  258. package/lib/index-Bn6Lc9tq.js.map +0 -1
  259. package/lib/index-CXRrqOIl.js +0 -1750
  260. package/lib/index-CXRrqOIl.js.map +0 -1
  261. package/lib/index-TaRXY2w1.js +0 -43
  262. package/lib/index-TaRXY2w1.js.map +0 -1
  263. package/lib/joinUrl-BTy9bvoK.js.map +0 -1
  264. package/src/lib/plugins/openapi/playground/ResponseTab.tsx +0 -76
@@ -0,0 +1,29 @@
1
+ import { GraphQLJSON } from "graphql-type-json";
2
+ import { GraphQLScalarType } from "graphql/index.js";
3
+
4
+ export const CIRCULAR_REF = "$[Circular Reference]";
5
+ const handleCircularRefs = (obj: any, visited = new WeakSet()): any => {
6
+ if (obj === CIRCULAR_REF) return CIRCULAR_REF;
7
+ if (obj === null || typeof obj !== "object") return obj;
8
+
9
+ if (visited.has(obj)) return CIRCULAR_REF;
10
+
11
+ visited.add(obj);
12
+
13
+ if (Array.isArray(obj)) {
14
+ return obj.map((item) => handleCircularRefs(item, visited));
15
+ }
16
+
17
+ const result: Record<string, any> = {};
18
+ for (const [key, value] of Object.entries(obj)) {
19
+ result[key] = handleCircularRefs(value, visited);
20
+ }
21
+ return result;
22
+ };
23
+ export const GraphQLJSONSchema = new GraphQLScalarType({
24
+ ...GraphQLJSON,
25
+ name: "JSONSchema",
26
+ description: "OpenAPI schema scalar type that handles circular references",
27
+ serialize: (value: unknown) =>
28
+ GraphQLJSON.serialize(handleCircularRefs(value)),
29
+ });
@@ -1,16 +1,15 @@
1
1
  /* eslint-disable @typescript-eslint/no-explicit-any */
2
2
  import SchemaBuilder from "@pothos/core";
3
3
  import {
4
- slugifyWithCounter,
5
4
  type CountableSlugify,
5
+ slugifyWithCounter,
6
6
  } from "@sindresorhus/slugify";
7
7
  import { GraphQLJSON, GraphQLJSONObject } from "graphql-type-json";
8
8
  import { createYoga, type YogaServerOptions } from "graphql-yoga";
9
9
  import {
10
- HttpMethods,
11
- validate,
12
10
  type EncodingObject,
13
11
  type ExampleObject,
12
+ HttpMethods,
14
13
  type OpenAPIDocument,
15
14
  type OperationObject,
16
15
  type ParameterObject,
@@ -18,7 +17,9 @@ import {
18
17
  type SchemaObject,
19
18
  type ServerObject,
20
19
  type TagObject,
20
+ validate,
21
21
  } from "../parser/index.js";
22
+ import { GraphQLJSONSchema } from "./circular.js";
22
23
 
23
24
  export type {
24
25
  EncodingObject,
@@ -45,10 +46,7 @@ export const createOperationSlug = (
45
46
  ) => {
46
47
  const summary =
47
48
  (operation.summary ?? "") +
48
- (operation.operationId
49
- ? "-" +
50
- operation.operationId.slice(0, operation.summary ? Infinity : Infinity)
51
- : "");
49
+ (operation.operationId ? "-" + operation.operationId : "");
52
50
 
53
51
  return slugify(
54
52
  (tag ? tag + "-" : "") +
@@ -65,17 +63,30 @@ const builder = new SchemaBuilder<{
65
63
  Scalars: {
66
64
  JSON: any;
67
65
  JSONObject: any;
66
+ JSONSchema: any;
68
67
  };
69
68
  Context: {
70
69
  schema: OpenAPIDocument;
70
+ operations: GraphQLOperationObject[];
71
+ tags: TagObject[];
71
72
  schemaImports?: SchemaImports;
73
+ currentTag?: string;
74
+ slugify: CountableSlugify;
72
75
  };
73
76
  }>({});
74
77
 
78
+ type GraphQLOperationObject = OperationObject & {
79
+ path: string;
80
+ method: string;
81
+ slug?: string;
82
+ parentTag?: string;
83
+ };
84
+
75
85
  const JSONScalar = builder.addScalarType("JSON", GraphQLJSON);
76
86
  const JSONObjectScalar = builder.addScalarType("JSONObject", GraphQLJSONObject);
87
+ const JSONSchemaScalar = builder.addScalarType("JSONSchema", GraphQLJSONSchema);
77
88
 
78
- const getAllTags = (schema: OpenAPIDocument): TagObject[] => {
89
+ export const getAllTags = (schema: OpenAPIDocument): TagObject[] => {
79
90
  const tags = schema.tags ?? [];
80
91
 
81
92
  // Extract tags from operations
@@ -94,10 +105,10 @@ const getAllTags = (schema: OpenAPIDocument): TagObject[] => {
94
105
  return [...tags, ...uniqueOperationTags.map((tag) => ({ name: tag }))];
95
106
  };
96
107
 
97
- const getAllOperations = (paths?: PathsObject, tag?: string) => {
98
- const slugify = slugifyWithCounter();
108
+ const getAllOperations = (paths?: PathsObject) => {
109
+ const start = performance.now();
99
110
 
100
- return Object.entries(paths ?? {}).flatMap(([path, value]) =>
111
+ const operations = Object.entries(paths ?? {}).flatMap(([path, value]) =>
101
112
  HttpMethods.flatMap((method) => {
102
113
  if (!value?.[method]) return [];
103
114
 
@@ -118,23 +129,17 @@ const getAllOperations = (paths?: PathsObject, tag?: string) => {
118
129
  ...operationParameters,
119
130
  ];
120
131
 
121
- const slugData = {
122
- summary: operation.summary,
123
- operationId: operation.operationId,
124
- path,
125
- method,
126
- };
127
-
128
132
  return {
129
133
  ...operation,
130
134
  method,
131
135
  path,
132
136
  parameters,
133
137
  tags: operation.tags ?? [],
134
- slug: createOperationSlug(slugify, slugData, tag),
135
138
  };
136
139
  }),
137
140
  );
141
+
142
+ return operations;
138
143
  };
139
144
 
140
145
  const SchemaTag = builder.objectRef<TagObject>("SchemaTag").implement({
@@ -144,15 +149,19 @@ const SchemaTag = builder.objectRef<TagObject>("SchemaTag").implement({
144
149
  operations: t.field({
145
150
  type: [OperationItem],
146
151
  resolve: (parent, _args, ctx) => {
147
- const rootTags = getAllTags(ctx.schema).map((tag) => tag.name);
148
-
149
- return getAllOperations(ctx.schema.paths, parent.name).filter((item) =>
150
- parent.name
151
- ? item.tags.includes(parent.name)
152
- : item.tags.length === 0 ||
153
- // If none of the tags are present in the root tags, then show them here
154
- item.tags.every((tag) => !rootTags.includes(tag)),
155
- );
152
+ const rootTags = ctx.tags.map((tag) => tag.name);
153
+ return ctx.operations
154
+ .filter((item) =>
155
+ parent.name
156
+ ? item.tags?.includes(parent.name)
157
+ : item.tags?.length === 0 ||
158
+ // If none of the tags are present in the root tags, then show them here
159
+ item.tags?.every((tag) => !rootTags.includes(tag)),
160
+ )
161
+ .map((item) => ({
162
+ ...item,
163
+ parentTag: parent.name,
164
+ }));
156
165
  },
157
166
  }),
158
167
  }),
@@ -238,7 +247,7 @@ const ParameterItem = builder
238
247
  })),
239
248
  nullable: true,
240
249
  }),
241
- schema: t.expose("schema", { type: JSONScalar, nullable: true }),
250
+ schema: t.expose("schema", { type: JSONSchemaScalar, nullable: true }),
242
251
  }),
243
252
  });
244
253
 
@@ -252,7 +261,7 @@ const MediaTypeItem = builder
252
261
  .implement({
253
262
  fields: (t) => ({
254
263
  mediaType: t.exposeString("mediaType"),
255
- schema: t.expose("schema", { type: JSONScalar, nullable: true }),
264
+ schema: t.expose("schema", { type: JSONSchemaScalar, nullable: true }),
256
265
  examples: t.expose("examples", { type: [ExampleItem], nullable: true }),
257
266
  encoding: t.expose("encoding", { type: [EncodingItem], nullable: true }),
258
267
  }),
@@ -300,12 +309,24 @@ const ResponseItem = builder
300
309
  });
301
310
 
302
311
  const OperationItem = builder
303
- .objectRef<
304
- OperationObject & { path: string; method: string; slug: string }
305
- >("OperationItem")
312
+ .objectRef<GraphQLOperationObject>("OperationItem")
306
313
  .implement({
307
314
  fields: (t) => ({
308
- slug: t.exposeString("slug"),
315
+ slug: t.field({
316
+ type: "String",
317
+ resolve: (parent, _, ctx) => {
318
+ const slugData = {
319
+ summary: parent.summary,
320
+ operationId: parent.operationId,
321
+ path: parent.path,
322
+ method: parent.method,
323
+ };
324
+
325
+ //TODO: fix parent tag parent.tags
326
+ return createOperationSlug(ctx.slugify, slugData, parent.parentTag);
327
+ },
328
+ }),
329
+
309
330
  path: t.exposeString("path"),
310
331
  method: t.exposeString("method"),
311
332
  operationId: t.exposeString("operationId", { nullable: true }),
@@ -414,8 +435,8 @@ const Schema = builder.objectRef<OpenAPIDocument>("Schema").implement({
414
435
  name: t.arg.string(),
415
436
  },
416
437
  type: [SchemaTag],
417
- resolve: (root, args) => {
418
- const tags = [...getAllTags(root), { name: "" }];
438
+ resolve: (root, args, ctx) => {
439
+ const tags = [...ctx.tags, { name: "" }];
419
440
  return args.name ? tags.filter((tag) => tag.name === args.name) : tags;
420
441
  },
421
442
  }),
@@ -426,15 +447,18 @@ const Schema = builder.objectRef<OpenAPIDocument>("Schema").implement({
426
447
  method: t.arg.string(),
427
448
  operationId: t.arg.string(),
428
449
  tag: t.arg.string(),
450
+ untagged: t.arg.boolean(),
429
451
  },
430
- resolve: (parent, args) =>
431
- getAllOperations(parent.paths).filter(
432
- (item) =>
433
- (!args.operationId || item.operationId === args.operationId) &&
434
- (!args.path || item.path === args.path) &&
435
- (!args.method || item.method === args.method) &&
436
- (!args.tag || item.tags.includes(args.tag)),
437
- ),
452
+ resolve: (parent, args, ctx) =>
453
+ ctx.operations.filter((op) => {
454
+ return (
455
+ (!args.operationId || op.operationId === args.operationId) &&
456
+ (!args.path || op.path === args.path) &&
457
+ (!args.method || op.method === args.method) &&
458
+ (!args.tag || op.tags?.some((tag) => args.tag?.includes(tag))) &&
459
+ (!args.untagged || (op.tags ?? []).length === 0)
460
+ );
461
+ }),
438
462
  }),
439
463
  }),
440
464
  });
@@ -467,6 +491,10 @@ builder.queryType({
467
491
  }
468
492
 
469
493
  ctx.schema = schema;
494
+ ctx.operations = getAllOperations(schema.paths);
495
+ ctx.slugify = slugifyWithCounter();
496
+ ctx.tags = getAllTags(schema);
497
+
470
498
  return schema;
471
499
  },
472
500
  }),
@@ -1,10 +1,9 @@
1
1
  import type { JSONSchema4, JSONSchema6 } from "json-schema";
2
+ import { CIRCULAR_REF } from "../../graphql/circular.js";
2
3
  import { resolveLocalRef } from "./resolveRef.js";
3
4
 
4
5
  export type JSONSchema = JSONSchema4 | JSONSchema6;
5
6
 
6
- export const CIRCULAR_REF = "$[Circular Reference]";
7
-
8
7
  type CustomResolver = (ref: string) => Promise<JSONSchema | undefined>;
9
8
 
10
9
  const cache = new Map<JSONSchema, JSONSchema>();
@@ -77,14 +77,14 @@ export const Endpoint = () => {
77
77
  setSelectedServer(e.target.value);
78
78
  })
79
79
  }
80
- value={selectedServer ?? result.data.schema.url}
80
+ value={selectedServer ?? servers.at(0)!.url}
81
81
  showChevrons={servers.length > 1}
82
82
  options={servers.map((server) => ({
83
83
  value: server.url,
84
84
  label: server.url,
85
85
  }))}
86
86
  />
87
- <CopyButton url={selectedServer ?? result.data.schema.url} />
87
+ <CopyButton url={selectedServer ?? servers.at(0)!.url} />
88
88
  </div>
89
89
  );
90
90
  };
@@ -1,4 +1,4 @@
1
- import { Outlet, useParams } from "react-router";
1
+ import { Outlet } from "react-router";
2
2
  import { joinPath } from "../../util/joinPath.js";
3
3
  import type { GraphQLClient } from "./client/GraphQLClient.js";
4
4
  import { GraphQLProvider } from "./client/GraphQLContext.js";
@@ -8,16 +8,16 @@ import { type OasPluginConfig } from "./interfaces.js";
8
8
  export const OpenApiRoute = ({
9
9
  basePath,
10
10
  versions,
11
+ version,
11
12
  config,
12
13
  client,
13
14
  }: {
14
15
  basePath: string;
16
+ version?: string;
15
17
  versions: string[];
16
18
  config: OasPluginConfig;
17
19
  client: GraphQLClient;
18
20
  }) => {
19
- const { version } = useParams<"version">();
20
-
21
21
  const input =
22
22
  config.type === "file"
23
23
  ? {
@@ -17,7 +17,6 @@ import { useApiIdentities } from "../../components/context/ZudokuContext.js";
17
17
  import { cn } from "../../util/cn.js";
18
18
  import { Endpoint } from "./Endpoint.js";
19
19
  import { OperationListItem } from "./OperationListItem.js";
20
- import StaggeredRender from "./StaggeredRender.js";
21
20
  import { useCreateQuery } from "./client/useCreateQuery.js";
22
21
  import { useOasConfig } from "./context.js";
23
22
  import { graphql } from "./graphql/index.js";
@@ -90,35 +89,51 @@ export const OperationsFragment = graphql(/* GraphQL */ `
90
89
  export type OperationListItemResult = ResultOf<typeof OperationsFragment>;
91
90
 
92
91
  const AllOperationsQuery = graphql(/* GraphQL */ `
93
- query AllOperations($input: JSON!, $type: SchemaType!) {
92
+ query AllOperations(
93
+ $input: JSON!
94
+ $type: SchemaType!
95
+ $tag: String
96
+ $untagged: Boolean
97
+ ) {
94
98
  schema(input: $input, type: $type) {
95
99
  description
96
100
  summary
97
101
  title
98
102
  url
99
103
  version
100
- tags {
104
+ tags(name: $tag) {
101
105
  name
102
106
  description
103
- operations {
104
- slug
105
- ...OperationsFragment
106
- }
107
+ }
108
+ operations(tag: $tag, untagged: $untagged) {
109
+ slug
110
+ ...OperationsFragment
107
111
  }
108
112
  }
109
113
  }
110
114
  `);
111
115
 
112
- export const OperationList = () => {
116
+ export const OperationList = ({
117
+ tag,
118
+ untagged,
119
+ }: {
120
+ tag?: string;
121
+ untagged?: boolean;
122
+ }) => {
113
123
  const { input, type, versions, version } = useOasConfig();
114
- const query = useCreateQuery(AllOperationsQuery, { input, type });
124
+ const query = useCreateQuery(AllOperationsQuery, {
125
+ input,
126
+ type,
127
+ tag,
128
+ untagged,
129
+ });
115
130
  const { selectedServer } = useSelectedServerStore();
116
131
  const result = useSuspenseQuery(query);
117
132
  const title = result.data.schema.title;
118
133
  const summary = result.data.schema.summary;
119
134
  const description = result.data.schema.description;
120
135
  const navigate = useNavigate();
121
-
136
+ const operations = result.data.schema.operations;
122
137
  // Prefetch for Playground
123
138
  useApiIdentities();
124
139
 
@@ -175,7 +190,14 @@ export const OperationList = () => {
175
190
  <div className="my-4 flex items-center justify-end gap-4">
176
191
  <Endpoint />
177
192
  </div>
178
- {result.data.schema.tags
193
+ {operations.map((fragment) => (
194
+ <OperationListItem
195
+ serverUrl={selectedServer ?? result.data.schema.url ?? ""}
196
+ key={fragment.slug}
197
+ operationFragment={fragment}
198
+ />
199
+ ))}
200
+ {/* {result.data.schema.tags
179
201
  .filter((tag) => tag.operations.length > 0)
180
202
  .map((tag) => (
181
203
  // px, -mx is so that `content-visibility` doesn't cut off overflown heading anchor links '#'
@@ -199,7 +221,7 @@ export const OperationList = () => {
199
221
  </StaggeredRender>
200
222
  </div>
201
223
  </div>
202
- ))}
224
+ ))} */}
203
225
  </div>
204
226
  );
205
227
  };
@@ -95,7 +95,6 @@ export const OperationListItem = ({
95
95
  level={3}
96
96
  className="capitalize"
97
97
  id={`${operation.slug}/request-body`}
98
- registerSidebarAnchor
99
98
  >
100
99
  Request Body
101
100
  </Heading>
@@ -108,7 +107,6 @@ export const OperationListItem = ({
108
107
  level={3}
109
108
  className="capitalize mt-8 pt-8 border-t"
110
109
  id={`${operation.slug}/responses`}
111
- registerSidebarAnchor
112
110
  >
113
111
  Responses
114
112
  </Heading>
@@ -54,6 +54,7 @@ export const ParameterListItem = ({
54
54
  </Badge>
55
55
  )}
56
56
  {parameter.required && <Badge variant="outline">required</Badge>}
57
+ {parameter.style === "form" && <Badge variant="secondary">form</Badge>}
57
58
  </div>
58
59
  {parameter.description && (
59
60
  <Markdown
@@ -8,6 +8,8 @@ export const RequestBodySidecarBox = ({
8
8
  content: Content;
9
9
  onExampleChange?: (example: unknown) => void;
10
10
  }) => {
11
+ if (content.length === 0) return null;
12
+
11
13
  return (
12
14
  <SidecarBox.Root>
13
15
  <SidecarBox.Head className="text-xs flex justify-between items-center">
@@ -99,7 +99,7 @@ export const Sidecar = ({
99
99
  selectedResponse?: string;
100
100
  onSelectResponse: (response: string) => void;
101
101
  }) => {
102
- const { input, type } = useOasConfig();
102
+ const { input, type, options } = useOasConfig();
103
103
  const query = useCreateQuery(GetServerQuery, { input, type });
104
104
  const result = useSuspenseQuery(query);
105
105
 
@@ -109,7 +109,8 @@ export const Sidecar = ({
109
109
  const [, startTransition] = useTransition();
110
110
  const [selectedExample, setSelectedExample] = useState<unknown>();
111
111
 
112
- const selectedLang = searchParams.get("lang") ?? "shell";
112
+ const selectedLang =
113
+ searchParams.get("lang") ?? options?.examplesDefaultLanguage ?? "shell";
113
114
 
114
115
  const requestBodyContent = operation.requestBody?.content;
115
116
 
@@ -195,7 +196,7 @@ export const Sidecar = ({
195
196
  </span>
196
197
  {isOnScreen && (
197
198
  <PlaygroundDialogWrapper
198
- server={result.data.schema.url}
199
+ server={result.data.schema.url ?? ""}
199
200
  servers={result.data.schema.servers.map((server) => server.url)}
200
201
  operation={operation}
201
202
  examples={requestBodyContent ?? undefined}
@@ -1,6 +1,6 @@
1
- import { useEffect, useState } from "react";
1
+ import { useEffect, useMemo, useState } from "react";
2
2
  import { SyntaxHighlight } from "../../components/SyntaxHighlight.js";
3
- import { type SchemaObject } from "../../oas/graphql/index.js";
3
+ import { SchemaObject } from "../../oas/parser/index.js";
4
4
  import { CollapsibleCode } from "./CollapsibleCode.js";
5
5
  import type { OperationListItemResult } from "./OperationList.js";
6
6
  import * as SidecarBox from "./SidecarBox.js";
@@ -57,27 +57,27 @@ export const SidecarExamples = ({
57
57
  const examples = effectiveContent?.examples ?? [];
58
58
  const selectedExample = examples[selectedExampleIndex];
59
59
 
60
- let exampleValue = undefined;
61
- if (selectedExample) {
62
- // If it's a wrapped example with a value field, use that
63
- exampleValue =
64
- "value" in selectedExample ? selectedExample.value : selectedExample;
65
- } else if (effectiveContent?.schema) {
66
- // No example provided, generate one from schema
67
- exampleValue = generateSchemaExample(
68
- effectiveContent.schema as SchemaObject,
69
- );
70
- }
60
+ const exampleValue = useMemo(() => {
61
+ if (selectedExample) {
62
+ // If it's a wrapped example with a value field, use that
63
+ return "value" in selectedExample
64
+ ? selectedExample.value
65
+ : selectedExample;
66
+ } else if (effectiveContent?.schema) {
67
+ // No example provided, generate one from schema
68
+ return generateSchemaExample(effectiveContent.schema as SchemaObject);
69
+ }
70
+ }, [selectedExample, effectiveContent?.schema]);
71
71
 
72
72
  useEffect(() => {
73
+ if (!exampleValue) return;
74
+
73
75
  onExampleChange?.(exampleValue);
74
76
  }, [exampleValue, onExampleChange]);
75
77
 
76
78
  const formattedExample = formatForDisplay(exampleValue);
77
79
  const language = getLanguage(effectiveContent?.mediaType);
78
80
 
79
- const hasContent = examples.length > 0 || content.length > 0;
80
-
81
81
  return (
82
82
  <>
83
83
  <SidecarBox.Body className="p-0">
@@ -109,13 +109,13 @@ export const SidecarExamples = ({
109
109
  </div>
110
110
  )}
111
111
  </SidecarBox.Body>
112
- {hasContent && (
113
- <SidecarBox.Footer className="text-xs p-0">
114
- {description && (
115
- <div className="text-muted-foreground text-xs border-b px-3 py-2">
116
- {description}
117
- </div>
118
- )}
112
+ <SidecarBox.Footer className="text-xs p-0 divide-y divide-border">
113
+ {description && (
114
+ <div className="text-muted-foreground text-xs px-3 py-2">
115
+ {description}
116
+ </div>
117
+ )}
118
+ {(examples.length !== 0 || content.length !== 0) && (
119
119
  <div className="flex items-center gap-2 justify-between min-w-0 px-3 py-2">
120
120
  <div className="flex items-center gap-2 min-w-0">
121
121
  {content.length > 1 ? (
@@ -156,8 +156,8 @@ export const SidecarExamples = ({
156
156
  </div>
157
157
  )}
158
158
  </div>
159
- </SidecarBox.Footer>
160
- )}
159
+ )}
160
+ </SidecarBox.Footer>
161
161
  </>
162
162
  );
163
163
  };
@@ -17,12 +17,14 @@ const documents = {
17
17
  types.ServersQueryDocument,
18
18
  "\n fragment OperationsFragment on OperationItem {\n slug\n summary\n method\n description\n operationId\n contentTypes\n path\n parameters {\n name\n in\n description\n required\n schema\n style\n examples {\n name\n description\n externalValue\n value\n summary\n }\n }\n requestBody {\n content {\n mediaType\n encoding {\n name\n }\n examples {\n name\n description\n externalValue\n value\n summary\n }\n schema\n }\n description\n required\n }\n responses {\n statusCode\n links\n description\n content {\n examples {\n name\n description\n externalValue\n value\n summary\n }\n mediaType\n encoding {\n name\n }\n schema\n }\n }\n }\n":
19
19
  types.OperationsFragmentFragmentDoc,
20
- "\n query AllOperations($input: JSON!, $type: SchemaType!) {\n schema(input: $input, type: $type) {\n description\n summary\n title\n url\n version\n tags {\n name\n description\n operations {\n slug\n ...OperationsFragment\n }\n }\n }\n }\n":
20
+ "\n query AllOperations(\n $input: JSON!\n $type: SchemaType!\n $tag: String\n $untagged: Boolean\n ) {\n schema(input: $input, type: $type) {\n description\n summary\n title\n url\n version\n tags(name: $tag) {\n name\n description\n }\n operations(tag: $tag, untagged: $untagged) {\n slug\n ...OperationsFragment\n }\n }\n }\n":
21
21
  types.AllOperationsDocument,
22
22
  "\n query getServerQuery($input: JSON!, $type: SchemaType!) {\n schema(input: $input, type: $type) {\n url\n servers {\n url\n }\n }\n }\n":
23
23
  types.GetServerQueryDocument,
24
- "\n query GetCategories($input: JSON!, $type: SchemaType!) {\n schema(input: $input, type: $type) {\n url\n tags {\n __typename\n name\n operations {\n __typename\n slug\n deprecated\n method\n summary\n operationId\n path\n }\n }\n }\n }\n":
24
+ "\n query GetCategories($input: JSON!, $type: SchemaType!) {\n schema(input: $input, type: $type) {\n url\n tags {\n name\n }\n }\n }\n":
25
25
  types.GetCategoriesDocument,
26
+ "\n query GetOperations(\n $input: JSON!\n $type: SchemaType!\n $tag: String\n $untagged: Boolean\n ) {\n schema(input: $input, type: $type) {\n operations(tag: $tag, untagged: $untagged) {\n slug\n deprecated\n method\n summary\n operationId\n path\n }\n }\n }\n":
27
+ types.GetOperationsDocument,
26
28
  };
27
29
 
28
30
  /**
@@ -41,7 +43,7 @@ export function graphql(
41
43
  * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
42
44
  */
43
45
  export function graphql(
44
- source: "\n query AllOperations($input: JSON!, $type: SchemaType!) {\n schema(input: $input, type: $type) {\n description\n summary\n title\n url\n version\n tags {\n name\n description\n operations {\n slug\n ...OperationsFragment\n }\n }\n }\n }\n",
46
+ source: "\n query AllOperations(\n $input: JSON!\n $type: SchemaType!\n $tag: String\n $untagged: Boolean\n ) {\n schema(input: $input, type: $type) {\n description\n summary\n title\n url\n version\n tags(name: $tag) {\n name\n description\n }\n operations(tag: $tag, untagged: $untagged) {\n slug\n ...OperationsFragment\n }\n }\n }\n",
45
47
  ): typeof import("./graphql.js").AllOperationsDocument;
46
48
  /**
47
49
  * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
@@ -53,8 +55,14 @@ export function graphql(
53
55
  * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
54
56
  */
55
57
  export function graphql(
56
- source: "\n query GetCategories($input: JSON!, $type: SchemaType!) {\n schema(input: $input, type: $type) {\n url\n tags {\n __typename\n name\n operations {\n __typename\n slug\n deprecated\n method\n summary\n operationId\n path\n }\n }\n }\n }\n",
58
+ source: "\n query GetCategories($input: JSON!, $type: SchemaType!) {\n schema(input: $input, type: $type) {\n url\n tags {\n name\n }\n }\n }\n",
57
59
  ): typeof import("./graphql.js").GetCategoriesDocument;
60
+ /**
61
+ * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
62
+ */
63
+ export function graphql(
64
+ source: "\n query GetOperations(\n $input: JSON!\n $type: SchemaType!\n $tag: String\n $untagged: Boolean\n ) {\n schema(input: $input, type: $type) {\n operations(tag: $tag, untagged: $untagged) {\n slug\n deprecated\n method\n summary\n operationId\n path\n }\n }\n }\n",
65
+ ): typeof import("./graphql.js").GetOperationsDocument;
58
66
 
59
67
  export function graphql(source: string) {
60
68
  return (documents as any)[source] ?? {};