zudoku 0.38.0 → 0.39.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (269) hide show
  1. package/dist/app/entry.server.d.ts +5 -4
  2. package/dist/app/entry.server.js +2 -2
  3. package/dist/app/entry.server.js.map +1 -1
  4. package/dist/app/tailwind.js +14 -0
  5. package/dist/app/tailwind.js.map +1 -1
  6. package/dist/cli/cmds/dev.js +1 -7
  7. package/dist/cli/cmds/dev.js.map +1 -1
  8. package/dist/config/validators/common.d.ts +17 -0
  9. package/dist/config/validators/common.js +1 -0
  10. package/dist/config/validators/common.js.map +1 -1
  11. package/dist/config/validators/validate.d.ts +7 -0
  12. package/dist/lib/components/Bootstrap.d.ts +2 -1
  13. package/dist/lib/components/Bootstrap.js +3 -2
  14. package/dist/lib/components/Bootstrap.js.map +1 -1
  15. package/dist/lib/components/Header.js +2 -2
  16. package/dist/lib/components/Header.js.map +1 -1
  17. package/dist/lib/components/Heading.d.ts +1 -1
  18. package/dist/lib/components/Layout.js +2 -9
  19. package/dist/lib/components/Layout.js.map +1 -1
  20. package/dist/lib/components/Main.js +3 -1
  21. package/dist/lib/components/Main.js.map +1 -1
  22. package/dist/lib/components/MobileTopNavigation.js +6 -3
  23. package/dist/lib/components/MobileTopNavigation.js.map +1 -1
  24. package/dist/lib/components/Pagination.d.ts +10 -0
  25. package/dist/lib/components/Pagination.js +10 -0
  26. package/dist/lib/components/Pagination.js.map +1 -0
  27. package/dist/lib/components/TopNavigation.d.ts +1 -0
  28. package/dist/lib/components/TopNavigation.js +18 -2
  29. package/dist/lib/components/TopNavigation.js.map +1 -1
  30. package/dist/lib/components/Zudoku.js +4 -1
  31. package/dist/lib/components/Zudoku.js.map +1 -1
  32. package/dist/lib/components/context/BypassProtectedRoutesContext.d.ts +1 -0
  33. package/dist/lib/components/context/BypassProtectedRoutesContext.js +3 -0
  34. package/dist/lib/components/context/BypassProtectedRoutesContext.js.map +1 -0
  35. package/dist/lib/components/index.d.ts +2 -1
  36. package/dist/lib/components/navigation/PoweredByZudoku.d.ts +3 -0
  37. package/dist/lib/components/navigation/PoweredByZudoku.js +6 -0
  38. package/dist/lib/components/navigation/PoweredByZudoku.js.map +1 -0
  39. package/dist/lib/components/navigation/SidebarItem.d.ts +1 -0
  40. package/dist/lib/components/navigation/SidebarItem.js +7 -3
  41. package/dist/lib/components/navigation/SidebarItem.js.map +1 -1
  42. package/dist/lib/components/navigation/SidebarWrapper.js +9 -2
  43. package/dist/lib/components/navigation/SidebarWrapper.js.map +1 -1
  44. package/dist/lib/{plugins/markdown → components/navigation}/Toc.js +5 -7
  45. package/dist/lib/components/navigation/Toc.js.map +1 -0
  46. package/dist/lib/components/navigation/ZudokuLogo.d.ts +6 -0
  47. package/dist/lib/components/navigation/ZudokuLogo.js +5 -0
  48. package/dist/lib/components/navigation/ZudokuLogo.js.map +1 -0
  49. package/dist/lib/core/RouteGuard.d.ts +1 -0
  50. package/dist/lib/core/RouteGuard.js +9 -3
  51. package/dist/lib/core/RouteGuard.js.map +1 -1
  52. package/dist/lib/core/ZudokuContext.d.ts +1 -0
  53. package/dist/lib/core/ZudokuContext.js.map +1 -1
  54. package/dist/lib/oas/graphql/index.d.ts +2 -1
  55. package/dist/lib/oas/graphql/index.js +74 -14
  56. package/dist/lib/oas/graphql/index.js.map +1 -1
  57. package/dist/lib/oas/parser/dereference/index.js +2 -0
  58. package/dist/lib/oas/parser/dereference/index.js.map +1 -1
  59. package/dist/lib/oas/parser/index.d.ts +5 -3
  60. package/dist/lib/oas/parser/index.js +0 -22
  61. package/dist/lib/oas/parser/index.js.map +1 -1
  62. package/dist/lib/plugins/api-catalog/index.js +19 -17
  63. package/dist/lib/plugins/api-catalog/index.js.map +1 -1
  64. package/dist/lib/plugins/markdown/MdxPage.js +3 -3
  65. package/dist/lib/plugins/markdown/MdxPage.js.map +1 -1
  66. package/dist/lib/plugins/openapi/ColorizedParam.js +1 -1
  67. package/dist/lib/plugins/openapi/ColorizedParam.js.map +1 -1
  68. package/dist/lib/plugins/openapi/OperationList.d.ts +1 -1
  69. package/dist/lib/plugins/openapi/OperationList.js +28 -8
  70. package/dist/lib/plugins/openapi/OperationList.js.map +1 -1
  71. package/dist/lib/plugins/openapi/OperationListItem.js +1 -1
  72. package/dist/lib/plugins/openapi/OperationListItem.js.map +1 -1
  73. package/dist/lib/plugins/openapi/ParameterListItem.js +2 -1
  74. package/dist/lib/plugins/openapi/ParameterListItem.js.map +1 -1
  75. package/dist/lib/plugins/openapi/SchemaList.d.ts +1 -0
  76. package/dist/lib/plugins/openapi/SchemaList.js +52 -0
  77. package/dist/lib/plugins/openapi/SchemaList.js.map +1 -0
  78. package/dist/lib/plugins/openapi/client/GraphQLClient.d.ts +1 -1
  79. package/dist/lib/plugins/openapi/client/GraphQLClient.js +1 -1
  80. package/dist/lib/plugins/openapi/client/GraphQLClient.js.map +1 -1
  81. package/dist/lib/plugins/openapi/client/useCreateQuery.d.ts +6 -2
  82. package/dist/lib/plugins/openapi/client/useCreateQuery.js +5 -5
  83. package/dist/lib/plugins/openapi/client/useCreateQuery.js.map +1 -1
  84. package/dist/lib/plugins/openapi/components/EnumValues.js +1 -1
  85. package/dist/lib/plugins/openapi/components/EnumValues.js.map +1 -1
  86. package/dist/lib/plugins/openapi/graphql/gql.d.ts +6 -2
  87. package/dist/lib/plugins/openapi/graphql/gql.js +3 -2
  88. package/dist/lib/plugins/openapi/graphql/gql.js.map +1 -1
  89. package/dist/lib/plugins/openapi/graphql/graphql.d.ts +67 -11
  90. package/dist/lib/plugins/openapi/graphql/graphql.js +34 -5
  91. package/dist/lib/plugins/openapi/graphql/graphql.js.map +1 -1
  92. package/dist/lib/plugins/openapi/index.js +12 -0
  93. package/dist/lib/plugins/openapi/index.js.map +1 -1
  94. package/dist/lib/plugins/openapi/schema/LogicalGroup/LogicalGroup.d.ts +1 -2
  95. package/dist/lib/plugins/openapi/schema/LogicalGroup/LogicalGroup.js +2 -2
  96. package/dist/lib/plugins/openapi/schema/LogicalGroup/LogicalGroup.js.map +1 -1
  97. package/dist/lib/plugins/openapi/schema/LogicalGroup/LogicalGroupConnector.d.ts +2 -1
  98. package/dist/lib/plugins/openapi/schema/LogicalGroup/LogicalGroupConnector.js +2 -2
  99. package/dist/lib/plugins/openapi/schema/LogicalGroup/LogicalGroupConnector.js.map +1 -1
  100. package/dist/lib/plugins/openapi/schema/LogicalGroup/LogicalGroupItem.d.ts +0 -1
  101. package/dist/lib/plugins/openapi/schema/LogicalGroup/LogicalGroupItem.js +1 -1
  102. package/dist/lib/plugins/openapi/schema/LogicalGroup/LogicalGroupItem.js.map +1 -1
  103. package/dist/lib/plugins/openapi/schema/SchemaExampleAndDefault.d.ts +4 -0
  104. package/dist/lib/plugins/openapi/schema/SchemaExampleAndDefault.js +12 -0
  105. package/dist/lib/plugins/openapi/schema/SchemaExampleAndDefault.js.map +1 -0
  106. package/dist/lib/plugins/openapi/schema/SchemaPropertyItem.d.ts +2 -4
  107. package/dist/lib/plugins/openapi/schema/SchemaPropertyItem.js +12 -9
  108. package/dist/lib/plugins/openapi/schema/SchemaPropertyItem.js.map +1 -1
  109. package/dist/lib/plugins/openapi/schema/SchemaView.d.ts +1 -2
  110. package/dist/lib/plugins/openapi/schema/SchemaView.js +30 -52
  111. package/dist/lib/plugins/openapi/schema/SchemaView.js.map +1 -1
  112. package/dist/lib/plugins/openapi/schema/utils.d.ts +1 -0
  113. package/dist/lib/plugins/openapi/schema/utils.js +3 -1
  114. package/dist/lib/plugins/openapi/schema/utils.js.map +1 -1
  115. package/dist/lib/plugins/openapi/util/getRoutes.js +9 -3
  116. package/dist/lib/plugins/openapi/util/getRoutes.js.map +1 -1
  117. package/dist/lib/plugins/search-pagefind/PagefindSearch.js +9 -4
  118. package/dist/lib/plugins/search-pagefind/PagefindSearch.js.map +1 -1
  119. package/dist/lib/plugins/search-pagefind/ResultList.d.ts +1 -1
  120. package/dist/lib/plugins/search-pagefind/ResultList.js +6 -12
  121. package/dist/lib/plugins/search-pagefind/ResultList.js.map +1 -1
  122. package/dist/lib/plugins/search-pagefind/index.d.ts +1 -3
  123. package/dist/lib/util/useOnScreen.d.ts +3 -2
  124. package/dist/lib/util/useOnScreen.js +3 -3
  125. package/dist/lib/util/useOnScreen.js.map +1 -1
  126. package/dist/vite/api/schema-codegen.js +2 -2
  127. package/dist/vite/api/schema-codegen.js.map +1 -1
  128. package/dist/vite/api/schema-codegen.test.js +5 -0
  129. package/dist/vite/api/schema-codegen.test.js.map +1 -1
  130. package/dist/vite/build.js +1 -9
  131. package/dist/vite/build.js.map +1 -1
  132. package/dist/vite/plugin-api.js +8 -7
  133. package/dist/vite/plugin-api.js.map +1 -1
  134. package/dist/vite/plugin-search.js +1 -1
  135. package/dist/vite/plugin-search.js.map +1 -1
  136. package/dist/vite/prerender/FileWritingResponse.d.ts +9 -5
  137. package/dist/vite/prerender/FileWritingResponse.js +5 -5
  138. package/dist/vite/prerender/FileWritingResponse.js.map +1 -1
  139. package/dist/vite/prerender/InMemoryResponse.d.ts +16 -0
  140. package/dist/vite/prerender/InMemoryResponse.js +32 -0
  141. package/dist/vite/prerender/InMemoryResponse.js.map +1 -0
  142. package/dist/vite/prerender/PrerenderResponse.d.ts +10 -0
  143. package/dist/vite/prerender/PrerenderResponse.js +2 -0
  144. package/dist/vite/prerender/PrerenderResponse.js.map +1 -0
  145. package/dist/vite/prerender/prerender.d.ts +1 -0
  146. package/dist/vite/prerender/prerender.js +18 -0
  147. package/dist/vite/prerender/prerender.js.map +1 -1
  148. package/dist/vite/prerender/worker.js +36 -8
  149. package/dist/vite/prerender/worker.js.map +1 -1
  150. package/dist/zuplo/with-zuplo.js +4 -0
  151. package/dist/zuplo/with-zuplo.js.map +1 -1
  152. package/lib/{AuthenticationPlugin-Duy_R1TU.js → AuthenticationPlugin-foqdvvkf.js} +2 -2
  153. package/lib/{AuthenticationPlugin-Duy_R1TU.js.map → AuthenticationPlugin-foqdvvkf.js.map} +1 -1
  154. package/lib/{Markdown-DIZ8nBVC.js → Markdown-aF5FdsNi.js} +1339 -1335
  155. package/lib/{Markdown-DIZ8nBVC.js.map → Markdown-aF5FdsNi.js.map} +1 -1
  156. package/lib/MdxPage-JscVnWM8.js +84 -0
  157. package/lib/MdxPage-JscVnWM8.js.map +1 -0
  158. package/lib/{OasProvider-D1A10JeA.js → OasProvider-C7Y53snX.js} +3 -3
  159. package/lib/{OasProvider-D1A10JeA.js.map → OasProvider-C7Y53snX.js.map} +1 -1
  160. package/lib/OperationList-_M8wg22T.js +5066 -0
  161. package/lib/OperationList-_M8wg22T.js.map +1 -0
  162. package/lib/Pagination-DCCvGq0m.js +46 -0
  163. package/lib/Pagination-DCCvGq0m.js.map +1 -0
  164. package/lib/RouteGuard-CqZPoZYJ.js +744 -0
  165. package/lib/RouteGuard-CqZPoZYJ.js.map +1 -0
  166. package/lib/SchemaList-CrKZdUyo.js +148 -0
  167. package/lib/SchemaList-CrKZdUyo.js.map +1 -0
  168. package/lib/SchemaView-B4JHn-BX.js +354 -0
  169. package/lib/SchemaView-B4JHn-BX.js.map +1 -0
  170. package/lib/{Select-fAYcJ0OU.js → Select-DVFRKf1R.js} +3 -3
  171. package/lib/{Select-fAYcJ0OU.js.map → Select-DVFRKf1R.js.map} +1 -1
  172. package/lib/{SlotletProvider-BEwNY8q0.js → SlotletProvider-DXvc0aY6.js} +2 -2
  173. package/lib/{SlotletProvider-BEwNY8q0.js.map → SlotletProvider-DXvc0aY6.js.map} +1 -1
  174. package/lib/Toc-YBsgI72s.js +92 -0
  175. package/lib/Toc-YBsgI72s.js.map +1 -0
  176. package/lib/{createServer-DjgKDpGV.js → createServer-mYvGvmc0.js} +2596 -2502
  177. package/lib/createServer-mYvGvmc0.js.map +1 -0
  178. package/lib/{hook-Cge6LiTK.js → hook-CqpVYDqN.js} +28 -28
  179. package/lib/{hook-Cge6LiTK.js.map → hook-CqpVYDqN.js.map} +1 -1
  180. package/lib/{index-B0y3fTg-.js → index-C8-tlf_X.js} +771 -729
  181. package/lib/index-C8-tlf_X.js.map +1 -0
  182. package/lib/index-D6ktNq4i.js +1863 -0
  183. package/lib/index-D6ktNq4i.js.map +1 -0
  184. package/lib/{mutation-EChriCeF.js → mutation-8LjrN7uz.js} +2 -2
  185. package/lib/{mutation-EChriCeF.js.map → mutation-8LjrN7uz.js.map} +1 -1
  186. package/lib/objectEntries-yMIkr2mI.js +5 -0
  187. package/lib/objectEntries-yMIkr2mI.js.map +1 -0
  188. package/lib/useLatest-hmRS46UF.js +11 -0
  189. package/lib/useLatest-hmRS46UF.js.map +1 -0
  190. package/lib/zudoku.auth-auth0.js +1 -1
  191. package/lib/zudoku.auth-clerk.js +2 -2
  192. package/lib/zudoku.auth-openid.js +2 -2
  193. package/lib/zudoku.components.js +32 -1454
  194. package/lib/zudoku.components.js.map +1 -1
  195. package/lib/zudoku.hooks.js +1 -1
  196. package/lib/zudoku.plugin-api-catalog.js +80 -76
  197. package/lib/zudoku.plugin-api-catalog.js.map +1 -1
  198. package/lib/zudoku.plugin-api-keys.js +3 -3
  199. package/lib/zudoku.plugin-custom-pages.js +1 -1
  200. package/lib/zudoku.plugin-markdown.js +1 -1
  201. package/lib/zudoku.plugin-openapi.js +2 -2
  202. package/lib/zudoku.plugin-search-pagefind.js +132 -137
  203. package/lib/zudoku.plugin-search-pagefind.js.map +1 -1
  204. package/package.json +6 -5
  205. package/src/app/entry.server.tsx +6 -3
  206. package/src/app/tailwind.ts +14 -0
  207. package/src/lib/components/Bootstrap.tsx +13 -6
  208. package/src/lib/components/Header.tsx +2 -2
  209. package/src/lib/components/Layout.tsx +5 -17
  210. package/src/lib/components/Main.tsx +6 -3
  211. package/src/lib/components/MobileTopNavigation.tsx +27 -18
  212. package/src/lib/components/Pagination.tsx +47 -0
  213. package/src/lib/components/TopNavigation.tsx +29 -2
  214. package/src/lib/components/Zudoku.tsx +5 -3
  215. package/src/lib/components/context/BypassProtectedRoutesContext.ts +3 -0
  216. package/src/lib/components/navigation/PoweredByZudoku.tsx +23 -0
  217. package/src/lib/components/navigation/SidebarItem.tsx +10 -4
  218. package/src/lib/components/navigation/SidebarWrapper.tsx +27 -13
  219. package/src/lib/{plugins/markdown → components/navigation}/Toc.tsx +5 -14
  220. package/src/lib/components/navigation/ZudokuLogo.tsx +25 -0
  221. package/src/lib/core/RouteGuard.tsx +26 -4
  222. package/src/lib/core/ZudokuContext.ts +1 -0
  223. package/src/lib/oas/graphql/index.ts +118 -45
  224. package/src/lib/oas/parser/dereference/index.ts +2 -0
  225. package/src/lib/oas/parser/index.ts +7 -29
  226. package/src/lib/plugins/api-catalog/index.tsx +40 -35
  227. package/src/lib/plugins/markdown/MdxPage.tsx +6 -36
  228. package/src/lib/plugins/openapi/ColorizedParam.tsx +1 -1
  229. package/src/lib/plugins/openapi/OperationList.tsx +36 -15
  230. package/src/lib/plugins/openapi/OperationListItem.tsx +7 -2
  231. package/src/lib/plugins/openapi/ParameterListItem.tsx +2 -0
  232. package/src/lib/plugins/openapi/SchemaList.tsx +151 -0
  233. package/src/lib/plugins/openapi/client/GraphQLClient.tsx +1 -1
  234. package/src/lib/plugins/openapi/client/useCreateQuery.ts +12 -5
  235. package/src/lib/plugins/openapi/components/EnumValues.tsx +1 -1
  236. package/src/lib/plugins/openapi/graphql/gql.ts +15 -6
  237. package/src/lib/plugins/openapi/graphql/graphql.ts +104 -15
  238. package/src/lib/plugins/openapi/index.tsx +13 -0
  239. package/src/lib/plugins/openapi/schema/LogicalGroup/LogicalGroup.tsx +1 -8
  240. package/src/lib/plugins/openapi/schema/LogicalGroup/LogicalGroupConnector.tsx +3 -0
  241. package/src/lib/plugins/openapi/schema/LogicalGroup/LogicalGroupItem.tsx +6 -3
  242. package/src/lib/plugins/openapi/schema/SchemaExampleAndDefault.tsx +36 -0
  243. package/src/lib/plugins/openapi/schema/SchemaPropertyItem.tsx +20 -21
  244. package/src/lib/plugins/openapi/schema/SchemaView.tsx +69 -141
  245. package/src/lib/plugins/openapi/schema/utils.ts +7 -1
  246. package/src/lib/plugins/openapi/util/getRoutes.tsx +9 -6
  247. package/src/lib/plugins/search-pagefind/PagefindSearch.tsx +11 -4
  248. package/src/lib/plugins/search-pagefind/ResultList.tsx +5 -16
  249. package/src/lib/plugins/search-pagefind/index.tsx +1 -1
  250. package/src/lib/util/useOnScreen.ts +6 -4
  251. package/dist/cli/dev/pagefind-command.d.ts +0 -3
  252. package/dist/cli/dev/pagefind-command.js +0 -59
  253. package/dist/cli/dev/pagefind-command.js.map +0 -1
  254. package/dist/lib/components/context/PluginSystem.d.ts +0 -1
  255. package/dist/lib/components/context/PluginSystem.js +0 -2
  256. package/dist/lib/components/context/PluginSystem.js.map +0 -1
  257. package/dist/lib/plugins/markdown/Toc.js.map +0 -1
  258. package/lib/MdxPage-JEdbfW-f.js +0 -195
  259. package/lib/MdxPage-JEdbfW-f.js.map +0 -1
  260. package/lib/OperationList-yOmYzMIp.js +0 -5379
  261. package/lib/OperationList-yOmYzMIp.js.map +0 -1
  262. package/lib/createServer-DjgKDpGV.js.map +0 -1
  263. package/lib/index-B0y3fTg-.js.map +0 -1
  264. package/lib/index.esm-CltAN0Tf.js +0 -711
  265. package/lib/index.esm-CltAN0Tf.js.map +0 -1
  266. package/lib/objectEntries-BS7aAgOm.js +0 -12
  267. package/lib/objectEntries-BS7aAgOm.js.map +0 -1
  268. package/src/lib/components/context/PluginSystem.ts +0 -0
  269. /package/dist/lib/{plugins/markdown → components/navigation}/Toc.d.ts +0 -0
@@ -52,6 +52,7 @@ type Metadata = Partial<{
52
52
  }>;
53
53
 
54
54
  type Page = Partial<{
55
+ showPoweredBy: boolean;
55
56
  pageTitle?: string;
56
57
  logo?: {
57
58
  src: {
@@ -97,7 +97,7 @@ const resolveExtensions = (obj: Record<string, any>) =>
97
97
  export const getAllTags = (
98
98
  schema: OpenAPIDocument,
99
99
  slugs: ReturnType<typeof getAllSlugs>["tags"],
100
- ): Array<TagObject & { slug?: string }> => {
100
+ ): Array<Omit<TagObject, "name"> & { name?: string; slug?: string }> => {
101
101
  const rootTags = schema.tags ?? [];
102
102
  const operationTags = new Set(
103
103
  Object.values(schema.paths ?? {})
@@ -105,6 +105,12 @@ export const getAllTags = (
105
105
  .flatMap((op) => (op as OperationObject).tags ?? []),
106
106
  );
107
107
 
108
+ const hasUntaggedOperations = Object.values(schema.paths ?? {}).some((path) =>
109
+ Object.values(path ?? {}).some(
110
+ (op) => !(op as OperationObject).tags?.length,
111
+ ),
112
+ );
113
+
108
114
  return [
109
115
  // Keep root tags that are actually used in operations
110
116
  ...rootTags
@@ -114,6 +120,8 @@ export const getAllTags = (
114
120
  ...[...operationTags]
115
121
  .filter((tag) => !rootTags.some((rt) => rt.name === tag))
116
122
  .map((tag) => ({ name: tag, slug: slugs[tag] })),
123
+ // Add untagged operations if there are any
124
+ ...(hasUntaggedOperations ? [{ name: undefined, slug: undefined }] : []),
117
125
  ];
118
126
  };
119
127
 
@@ -181,38 +189,55 @@ export const getAllOperations = (
181
189
  return operations;
182
190
  };
183
191
 
184
- const SchemaTag = builder
185
- .objectRef<
186
- Omit<TagObject, "name"> & { name?: string; slug?: string }
187
- >("SchemaTag")
188
- .implement({
189
- fields: (t) => ({
190
- name: t.exposeString("name", { nullable: true }),
191
- slug: t.exposeString("slug", { nullable: true }),
192
- description: t.exposeString("description", { nullable: true }),
193
- operations: t.field({
194
- type: [OperationItem],
195
- resolve: (parent, _args, ctx) => {
196
- const rootTags = ctx.tags.map((tag) => tag.name);
197
-
198
- return ctx.operations
199
- .filter((item) =>
200
- parent.name
201
- ? item.tags?.includes(parent.name)
202
- : item.tags?.length === 0 ||
203
- // If none of the tags are present in the root tags, then show them here
204
- item.tags?.every((tag) => !rootTags.includes(tag)),
205
- )
206
- .map((item) => ({ ...item, parentTag: parent.name }));
207
- },
208
- }),
209
- extensions: t.field({
210
- type: JSONObjectScalar,
211
- resolve: (parent) => resolveExtensions(parent),
212
- nullable: true,
213
- }),
192
+ const SchemaTag = builder.objectRef<
193
+ Omit<TagObject, "name"> & { name?: string; slug?: string }
194
+ >("SchemaTag");
195
+
196
+ SchemaTag.implement({
197
+ fields: (t) => ({
198
+ name: t.exposeString("name", { nullable: true }),
199
+ slug: t.exposeString("slug", { nullable: true }),
200
+ isUntagged: t.field({ type: "Boolean", resolve: (parent) => !parent.name }),
201
+ description: t.exposeString("description", { nullable: true }),
202
+ operations: t.field({
203
+ type: [OperationItem],
204
+ resolve: (parent, _args, ctx) => {
205
+ const rootTags = ctx.tags.map((tag) => tag.name);
206
+
207
+ return ctx.operations
208
+ .filter((item) =>
209
+ parent.name
210
+ ? item.tags?.includes(parent.name)
211
+ : item.tags?.length === 0 ||
212
+ // If none of the tags are present in the root tags, then show them here
213
+ item.tags?.every((tag) => !rootTags.includes(tag)),
214
+ )
215
+ .map((item) => ({ ...item, parentTag: parent.name }));
216
+ },
214
217
  }),
215
- });
218
+ prev: t.field({
219
+ type: SchemaTag,
220
+ nullable: true,
221
+ resolve: (parent, _args, ctx) => {
222
+ const index = ctx.tags.findIndex((tag) => tag.slug === parent.slug);
223
+ return ctx.tags[index - 1];
224
+ },
225
+ }),
226
+ next: t.field({
227
+ type: SchemaTag,
228
+ nullable: true,
229
+ resolve: (parent, _args, ctx) => {
230
+ const index = ctx.tags.findIndex((tag) => tag.slug === parent.slug);
231
+ return ctx.tags[index + 1];
232
+ },
233
+ }),
234
+ extensions: t.field({
235
+ type: JSONObjectScalar,
236
+ resolve: (parent) => resolveExtensions(parent),
237
+ nullable: true,
238
+ }),
239
+ }),
240
+ });
216
241
 
217
242
  const ServerItem = builder.objectRef<ServerObject>("Server").implement({
218
243
  fields: (t) => ({
@@ -466,6 +491,43 @@ const OperationItem = builder
466
491
  }),
467
492
  });
468
493
 
494
+ const SchemaItem = builder
495
+ .objectRef<{
496
+ name: string;
497
+ schema: SchemaObject;
498
+ extensions?: Record<string, any>;
499
+ }>("SchemaItem")
500
+ .implement({
501
+ fields: (t) => ({
502
+ name: t.exposeString("name"),
503
+ schema: t.expose("schema", { type: JSONSchemaScalar }),
504
+ extensions: t.expose("extensions", {
505
+ type: JSONObjectScalar,
506
+ nullable: true,
507
+ }),
508
+ }),
509
+ });
510
+
511
+ const Components = builder.objectRef<{
512
+ schemas?: Record<string, SchemaObject>;
513
+ }>("Components");
514
+
515
+ Components.implement({
516
+ fields: (t) => ({
517
+ schemas: t.field({
518
+ type: [SchemaItem],
519
+ resolve: (parent) => {
520
+ return Object.entries(parent.schemas ?? {}).map(([name, schema]) => ({
521
+ name,
522
+ schema,
523
+ extensions: resolveExtensions(schema),
524
+ }));
525
+ },
526
+ nullable: true,
527
+ }),
528
+ }),
529
+ });
530
+
469
531
  const Schema = builder.objectRef<OpenAPIDocument>("Schema").implement({
470
532
  fields: (t) => ({
471
533
  openapi: t.string({ resolve: (root) => root.openapi }),
@@ -495,24 +557,30 @@ const Schema = builder.objectRef<OpenAPIDocument>("Schema").implement({
495
557
  methods: Object.keys(value!) as typeof HttpMethods,
496
558
  })),
497
559
  }),
498
- tags: t.field({
560
+ tag: t.field({
561
+ type: SchemaTag,
499
562
  args: {
563
+ slug: t.arg.string(),
500
564
  name: t.arg.string(),
565
+ untagged: t.arg.boolean(),
501
566
  },
502
- type: [SchemaTag],
503
- resolve: (_root, args, ctx) => {
504
- if (args.name) {
505
- return ctx.tags.filter((tag) => tag.name === args.name);
567
+ nullable: true,
568
+ resolve: (_, args, ctx) => {
569
+ if (args.untagged) {
570
+ return ctx.tags.find((tag) => tag.name === undefined);
506
571
  }
507
-
508
- // Append empty tag which will be used to display untagged operations
509
- if (ctx.operations.some((op) => !op.tags?.length)) {
510
- return [...ctx.tags, { name: undefined, slug: undefined }];
572
+ if (args.slug) {
573
+ return ctx.tags.find((tag) => tag.slug === args.slug);
574
+ }
575
+ if (args.name) {
576
+ return ctx.tags.find((tag) => tag.name === args.name);
511
577
  }
512
-
513
- return ctx.tags;
514
578
  },
515
579
  }),
580
+ tags: t.field({
581
+ type: [SchemaTag],
582
+ resolve: (_root, _args, ctx) => ctx.tags,
583
+ }),
516
584
  operations: t.field({
517
585
  type: [OperationItem],
518
586
  args: {
@@ -522,7 +590,7 @@ const Schema = builder.objectRef<OpenAPIDocument>("Schema").implement({
522
590
  tag: t.arg.string(),
523
591
  untagged: t.arg.boolean(),
524
592
  },
525
- resolve: (parent, args, ctx) =>
593
+ resolve: (_parent, args, ctx) =>
526
594
  ctx.operations.filter((op) => {
527
595
  return (
528
596
  (!args.operationId || op.operationId === args.operationId) &&
@@ -533,6 +601,11 @@ const Schema = builder.objectRef<OpenAPIDocument>("Schema").implement({
533
601
  );
534
602
  }),
535
603
  }),
604
+ components: t.field({
605
+ type: Components,
606
+ resolve: (root) => root.components,
607
+ nullable: true,
608
+ }),
536
609
  extensions: t.field({
537
610
  type: JSONObjectScalar,
538
611
  resolve: (root) => resolveExtensions(root),
@@ -553,7 +626,7 @@ builder.queryType({
553
626
  type: t.arg({ type: SchemaSource, required: true }),
554
627
  input: t.arg({ type: JSONScalar, required: true }),
555
628
  },
556
- resolve: async (_, args, ctx) => {
629
+ resolve: async (_parent, args, ctx) => {
557
630
  if (args.type === "file" && typeof args.input === "string") {
558
631
  const loadSchema = ctx.schemaImports?.[args.input];
559
632
 
@@ -38,6 +38,8 @@ export const dereference = async (
38
38
  }
39
39
  } else {
40
40
  if ("$ref" in current && typeof current.$ref === "string") {
41
+ // Store the ref path before resolving
42
+ current.__$ref = current.$ref;
41
43
  for (const resolver of resolvers) {
42
44
  const resolved = await resolver(current.$ref);
43
45
  if (resolved) return await resolve(resolved, path);
@@ -3,11 +3,15 @@ import { OpenAPIV3, type OpenAPIV3_1 } from "openapi-types";
3
3
  import { dereference, type JSONSchema } from "./dereference/index.js";
4
4
  import { upgradeSchema } from "./upgrade/index.js";
5
5
 
6
- type ReferenceObject = OpenAPIV3_1.ReferenceObject;
7
- type DeepOmitReference<T> = T extends ReferenceObject
6
+ // Must be an interface (not a type) to allow merging with OpenAPI types with index signatures
7
+ interface WithRef {
8
+ __$ref?: string;
9
+ }
10
+
11
+ type DeepOmitReference<T> = T extends OpenAPIV3_1.ReferenceObject
8
12
  ? never
9
13
  : T extends object
10
- ? { [K in keyof T]: DeepOmitReference<T[K]> }
14
+ ? { [K in keyof T]: DeepOmitReference<T[K]> } & WithRef
11
15
  : T;
12
16
 
13
17
  export type OpenAPIDocument = DeepOmitReference<OpenAPIV3_1.Document>;
@@ -24,25 +28,6 @@ export type ServerObject = DeepOmitReference<OpenAPIV3_1.ServerObject>;
24
28
 
25
29
  export const HttpMethods = Object.values(OpenAPIV3.HttpMethods);
26
30
 
27
- // class ValidationError extends Error {
28
- // constructor(public errors: OutputUnit[]) {
29
- // super("Validation error");
30
- // }
31
- // }
32
-
33
- // const getValidator = async (openApiVersion: string) => {
34
- // if (openApiVersion.startsWith("3.0")) {
35
- // const schema = (await import("./schemas/v3.0.json")) as any;
36
- // return new Validator(schema, "4");
37
- // }
38
- // if (openApiVersion.startsWith("3.1")) {
39
- // const schema = (await import("./schemas/v3.1.json")) as any;
40
- // return new Validator(schema as any, "2020-12");
41
- // }
42
-
43
- // throw new Error(`Unsupported OpenAPI version: ${openApiVersion}`);
44
- // };
45
-
46
31
  const parseSchemaInput = async (
47
32
  schemaInput: unknown,
48
33
  ): Promise<JSONSchema & { openapi?: string }> => {
@@ -110,13 +95,6 @@ export const validate = async (schemaInput: unknown) => {
110
95
  throw new GraphQLError("OpenAPI version is not defined");
111
96
  }
112
97
 
113
- // const validator = await getValidator(schema.openapi);
114
- // const result = validator.validate(schema);
115
- //
116
- // if (!result.valid) {
117
- // throw new ValidationError(result.errors);
118
- // }
119
-
120
98
  const dereferenced = await dereference(schema);
121
99
 
122
100
  return upgradeSchema(dereferenced);
@@ -51,9 +51,22 @@ export const apiCatalogPlugin = ({
51
51
  items: ApiCatalogItem[];
52
52
  filterCatalogItems?: filterCatalogItems;
53
53
  }): ZudokuPlugin => {
54
+ const paths = Object.fromEntries(
55
+ categories.flatMap((category) =>
56
+ [undefined, ...category.tags].map((tag) => [
57
+ joinUrl(navigationId, tag ? getKey(category.label, tag) : undefined),
58
+ tag,
59
+ ]),
60
+ ),
61
+ );
62
+
54
63
  return {
55
- getSidebar: async function Sidebar(path) {
56
- if (!matchPath({ path: joinUrl(navigationId), end: false }, path)) {
64
+ getSidebar: async (currentPath) => {
65
+ const matches = Object.keys(paths).some((path) =>
66
+ matchPath(path, currentPath),
67
+ );
68
+
69
+ if (!matches) {
57
70
  return [];
58
71
  }
59
72
 
@@ -61,22 +74,19 @@ export const apiCatalogPlugin = ({
61
74
  type: "category" as const,
62
75
  label: category.label,
63
76
  collapsible: false,
64
- items: category.tags.map((tag) => {
65
- const tagPath = getKey(category.label, tag);
66
- return {
67
- type: "doc" as const,
68
- id: joinUrl(navigationId, tagPath),
69
- label: tag,
70
- badge: {
71
- label: String(
72
- items.filter((api) =>
73
- api.categories.find((c) => c.tags.includes(tag)),
74
- ).length,
75
- ),
76
- color: "outline" as const,
77
- },
78
- };
79
- }),
77
+ items: category.tags.map((tag) => ({
78
+ type: "doc" as const,
79
+ id: joinUrl(navigationId, getKey(category.label, tag)),
80
+ label: tag,
81
+ badge: {
82
+ label: String(
83
+ items.filter((api) =>
84
+ api.categories.find((c) => c.tags.includes(tag)),
85
+ ).length,
86
+ ),
87
+ color: "outline" as const,
88
+ },
89
+ })),
80
90
  }));
81
91
 
82
92
  sidebar.unshift({
@@ -89,22 +99,17 @@ export const apiCatalogPlugin = ({
89
99
  return sidebar;
90
100
  },
91
101
  getRoutes: () =>
92
- categories.flatMap((category) =>
93
- [undefined, ...category.tags].map((tag) => ({
94
- path: joinUrl(
95
- navigationId,
96
- tag ? getKey(category.label, tag) : undefined,
97
- ),
98
- element: (
99
- <Catalog
100
- label={label}
101
- categoryLabel={tag}
102
- items={items}
103
- filterCatalogItems={filterCatalogItems}
104
- categories={categories}
105
- />
106
- ),
107
- })),
108
- ),
102
+ Object.entries(paths).map(([path, tag]) => ({
103
+ path,
104
+ element: (
105
+ <Catalog
106
+ label={label}
107
+ categoryLabel={tag}
108
+ items={items}
109
+ filterCatalogItems={filterCatalogItems}
110
+ categories={categories}
111
+ />
112
+ ),
113
+ })),
109
114
  };
110
115
  };
@@ -2,17 +2,17 @@ import { useMDXComponents } from "@mdx-js/react";
2
2
  import slugify from "@sindresorhus/slugify";
3
3
  import { Helmet } from "@zudoku/react-helmet-async";
4
4
  import { type PropsWithChildren, useEffect } from "react";
5
- import { Link } from "react-router";
6
5
  import { CategoryHeading } from "../../components/CategoryHeading.js";
7
6
  import { Heading } from "../../components/Heading.js";
8
7
  import { ProseClasses } from "../../components/Markdown.js";
8
+ import { Pagination } from "../../components/Pagination.js";
9
+ import { Toc } from "../../components/navigation/Toc.js";
9
10
  import {
10
11
  useCurrentItem,
11
12
  usePrevNext,
12
13
  } from "../../components/navigation/utils.js";
13
14
  import type { MdxComponentsType } from "../../util/MdxComponents.js";
14
15
  import { cn } from "../../util/cn.js";
15
- import { Toc } from "./Toc.js";
16
16
  import { type MarkdownPluginDefaultOptions, type MDXImport } from "./index.js";
17
17
 
18
18
  declare global {
@@ -115,40 +115,10 @@ export const MdxPage = ({
115
115
  {!hidePager && (
116
116
  <>
117
117
  <hr />
118
- <div className="not-prose flex flex-wrap items-center justify-between gap-2 lg:gap-8">
119
- {prev ? (
120
- <Link
121
- to={prev.id}
122
- className="flex flex-col items-stretch gap-2 flex-1 min-w-max border rounded px-6 py-4 text-start hover:border-primary/85 transition shadow-sm hover:shadow-md"
123
- title={prev.label}
124
- >
125
- <div className="text-sm text-muted-foreground">
126
- ← Previous page
127
- </div>
128
- <div className="text-lg text-primary truncate">
129
- {prev.label}
130
- </div>
131
- </Link>
132
- ) : (
133
- <div className="flex-1" />
134
- )}
135
- {next ? (
136
- <Link
137
- to={next.id}
138
- className="flex flex-col items-stretch gap-2 flex-1 min-w-max border rounded px-6 py-4 text-end hover:border-primary/85 transition shadow-sm hover:shadow-md"
139
- title={next.label}
140
- >
141
- <div className="text-sm text-muted-foreground">
142
- Next page →
143
- </div>
144
- <div className="text-lg text-primary truncate">
145
- {next.label}
146
- </div>
147
- </Link>
148
- ) : (
149
- <div className="flex-1" />
150
- )}
151
- </div>
118
+ <Pagination
119
+ prev={prev ? { to: prev.id, label: prev.label } : undefined}
120
+ next={next ? { to: next.id, label: next.label } : undefined}
121
+ />
152
122
  </>
153
123
  )}
154
124
  </div>
@@ -90,7 +90,7 @@ export const ColorizedParam = ({
90
90
  {...{ [DATA_ATTR]: normalizedSlug }}
91
91
  className={cn(
92
92
  // This may not contain (inline-)flex or (inline-)block otherwise it breaks the browser's full text search
93
- "relative rounded transition-all duration-100 rounded-lg",
93
+ "relative transition-all duration-100 rounded-lg",
94
94
  "border border-[--border-color] p-0.5 text-[--param-color] bg-[--background-color]",
95
95
  "data-[active=true]:border-[--param-color] data-[active=true]:shadow data-[active=true]:bottom-px",
96
96
  className,
@@ -18,6 +18,7 @@ import {
18
18
  import { CategoryHeading } from "../../components/CategoryHeading.js";
19
19
  import { Heading } from "../../components/Heading.js";
20
20
  import { Markdown, ProseClasses } from "../../components/Markdown.js";
21
+ import { Pagination } from "../../components/Pagination.js";
21
22
  import { useApiIdentities } from "../../components/context/ZudokuContext.js";
22
23
  import { cn } from "../../util/cn.js";
23
24
  import { Endpoint } from "./Endpoint.js";
@@ -25,6 +26,7 @@ import { OperationListItem } from "./OperationListItem.js";
25
26
  import { useCreateQuery } from "./client/useCreateQuery.js";
26
27
  import { useOasConfig } from "./context.js";
27
28
  import { graphql } from "./graphql/index.js";
29
+ import { UNTAGGED_PATH } from "./index.js";
28
30
  import { useSelectedServer } from "./state.js";
29
31
  import { sanitizeMarkdownForMetatag } from "./util/sanitizeMarkdownForMetatag.js";
30
32
 
@@ -121,13 +123,21 @@ const OperationsForTagQuery = graphql(/* GraphQL */ `
121
123
  title
122
124
  url
123
125
  version
124
- tags(name: $tag) {
126
+ tag(slug: $tag, untagged: $untagged) {
125
127
  name
126
128
  description
127
- }
128
- operations(tag: $tag, untagged: $untagged) {
129
- slug
130
- ...OperationsFragment
129
+ operations {
130
+ slug
131
+ ...OperationsFragment
132
+ }
133
+ next {
134
+ name
135
+ slug
136
+ }
137
+ prev {
138
+ name
139
+ slug
140
+ }
131
141
  }
132
142
  }
133
143
  }
@@ -156,8 +166,6 @@ export const OperationList = ({
156
166
  const summary = schema.summary;
157
167
  const description = schema.description;
158
168
  const navigate = useNavigate();
159
- const operations = schema.operations;
160
- const tagDescription = schema.tags.find((t) => t.name === tag)?.description;
161
169
 
162
170
  // This is to warmup (i.e. load the schema in the background) the schema on the client, if the page has been rendered on the server
163
171
  const warmupQuery = useCreateQuery(SchemaWarmupQuery, { input, type });
@@ -170,6 +178,10 @@ export const OperationList = ({
170
178
  // Prefetch for Playground
171
179
  useApiIdentities();
172
180
 
181
+ if (!schema.tag) return null;
182
+
183
+ const { operations, next, prev, description: tagDescription } = schema.tag;
184
+
173
185
  // The summary property is preferable here as it is a short description of
174
186
  // the API, whereas the description property is typically longer and supports
175
187
  // commonmark formatting, making it ill-suited for use in the meta description
@@ -187,6 +199,16 @@ export const OperationList = ({
187
199
  options?.showVersionSelect === "always" ||
188
200
  (hasMultipleVersions && options?.showVersionSelect !== "hide");
189
201
 
202
+ const paginationProps = {
203
+ prev: prev?.name ? { to: `../${prev.slug}`, label: prev.name } : undefined,
204
+ next: next
205
+ ? {
206
+ to: `../${next.slug ?? UNTAGGED_PATH}`,
207
+ label: next.name ?? "Other endpoints",
208
+ }
209
+ : undefined,
210
+ };
211
+
190
212
  return (
191
213
  <div
192
214
  className="pt-[--padding-content-top]"
@@ -194,7 +216,7 @@ export const OperationList = ({
194
216
  data-pagefind-meta="section:openapi"
195
217
  >
196
218
  <Helmet>
197
- <title>{[tag, title].filter(Boolean).join(" - ")}</title>
219
+ <title>{[schema.tag.name, title].filter(Boolean).join(" - ")}</title>
198
220
  {metaDescription && (
199
221
  <meta name="description" content={metaDescription} />
200
222
  )}
@@ -202,7 +224,7 @@ export const OperationList = ({
202
224
  <div className="mb-8">
203
225
  <Collapsible className="w-full">
204
226
  <div className="flex flex-col gap-y-4 sm:flex-row justify-around items-start sm:items-end">
205
- <div className="flex-1">
227
+ <div className="flex flex-col flex-1 gap-2">
206
228
  <CategoryHeading>{title}</CategoryHeading>
207
229
  <Heading
208
230
  level={1}
@@ -210,7 +232,7 @@ export const OperationList = ({
210
232
  registerSidebarAnchor
211
233
  className="mb-0"
212
234
  >
213
- {tag ?? "Other endpoints"}
235
+ {schema.tag.name ?? "Other endpoints"}
214
236
  {showVersions && (
215
237
  <span className="text-xl text-muted-foreground ml-1.5">
216
238
  {" "}
@@ -218,6 +240,7 @@ export const OperationList = ({
218
240
  </span>
219
241
  )}
220
242
  </Heading>
243
+ <Endpoint />
221
244
  </div>
222
245
  <div className="flex flex-col gap-4 sm:items-end">
223
246
  {showVersions && (
@@ -240,7 +263,7 @@ export const OperationList = ({
240
263
  )}
241
264
  {schema.description && (
242
265
  <CollapsibleTrigger className="flex items-center gap-1 text-sm font-medium text-muted-foreground group">
243
- <span>Schema description</span>
266
+ <span>API information</span>
244
267
 
245
268
  <ChevronsUpDownIcon
246
269
  className="group-data-[state=open]:hidden translate-y-px"
@@ -282,11 +305,8 @@ export const OperationList = ({
282
305
  )}
283
306
  </div>
284
307
  <hr />
285
- <div className="my-4 flex items-center justify-end gap-4">
286
- <Endpoint />
287
- </div>
288
308
  {/* px, -mx is so that `content-visibility` doesn't cut off overflown heading anchor links '#' */}
289
- <div className="px-6 -mx-6 [content-visibility:auto]">
309
+ <div className="px-6 mt-6 -mx-6 [content-visibility:auto]">
290
310
  {operations.map((fragment) => (
291
311
  <OperationListItem
292
312
  serverUrl={selectedServer}
@@ -294,6 +314,7 @@ export const OperationList = ({
294
314
  operationFragment={fragment}
295
315
  />
296
316
  ))}
317
+ <Pagination {...paginationProps} />
297
318
  </div>
298
319
  </div>
299
320
  );
@@ -100,13 +100,18 @@ export const OperationListItem = ({
100
100
  <div className="mt-4 flex flex-col gap-4">
101
101
  <Heading
102
102
  level={3}
103
- className="capitalize"
103
+ className="capitalize flex items-center gap-2"
104
104
  id={`${operation.slug}/request-body`}
105
105
  >
106
106
  {operation.summary && (
107
107
  <VisuallyHidden>{operation.summary} &rsaquo; </VisuallyHidden>
108
108
  )}
109
- Request Body
109
+ Request Body{" "}
110
+ {operation.requestBody?.required === false ? (
111
+ <Badge variant="muted">optional</Badge>
112
+ ) : (
113
+ ""
114
+ )}
110
115
  </Heading>
111
116
  <SchemaView schema={schema} />
112
117
  </div>
@@ -6,6 +6,7 @@ import type { ParameterGroup } from "./OperationListItem.js";
6
6
  import { ParamInfos } from "./ParamInfos.js";
7
7
  import { EnumValues } from "./components/EnumValues.js";
8
8
  import { SelectOnClick } from "./components/SelectOnClick.js";
9
+ import { SchemaExampleAndDefault } from "./schema/SchemaExampleAndDefault.js";
9
10
 
10
11
  const getParameterSchema = (
11
12
  parameter: ParameterListItemResult,
@@ -72,6 +73,7 @@ export const ParameterListItem = ({
72
73
  ) : (
73
74
  paramSchema.enum && <EnumValues values={paramSchema.enum} />
74
75
  )}
76
+ <SchemaExampleAndDefault schema={paramSchema} />
75
77
  </li>
76
78
  );
77
79
  };