zudoku 0.3.0-dev.31 → 0.3.0-dev.33

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 (206) hide show
  1. package/dist/app/App.d.ts +1 -0
  2. package/dist/app/App.js +2 -0
  3. package/dist/app/App.js.map +1 -0
  4. package/dist/app/entry.client.d.ts +3 -0
  5. package/dist/app/entry.client.js +38 -0
  6. package/dist/app/entry.client.js.map +1 -0
  7. package/dist/app/entry.server.d.ts +10 -0
  8. package/dist/app/entry.server.js +107 -0
  9. package/dist/app/entry.server.js.map +1 -0
  10. package/dist/app/main.d.ts +26 -2
  11. package/dist/app/main.js +39 -17
  12. package/dist/app/main.js.map +1 -1
  13. package/dist/app/tailwind.js +5 -0
  14. package/dist/app/tailwind.js.map +1 -1
  15. package/dist/app/zudoku-manifest.d.ts +1 -0
  16. package/dist/app/zudoku-manifest.js +20 -0
  17. package/dist/app/zudoku-manifest.js.map +1 -0
  18. package/dist/cli/cmds/dev.js +5 -0
  19. package/dist/cli/cmds/dev.js.map +1 -1
  20. package/dist/cli/dev/handler.d.ts +1 -0
  21. package/dist/cli/dev/handler.js +3 -1
  22. package/dist/cli/dev/handler.js.map +1 -1
  23. package/dist/config/config.d.ts +5 -0
  24. package/dist/lib/authentication/providers/clerk.js +2 -0
  25. package/dist/lib/authentication/providers/clerk.js.map +1 -1
  26. package/dist/lib/components/DevPortal.d.ts +1 -1
  27. package/dist/lib/components/DevPortal.js +6 -10
  28. package/dist/lib/components/DevPortal.js.map +1 -1
  29. package/dist/lib/components/ErrorPage.d.ts +6 -0
  30. package/dist/lib/components/ErrorPage.js +9 -0
  31. package/dist/lib/components/ErrorPage.js.map +1 -0
  32. package/dist/lib/components/InlineCode.d.ts +5 -0
  33. package/dist/lib/components/InlineCode.js +4 -0
  34. package/dist/lib/components/InlineCode.js.map +1 -0
  35. package/dist/lib/components/Layout.js +2 -1
  36. package/dist/lib/components/Layout.js.map +1 -1
  37. package/dist/lib/components/NotFoundPage.d.ts +1 -0
  38. package/dist/lib/components/NotFoundPage.js +12 -0
  39. package/dist/lib/components/NotFoundPage.js.map +1 -0
  40. package/dist/lib/components/SyntaxHighlight.d.ts +3 -2
  41. package/dist/lib/components/SyntaxHighlight.js +20 -22
  42. package/dist/lib/components/SyntaxHighlight.js.map +1 -1
  43. package/dist/lib/errors/RouterError.js +6 -3
  44. package/dist/lib/errors/RouterError.js.map +1 -1
  45. package/dist/lib/errors/ServerError.d.ts +3 -0
  46. package/dist/lib/errors/ServerError.js +6 -0
  47. package/dist/lib/errors/ServerError.js.map +1 -0
  48. package/dist/lib/oas/parser/index.d.ts +1 -1
  49. package/dist/lib/oas/parser/index.js +38 -14
  50. package/dist/lib/oas/parser/index.js.map +1 -1
  51. package/dist/lib/plugins/api-keys/index.js +3 -8
  52. package/dist/lib/plugins/api-keys/index.js.map +1 -1
  53. package/dist/lib/plugins/markdown/generateRoutes.js.map +1 -1
  54. package/dist/lib/plugins/markdown/index.js +3 -7
  55. package/dist/lib/plugins/markdown/index.js.map +1 -1
  56. package/dist/lib/plugins/openapi/OperationList.js +11 -1
  57. package/dist/lib/plugins/openapi/OperationList.js.map +1 -1
  58. package/dist/lib/plugins/openapi/OperationListItem.js +2 -1
  59. package/dist/lib/plugins/openapi/OperationListItem.js.map +1 -1
  60. package/dist/lib/plugins/openapi/SchemaListView.js +2 -1
  61. package/dist/lib/plugins/openapi/SchemaListView.js.map +1 -1
  62. package/dist/lib/plugins/openapi/client/createMemoryClient.js +1 -1
  63. package/dist/lib/plugins/openapi/client/createMemoryClient.js.map +1 -1
  64. package/dist/lib/plugins/openapi/index.js +9 -1
  65. package/dist/lib/plugins/openapi/index.js.map +1 -1
  66. package/dist/lib/plugins/openapi/playground/QueryParams.js +2 -1
  67. package/dist/lib/plugins/openapi/playground/QueryParams.js.map +1 -1
  68. package/dist/lib/plugins/redirect/index.js +2 -3
  69. package/dist/lib/plugins/redirect/index.js.map +1 -1
  70. package/dist/lib/ui/Callout.js +1 -1
  71. package/dist/lib/ui/Callout.js.map +1 -1
  72. package/dist/lib/ui/button-variants.d.ts +1 -1
  73. package/dist/lib/util/MdxComponents.js +2 -2
  74. package/dist/lib/util/MdxComponents.js.map +1 -1
  75. package/dist/lib/util/groupBy.d.ts +1 -6
  76. package/dist/lib/util/groupBy.js +10 -8
  77. package/dist/lib/util/groupBy.js.map +1 -1
  78. package/dist/vite/build.js +30 -11
  79. package/dist/vite/build.js.map +1 -1
  80. package/dist/vite/config.d.ts +2 -1
  81. package/dist/vite/config.js +34 -7
  82. package/dist/vite/config.js.map +1 -1
  83. package/dist/vite/dev-server.d.ts +1 -1
  84. package/dist/vite/dev-server.js +15 -9
  85. package/dist/vite/dev-server.js.map +1 -1
  86. package/dist/vite/html.js +5 -4
  87. package/dist/vite/html.js.map +1 -1
  88. package/dist/vite/plugin-custom-css.d.ts +6 -0
  89. package/dist/vite/plugin-custom-css.js +55 -0
  90. package/dist/vite/plugin-custom-css.js.map +1 -0
  91. package/dist/vite/plugin-docs.js +14 -5
  92. package/dist/vite/plugin-docs.js.map +1 -1
  93. package/dist/vite/plugin-openapi-worker.js +4 -1
  94. package/dist/vite/plugin-openapi-worker.js.map +1 -1
  95. package/dist/vite/plugin.js +2 -0
  96. package/dist/vite/plugin.js.map +1 -1
  97. package/dist/vite/prerender.d.ts +1 -0
  98. package/dist/vite/prerender.js +57 -0
  99. package/dist/vite/prerender.js.map +1 -0
  100. package/lib/{DevPortalProvider-BMk-RCE0.js → DevPortalProvider-BlxLX6GG.js} +230 -250
  101. package/lib/DevPortalProvider-BlxLX6GG.js.map +1 -0
  102. package/lib/{Markdown-DDmW47R9.js → Markdown-CL8KPvJN.js} +8 -9
  103. package/lib/{Markdown-DDmW47R9.js.map → Markdown-CL8KPvJN.js.map} +1 -1
  104. package/lib/MdxComponents-Ev_hBHb2.js +5885 -0
  105. package/lib/MdxComponents-Ev_hBHb2.js.map +1 -0
  106. package/lib/{MdxPage-DyJAHF9y.js → MdxPage-Z3HKNTrj.js} +92 -89
  107. package/lib/MdxPage-Z3HKNTrj.js.map +1 -0
  108. package/lib/{OperationList-Dz9rHM9r.js → OperationList-DfkWNe8Y.js} +1972 -1786
  109. package/lib/OperationList-DfkWNe8Y.js.map +1 -0
  110. package/lib/Route-Bf1_D_vC.js +13 -0
  111. package/lib/{Route-CN_7-e5r.js.map → Route-Bf1_D_vC.js.map} +1 -1
  112. package/lib/Select-DSa3bN4t.js +4770 -0
  113. package/lib/Select-DSa3bN4t.js.map +1 -0
  114. package/lib/assets/{worker-BXS8hiSM.js → worker-BjPv-hjP.js} +3100 -2720
  115. package/lib/assets/worker-BjPv-hjP.js.map +1 -0
  116. package/lib/hook-CTmJ6CWq.js +35 -0
  117. package/lib/hook-CTmJ6CWq.js.map +1 -0
  118. package/lib/index-BdWBDosx.js +74 -0
  119. package/lib/index-BdWBDosx.js.map +1 -0
  120. package/lib/{index-Cpdpun6t.js → index-BjSy8IQO.js} +57 -41
  121. package/lib/index-BjSy8IQO.js.map +1 -0
  122. package/lib/{AnchorLink-ptdQk87q.js → index.esm-CPEExBJE.js} +156 -168
  123. package/lib/index.esm-CPEExBJE.js.map +1 -0
  124. package/lib/jsx-runtime-CM0TzjGp.js +866 -0
  125. package/lib/jsx-runtime-CM0TzjGp.js.map +1 -0
  126. package/lib/mutation-91kw0lHb.js +208 -0
  127. package/lib/mutation-91kw0lHb.js.map +1 -0
  128. package/lib/router-CcYTwKjf.js +183 -0
  129. package/lib/router-CcYTwKjf.js.map +1 -0
  130. package/lib/zudoku.auth-clerk.js.map +1 -1
  131. package/lib/zudoku.auth-openid.js +588 -441
  132. package/lib/zudoku.auth-openid.js.map +1 -1
  133. package/lib/zudoku.components.js +284 -595
  134. package/lib/zudoku.components.js.map +1 -1
  135. package/lib/zudoku.openapi-worker.js +18 -18
  136. package/lib/zudoku.plugin-api-keys.js +143 -98
  137. package/lib/zudoku.plugin-api-keys.js.map +1 -1
  138. package/lib/zudoku.plugin-markdown.js +2 -49
  139. package/lib/zudoku.plugin-markdown.js.map +1 -1
  140. package/lib/zudoku.plugin-openapi.js +5 -3
  141. package/lib/zudoku.plugin-openapi.js.map +1 -1
  142. package/lib/zudoku.plugin-redirect.js +6 -7
  143. package/lib/zudoku.plugin-redirect.js.map +1 -1
  144. package/package.json +9 -8
  145. package/src/app/App.tsx +0 -0
  146. package/src/app/entry.client.tsx +64 -0
  147. package/src/app/entry.server.tsx +158 -0
  148. package/src/app/main.tsx +65 -43
  149. package/src/app/tailwind.ts +6 -0
  150. package/src/app/zudoku-manifest.ts +22 -0
  151. package/src/lib/authentication/providers/clerk.tsx +1 -0
  152. package/src/lib/components/DevPortal.tsx +25 -33
  153. package/src/lib/components/ErrorPage.tsx +28 -0
  154. package/src/lib/components/InlineCode.tsx +19 -0
  155. package/src/lib/components/Layout.tsx +7 -4
  156. package/src/lib/components/NotFoundPage.tsx +39 -0
  157. package/src/lib/components/SyntaxHighlight.tsx +26 -22
  158. package/src/lib/errors/RouterError.tsx +8 -7
  159. package/src/lib/errors/ServerError.tsx +5 -0
  160. package/src/lib/oas/parser/index.ts +41 -22
  161. package/src/lib/plugins/api-keys/index.tsx +4 -16
  162. package/src/lib/plugins/markdown/generateRoutes.tsx +1 -1
  163. package/src/lib/plugins/markdown/index.tsx +3 -7
  164. package/src/lib/plugins/openapi/OperationList.tsx +30 -0
  165. package/src/lib/plugins/openapi/OperationListItem.tsx +3 -1
  166. package/src/lib/plugins/openapi/SchemaListView.tsx +8 -10
  167. package/src/lib/plugins/openapi/client/createMemoryClient.ts +1 -1
  168. package/src/lib/plugins/openapi/index.tsx +18 -1
  169. package/src/lib/plugins/openapi/playground/QueryParams.tsx +6 -1
  170. package/src/lib/plugins/redirect/index.tsx +2 -2
  171. package/src/lib/ui/Callout.tsx +2 -2
  172. package/src/lib/util/MdxComponents.tsx +2 -11
  173. package/src/lib/util/groupBy.ts +7 -12
  174. package/dist/lib/components/Router.d.ts +0 -4
  175. package/dist/lib/components/Router.js +0 -21
  176. package/dist/lib/components/Router.js.map +0 -1
  177. package/lib/AnchorLink-ptdQk87q.js.map +0 -1
  178. package/lib/DevPortalProvider-BMk-RCE0.js.map +0 -1
  179. package/lib/MdxComponents-C0R6zobS.js +0 -3019
  180. package/lib/MdxComponents-C0R6zobS.js.map +0 -1
  181. package/lib/MdxPage-DyJAHF9y.js.map +0 -1
  182. package/lib/OperationList-Dz9rHM9r.js.map +0 -1
  183. package/lib/Route-CN_7-e5r.js +0 -14
  184. package/lib/Select-D-Jtx53Q.js +0 -4572
  185. package/lib/Select-D-Jtx53Q.js.map +0 -1
  186. package/lib/Spinner-BG1JnYy0.js +0 -182
  187. package/lib/Spinner-BG1JnYy0.js.map +0 -1
  188. package/lib/assets/worker-BXS8hiSM.js.map +0 -1
  189. package/lib/cn-DpqTslo9.js +0 -2342
  190. package/lib/cn-DpqTslo9.js.map +0 -1
  191. package/lib/hook-BzBeIPL4.js +0 -25
  192. package/lib/hook-BzBeIPL4.js.map +0 -1
  193. package/lib/index-BaOOUFsA.js +0 -412
  194. package/lib/index-BaOOUFsA.js.map +0 -1
  195. package/lib/index-CPvRaBBB.js +0 -713
  196. package/lib/index-CPvRaBBB.js.map +0 -1
  197. package/lib/index-Cpdpun6t.js.map +0 -1
  198. package/lib/index-DLS6fPwU.js +0 -464
  199. package/lib/index-DLS6fPwU.js.map +0 -1
  200. package/lib/jsx-runtime-SV6hXQua.js +0 -3009
  201. package/lib/jsx-runtime-SV6hXQua.js.map +0 -1
  202. package/lib/loglevel-CA34MiFn.js +0 -153
  203. package/lib/loglevel-CA34MiFn.js.map +0 -1
  204. package/lib/util-CCWvaWo7.js +0 -41
  205. package/lib/util-CCWvaWo7.js.map +0 -1
  206. package/src/lib/components/Router.tsx +0 -24
@@ -1,6 +1,7 @@
1
1
  import { Suspense, useEffect, useRef, type ReactNode } from "react";
2
2
  import { Helmet } from "react-helmet-async";
3
3
  import { Outlet, useLocation } from "react-router-dom";
4
+ import { cn } from "../util/cn.js";
4
5
  import { useScrollToAnchor } from "../util/useScrollToAnchor.js";
5
6
  import { useScrollToTop } from "../util/useScrollToTop.js";
6
7
  import { useDevPortal } from "./context/DevPortalProvider.js";
@@ -47,10 +48,12 @@ export const Layout = ({ children }: { children?: ReactNode }) => {
47
48
  >
48
49
  <SideNavigation />
49
50
  <main
50
- className="dark:border-white/10 translate-x-0 h-full
51
- lg:overflow-visible
52
- lg:peer-data-[navigation=true]:w-[calc(100%-var(--side-nav-width))]
53
- lg:peer-data-[navigation=true]:translate-x-[--side-nav-width] peer-data-[navigation=true]:pl-12"
51
+ className={cn(
52
+ "dark:border-white/10 translate-x-0 h-full",
53
+ "lg:overflow-visible",
54
+ "lg:peer-data-[navigation=true]:w-[calc(100%-var(--side-nav-width))]",
55
+ "lg:peer-data-[navigation=true]:translate-x-[--side-nav-width] peer-data-[navigation=true]:pl-12",
56
+ )}
54
57
  >
55
58
  {children ?? <Outlet />}
56
59
  </main>
@@ -0,0 +1,39 @@
1
+ import { UnlinkIcon } from "lucide-react";
2
+ import { Link, useParams } from "react-router-dom";
3
+ import { Callout } from "../ui/Callout.js";
4
+ import { CategoryHeading } from "./CategoryHeading.js";
5
+ import { Heading } from "./Heading.js";
6
+ import { ProseClasses } from "./Markdown.js";
7
+
8
+ export const NotFoundPage = () => {
9
+ const params = useParams();
10
+
11
+ return (
12
+ <div className={ProseClasses + " h-full pt-[--padding-content-top]"}>
13
+ <CategoryHeading>404</CategoryHeading>
14
+ <Heading level={1} className="flex gap-3.5 items-center">
15
+ Page not found
16
+ <UnlinkIcon size={24} />
17
+ </Heading>
18
+ {import.meta.env.DEV && (
19
+ <Callout type="caution" title="Developer hint">
20
+ Start by adding a file at{" "}
21
+ <code>
22
+ {"{PROJECT_ROOT}"}/{params["*"]}.mdx
23
+ </code>{" "}
24
+ and add some content to make this error go away.
25
+ <br />
26
+ <small className="italic">
27
+ Note: This hint is only shown in development mode.
28
+ </small>
29
+ </Callout>
30
+ )}
31
+ <p>
32
+ It seems that the page you are looking for does not exist or may have
33
+ been moved. Please check the URL for any typos or use the navigation
34
+ menu to find the correct page.
35
+ </p>
36
+ <Link to="/">Go back home</Link>
37
+ </div>
38
+ );
39
+ };
@@ -7,25 +7,23 @@ import {
7
7
 
8
8
  import { CheckIcon, CopyIcon } from "lucide-react";
9
9
 
10
- if (!import.meta.env.SSR) {
11
- globalThis.Prism = Prism;
12
- // @ts-expect-error This is untyped
13
- import("prismjs/components/prism-bash.min.js");
14
- // @ts-expect-error This is untyped
15
- import("prismjs/components/prism-ruby.min.js");
16
- // @ts-expect-error This is untyped
17
- import("prismjs/components/prism-markup-templating.js");
18
- // @ts-expect-error This is untyped
19
- import("prismjs/components/prism-php.min.js");
20
- // @ts-expect-error This is untyped
21
- import("prismjs/components/prism-json.min.js");
22
- // @ts-expect-error This is untyped
23
- import("prismjs/components/prism-java.min.js");
24
- // @ts-expect-error This is untyped
25
- import("prismjs/components/prism-csharp.min.js");
26
- // @ts-expect-error This is untyped
27
- import("prismjs/components/prism-objectivec.min.js");
28
- }
10
+ globalThis.Prism = Prism;
11
+ // @ts-expect-error This is untyped
12
+ import("prismjs/components/prism-bash.min.js");
13
+ // @ts-expect-error This is untyped
14
+ import("prismjs/components/prism-ruby.min.js");
15
+ // @ts-expect-error This is untyped
16
+ import("prismjs/components/prism-markup-templating.js");
17
+ // @ts-expect-error This is untyped
18
+ import("prismjs/components/prism-php.min.js");
19
+ // @ts-expect-error This is untyped
20
+ import("prismjs/components/prism-json.min.js");
21
+ // @ts-expect-error This is untyped
22
+ import("prismjs/components/prism-java.min.js");
23
+ // @ts-expect-error This is untyped
24
+ import("prismjs/components/prism-csharp.min.js");
25
+ // @ts-expect-error This is untyped
26
+ import("prismjs/components/prism-objectivec.min.js");
29
27
 
30
28
  import { useState } from "react";
31
29
  import { cn } from "../util/cn.js";
@@ -37,10 +35,12 @@ type SyntaxHighlightProps = {
37
35
  wrapLines?: boolean;
38
36
  copyable?: boolean;
39
37
  showLanguageIndicator?: boolean;
40
- } & Omit<HighlightProps, "children">;
38
+ language?: string;
39
+ } & Omit<HighlightProps, "children" | "language">;
41
40
 
42
41
  export const SyntaxHighlight = ({
43
42
  copyable = true,
43
+ language = "plain",
44
44
  ...props
45
45
  }: SyntaxHighlightProps) => {
46
46
  const [isDark] = useTheme();
@@ -51,7 +51,11 @@ export const SyntaxHighlight = ({
51
51
  }
52
52
 
53
53
  return (
54
- <Highlight theme={isDark ? themes.vsDark : themes.github} {...props}>
54
+ <Highlight
55
+ theme={isDark ? themes.vsDark : themes.github}
56
+ language={language}
57
+ {...props}
58
+ >
55
59
  {({ className, style, tokens, getLineProps, getTokenProps }) => (
56
60
  <pre
57
61
  className={cn(
@@ -88,7 +92,7 @@ export const SyntaxHighlight = ({
88
92
  )}
89
93
  {props.showLanguageIndicator && (
90
94
  <span className="absolute top-1.5 right-3 text-[11px] font-mono text-muted-foreground transition group-hover:opacity-0">
91
- {props.language}
95
+ {language}
92
96
  </span>
93
97
  )}
94
98
  {tokens.map((line, i) => (
@@ -1,12 +1,13 @@
1
- import { useRouteError } from "react-router-dom";
2
- import { Layout } from "../components/Layout.js";
1
+ import { isRouteErrorResponse, useRouteError } from "react-router-dom";
2
+ import { NotFoundPage } from "../components/NotFoundPage.js";
3
3
  import { ErrorAlert } from "./ErrorAlert.js";
4
4
 
5
5
  export function RouterError() {
6
6
  const error = useRouteError();
7
- return (
8
- <Layout>
9
- <ErrorAlert error={error} />
10
- </Layout>
11
- );
7
+
8
+ if (isRouteErrorResponse(error) && error.status === 404) {
9
+ return <NotFoundPage />;
10
+ }
11
+
12
+ return <ErrorAlert error={error} />;
12
13
  }
@@ -0,0 +1,5 @@
1
+ import { ErrorAlert } from "./ErrorAlert.js";
2
+
3
+ export function ServerError({ error }: { error: unknown }) {
4
+ return <ErrorAlert error={error} />;
5
+ }
@@ -1,3 +1,4 @@
1
+ import { GraphQLError } from "graphql/error/index.js";
1
2
  import { OpenAPIV3, type OpenAPIV3_1 } from "openapi-types";
2
3
  import { dereference, type JSONSchema } from "./dereference/index.js";
3
4
  import { upgradeSchema } from "./upgrade/index.js";
@@ -9,10 +10,6 @@ type DeepOmitReference<T> = T extends ReferenceObject
9
10
  ? { [K in keyof T]: DeepOmitReference<T[K]> }
10
11
  : T;
11
12
 
12
- // type Prettify<T> = {
13
- // [K in keyof T]: T[K];
14
- // } & {};
15
-
16
13
  export type OpenAPIDocument = DeepOmitReference<OpenAPIV3_1.Document>;
17
14
  export type ResponseObject = DeepOmitReference<OpenAPIV3_1.ResponseObject>;
18
15
  export type OperationObject = DeepOmitReference<OpenAPIV3_1.OperationObject>;
@@ -46,37 +43,63 @@ export const HttpMethods = Object.values(OpenAPIV3.HttpMethods);
46
43
  // };
47
44
 
48
45
  const parseSchemaInput = async (
49
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
50
- schemaInput: any,
46
+ schemaInput: unknown,
51
47
  ): Promise<JSONSchema & { openapi?: string }> => {
52
48
  if (typeof schemaInput === "string") {
53
49
  if (schemaInput.trim().startsWith("{")) {
54
- return JSON.parse(schemaInput);
50
+ try {
51
+ return JSON.parse(schemaInput);
52
+ } catch (err) {
53
+ throw new GraphQLError("Invalid JSON schema", {
54
+ originalError: err,
55
+ });
56
+ }
55
57
  }
56
58
  if (schemaInput.includes("://")) {
57
- const response = await fetch(schemaInput, {
58
- cache: "force-cache",
59
- });
60
- return (await response.json()) as JSONSchema;
59
+ let response;
60
+ try {
61
+ response = await fetch(schemaInput, {
62
+ cache: "force-cache",
63
+ });
64
+ } catch (err) {
65
+ throw new GraphQLError("Failed to fetch schema", {
66
+ originalError: err,
67
+ });
68
+ }
69
+
70
+ if (!response.ok) {
71
+ throw new GraphQLError(
72
+ `Failed to fetch schema: ${response.statusText}`,
73
+ );
74
+ }
75
+
76
+ try {
77
+ return (await response.json()) as JSONSchema;
78
+ } catch (err) {
79
+ throw new GraphQLError("Fetched invalid JSON schema", {
80
+ originalError: err,
81
+ });
82
+ }
61
83
  }
62
84
  const yaml = await import("yaml");
63
- return yaml.parse(schemaInput);
85
+ const parsed = yaml.parse(schemaInput);
86
+
87
+ if (typeof parsed === "object") return parsed;
64
88
  }
65
89
 
66
- if (typeof schemaInput === "object") return schemaInput;
90
+ if (typeof schemaInput === "object") return schemaInput as JSONSchema;
67
91
 
68
- throw new Error("Unsupported schema input");
92
+ throw new GraphQLError("Unsupported schema input: " + schemaInput);
69
93
  };
70
94
 
71
95
  /**
72
96
  * Validates, dereferences and upgrades the OpenAPI schema (to v3.1) if necessary.
73
97
  */
74
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
75
- export const validate = async (schemaInput: any) => {
98
+ export const validate = async (schemaInput: unknown) => {
76
99
  const schema = await parseSchemaInput(schemaInput);
77
100
 
78
101
  if (!schema.openapi) {
79
- throw new Error("OpenAPI version is not defined");
102
+ throw new GraphQLError("OpenAPI version is not defined");
80
103
  }
81
104
 
82
105
  // const validator = await getValidator(schema.openapi);
@@ -88,9 +111,5 @@ export const validate = async (schemaInput: any) => {
88
111
 
89
112
  const dereferenced = await dereference(schema);
90
113
 
91
- const upgraded = upgradeSchema(
92
- dereferenced as OpenAPIV3_1.Document | OpenAPIV3.Document,
93
- );
94
-
95
- return upgraded;
114
+ return upgradeSchema(dereferenced);
96
115
  };
@@ -1,5 +1,4 @@
1
- import logger from "loglevel";
2
- import { Outlet, useRouteError } from "react-router-dom";
1
+ import { Outlet, type RouteObject } from "react-router-dom";
3
2
  import invariant from "tiny-invariant";
4
3
  import { useAuth } from "../../authentication/hook.js";
5
4
  import { DevPortalContext } from "../../core/DevPortalContext.js";
@@ -7,6 +6,7 @@ import {
7
6
  type ApiIdentityPlugin,
8
7
  type DevPortalPlugin,
9
8
  } from "../../core/plugins.js";
9
+ import { RouterError } from "../../errors/RouterError.js";
10
10
  import { Button } from "../../ui/Button.js";
11
11
  import { CreateApiKey } from "./CreateApiKey.js";
12
12
  import { SettingsApiKeys } from "./SettingsApiKeys.js";
@@ -100,18 +100,6 @@ const ProtectedRoute = () => {
100
100
  );
101
101
  };
102
102
 
103
- const SettingsErrorBoundary = () => {
104
- const error = useRouteError();
105
- logger.error(String(error));
106
-
107
- return (
108
- <div className="flex flex-col justify-center gap-2 items-center h-1/2 my-12">
109
- <h1>Something went wrong</h1>
110
- {error instanceof Error && <p>{error.message}</p>}
111
- </div>
112
- );
113
- };
114
-
115
103
  export const apiKeyPlugin = (
116
104
  options: ApiKeyPluginOptions,
117
105
  ): DevPortalPlugin & ApiIdentityPlugin => {
@@ -138,12 +126,12 @@ export const apiKeyPlugin = (
138
126
  return [];
139
127
  }
140
128
  },
141
- getRoutes: () => {
129
+ getRoutes: (): RouteObject[] => {
142
130
  // TODO: Make lazy
143
131
  return [
144
132
  {
145
133
  element: <ProtectedRoute />,
146
- errorElement: <SettingsErrorBoundary />,
134
+ errorElement: <RouterError />,
147
135
  children: [
148
136
  {
149
137
  path: "/settings/api-keys",
@@ -45,7 +45,7 @@ export const generateRoutes = (
45
45
  },
46
46
  );
47
47
 
48
- const rootRoutes = Array.from(
48
+ const rootRoutes: RouteObject[] = Array.from(
49
49
  new Set(routes.map((route) => route.path.split("/").at(0))),
50
50
  ).map((dir) => ({
51
51
  path: `/${dir}`,
@@ -29,10 +29,6 @@ export type MDXImport = {
29
29
  export const markdownPlugin = ({
30
30
  markdownFiles,
31
31
  defaultOptions,
32
- }: MarkdownPluginOptions): DevPortalPlugin => {
33
- return {
34
- getRoutes() {
35
- return generateRoutes(markdownFiles, defaultOptions);
36
- },
37
- };
38
- };
32
+ }: MarkdownPluginOptions): DevPortalPlugin => ({
33
+ getRoutes: () => generateRoutes(markdownFiles, defaultOptions),
34
+ });
@@ -1,7 +1,11 @@
1
1
  import { ResultOf } from "@graphql-typed-document-node/core";
2
2
  import { CategoryHeading } from "../../components/CategoryHeading.js";
3
+ import { ErrorPage } from "../../components/ErrorPage.js";
3
4
  import { Heading } from "../../components/Heading.js";
5
+ import { InlineCode } from "../../components/InlineCode.js";
4
6
  import { Markdown } from "../../components/Markdown.js";
7
+ import { SyntaxHighlight } from "../../components/SyntaxHighlight.js";
8
+ import { Callout } from "../../ui/Callout.js";
5
9
  import { cn } from "../../util/cn.js";
6
10
  import { OperationListItem } from "./OperationListItem.js";
7
11
  import { useOasConfig } from "./context.js";
@@ -91,6 +95,32 @@ export const OperationList = () => {
91
95
  context: suspenseContext,
92
96
  });
93
97
 
98
+ const error = result.error?.graphQLErrors.at(0);
99
+
100
+ // Looks like there is no Suspense level error handling (yet)?
101
+ // So we handle the error case in the component directly
102
+ if (error) {
103
+ return (
104
+ <ErrorPage
105
+ category="Error"
106
+ title="Schema cannot be displayed"
107
+ message={
108
+ <>
109
+ {import.meta.env.DEV && (
110
+ <Callout type="danger" title="Developer hint" className="mb-4">
111
+ Check your configuration value{" "}
112
+ <InlineCode>apis.type</InlineCode> and{" "}
113
+ <InlineCode>apis.input</InlineCode> in the Zudoku config.
114
+ </Callout>
115
+ )}
116
+ An error occurred while trying to fetch the API reference:
117
+ <SyntaxHighlight code={error.toString()} language="plain" />
118
+ </>
119
+ }
120
+ />
121
+ );
122
+ }
123
+
94
124
  if (!result.data) return null;
95
125
 
96
126
  return (
@@ -1,6 +1,7 @@
1
1
  import { Heading } from "../../components/Heading.js";
2
2
  import { Markdown } from "../../components/Markdown.js";
3
3
  import { Tabs, TabsContent, TabsList, TabsTrigger } from "../../ui/Tabs.js";
4
+ import { groupBy } from "../../util/groupBy.js";
4
5
  import { renderIf } from "../../util/renderIf.js";
5
6
  import { OperationsFragment } from "./OperationList.js";
6
7
  import { ParameterList } from "./ParameterList.js";
@@ -18,10 +19,11 @@ export const OperationListItem = ({
18
19
  operationFragment: FragmentType<typeof OperationsFragment>;
19
20
  }) => {
20
21
  const operation = useFragment(OperationsFragment, operationFragment);
21
- const groupedParameters = Object.groupBy(
22
+ const groupedParameters = groupBy(
22
23
  operation.parameters ?? [],
23
24
  (param) => param.in,
24
25
  );
26
+
25
27
  const first = operation.responses.at(0);
26
28
  return (
27
29
  <div
@@ -1,5 +1,6 @@
1
1
  import { Markdown } from "../../components/Markdown.js";
2
2
  import { SchemaObject } from "../../oas/parser/index.js";
3
+ import { groupBy } from "../../util/groupBy.js";
3
4
  import { objectEntries } from "../../util/objectEntries.js";
4
5
  import { SchemaListViewItemGroup } from "./SchemaListViewItemGroup.js";
5
6
  import { SchemaProseClasses } from "./util/prose.js";
@@ -25,16 +26,13 @@ export const SchemaListView = ({
25
26
  Array.isArray(additionalProperties) ? additionalProperties : [],
26
27
  );
27
28
 
28
- const groups = Object.groupBy(
29
- combinedProperties,
30
- ([propertyName, property]) => {
31
- return property.deprecated
32
- ? "deprecated"
33
- : schema.required?.includes(propertyName)
34
- ? "required"
35
- : "optional";
36
- },
37
- );
29
+ const groups = groupBy(combinedProperties, ([propertyName, property]) => {
30
+ return property.deprecated
31
+ ? "deprecated"
32
+ : schema.required?.includes(propertyName)
33
+ ? "required"
34
+ : "optional";
35
+ });
38
36
 
39
37
  return (
40
38
  <div className="flex flex-col gap-2.5">
@@ -25,7 +25,7 @@ export const createClient: CreateClientFunction = () => {
25
25
  fetch: async (req, init) => {
26
26
  if (!init?.body) throw new Error("No body");
27
27
  const response = await localServer.fetch(
28
- new Request("/__z/graphql", {
28
+ new Request("http://localhost/__z/graphql", {
29
29
  method: "POST",
30
30
  body: init.body,
31
31
  headers: {
@@ -1,4 +1,4 @@
1
- import { matchPath, type RouteObject } from "react-router-dom";
1
+ import { matchPath, useRouteError, type RouteObject } from "react-router-dom";
2
2
  import {
3
3
  type DevPortalPlugin,
4
4
  type PluginNavigationCategory,
@@ -12,6 +12,8 @@ import {
12
12
  } from "./util/urql.js";
13
13
 
14
14
  import { createClient } from "virtual:zudoku-openapi-worker";
15
+ import { ErrorPage } from "../../components/ErrorPage.js";
16
+ import { SyntaxHighlight } from "../../components/SyntaxHighlight.js";
15
17
  import { OasPluginConfig } from "./interfaces.js";
16
18
 
17
19
  const GetCategoriesQuery = graphql(`
@@ -34,6 +36,20 @@ const GetCategoriesQuery = graphql(`
34
36
  }
35
37
  `);
36
38
 
39
+ const OpenApiErrorPage = () => {
40
+ const error = useRouteError();
41
+ const message =
42
+ error instanceof Error ? (
43
+ <SyntaxHighlight code={error.message} />
44
+ ) : (
45
+ "An unknown error occurred"
46
+ );
47
+
48
+ return (
49
+ <ErrorPage category="Error" title="An error occurred" message={message} />
50
+ );
51
+ };
52
+
37
53
  export const openApiPlugin = (config: OasPluginConfig): DevPortalPlugin => {
38
54
  const basePath = config.path ?? "/reference";
39
55
 
@@ -112,6 +128,7 @@ export const openApiPlugin = (config: OasPluginConfig): DevPortalPlugin => {
112
128
  element: <OpenApiRoute client={client} config={config} />,
113
129
  };
114
130
  },
131
+ errorElement: <OpenApiErrorPage />,
115
132
  children: [
116
133
  {
117
134
  path: basePath,
@@ -5,6 +5,7 @@ import {
5
5
  useFieldArray,
6
6
  useFormContext,
7
7
  } from "react-hook-form";
8
+ import { cn } from "../../../util/cn.js";
8
9
  import { InlineInput } from "./InlineInput.js";
9
10
  import type { PlaygroundForm } from "./Playground.js";
10
11
 
@@ -73,7 +74,11 @@ export const QueryParams = ({
73
74
  render={({ field }) => {
74
75
  return (
75
76
  <button
76
- className="hover:bg-black/5 p-1 rounded mr-2 text-muted-foreground invisible group-hover:visible peer-focus:visible"
77
+ type="button"
78
+ className={cn(
79
+ "hover:bg-black/5 p-1 rounded mr-2 text-muted-foreground invisible group-hover:visible peer-focus:visible",
80
+ field.value.length === 0 && "opacity-0 pointer-events-none",
81
+ )}
77
82
  onClick={() => field.onChange("")}
78
83
  >
79
84
  <XIcon size={16} />
@@ -1,4 +1,4 @@
1
- import { Navigate } from "react-router-dom";
1
+ import { redirect } from "react-router-dom";
2
2
  import type { DevPortalPlugin } from "../../core/plugins.js";
3
3
 
4
4
  export type Redirect = {
@@ -14,7 +14,7 @@ export const redirectPlugin = (options: {
14
14
  getRoutes: () =>
15
15
  options.redirects.map(({ from, to, replace }) => ({
16
16
  path: from,
17
- element: <Navigate to={to} replace={replace} />,
17
+ loader: () => redirect(to),
18
18
  })),
19
19
  };
20
20
  };
@@ -64,9 +64,9 @@ export const Callout = ({ type, children, title, className }: CalloutProps) => {
64
64
  return (
65
65
  <div
66
66
  className={cn(
67
- "not-prose grid grid-cols-[fit-content_1fr] grid-rows-[fit-content_1fr] gap-x-4 gap-y-2 text-md rounded-md border p-4",
67
+ "not-prose grid grid-cols-[min-content_1fr] grid-rows-[fit-content_1fr] gap-x-4 gap-y-2 text-md rounded-md border p-4",
68
68
  "[&_a]:underline [&_a]:decoration-current [&_a]:decoration-from-font [&_a]:underline-offset-4 hover:[&_a]:decoration-1",
69
- "[&_code]:!bg-transparent [&_code]:!border-none",
69
+ "[&_code]:!bg-gray-50 [&_code]:dark:!bg-gray-800 [&_code]:!border-none",
70
70
  title && "items-center",
71
71
  border,
72
72
  bg,
@@ -2,9 +2,9 @@ import { MDXProvider } from "@mdx-js/react";
2
2
  import type { ComponentProps } from "react";
3
3
  import { Link } from "react-router-dom";
4
4
  import { Heading } from "../components/Heading.js";
5
+ import { InlineCode } from "../components/InlineCode.js";
5
6
  import { SyntaxHighlight } from "../components/SyntaxHighlight.js";
6
7
  import { Callout } from "../ui/Callout.js";
7
- import { cn } from "./cn.js";
8
8
 
9
9
  export type MdxComponentsType = ComponentProps<
10
10
  typeof MDXProvider
@@ -80,15 +80,6 @@ export const MdxComponents = {
80
80
  );
81
81
  }
82
82
 
83
- return (
84
- <code
85
- className={cn(
86
- className,
87
- "font-mono border border-border p-1 py-0.5 rounded bg-border/50 dark:bg-border/70 whitespace-nowrap",
88
- )}
89
- >
90
- {children}
91
- </code>
92
- );
83
+ return <InlineCode className={className}>{children}</InlineCode>;
93
84
  },
94
85
  } satisfies MdxComponentsType;
@@ -1,24 +1,19 @@
1
- type MapValuesToKeysIfAllowed<T> = {
2
- [K in keyof T]: T[K] extends PropertyKey ? K : never;
3
- };
4
- type Filter<T> = MapValuesToKeysIfAllowed<T>[keyof T];
5
-
6
1
  export const groupBy = <
7
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
8
2
  T extends Record<PropertyKey, any>,
9
- Key extends Filter<T>,
3
+ KeySelector extends (item: T) => PropertyKey,
10
4
  >(
11
5
  arr: T[],
12
- key: Key,
13
- ): Record<T[Key], T[]> =>
14
- arr.reduce(
6
+ keySelector: KeySelector,
7
+ ): Partial<Record<ReturnType<KeySelector>, T[]>> => {
8
+ return arr.reduce(
15
9
  (accumulator, val) => {
16
- const groupedKey = val[key];
10
+ const groupedKey = keySelector(val) as ReturnType<KeySelector>;
17
11
  if (!accumulator[groupedKey]) {
18
12
  accumulator[groupedKey] = [];
19
13
  }
20
14
  accumulator[groupedKey].push(val);
21
15
  return accumulator;
22
16
  },
23
- {} as Record<T[Key], T[]>,
17
+ {} as Record<ReturnType<KeySelector>, T[]>,
24
18
  );
19
+ };
@@ -1,4 +0,0 @@
1
- import { DevPortalPlugin } from "../core/plugins.js";
2
- export declare function Router({ plugins }: {
3
- plugins?: DevPortalPlugin[];
4
- }): import("react/jsx-runtime").JSX.Element;
@@ -1,21 +0,0 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import { useMemo } from "react";
3
- import { createBrowserRouter, RouterProvider } from "react-router-dom";
4
- import { isNavigationPlugin } from "../core/plugins.js";
5
- import { RouterError } from "../errors/RouterError.js";
6
- import { Layout } from "./Layout.js";
7
- export function Router({ plugins }) {
8
- const router = useMemo(() => {
9
- const routes = (plugins ?? []).flatMap((plugin) => isNavigationPlugin(plugin) ? plugin.getRoutes() : []);
10
- return createBrowserRouter([
11
- {
12
- path: "/",
13
- element: _jsx(Layout, {}),
14
- errorElement: _jsx(RouterError, {}),
15
- children: routes,
16
- },
17
- ]);
18
- }, [plugins]);
19
- return _jsx(RouterProvider, { router: router });
20
- }
21
- //# sourceMappingURL=Router.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"Router.js","sourceRoot":"","sources":["../../../src/lib/components/Router.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAChC,OAAO,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AACvE,OAAO,EAAmB,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAEzE,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,MAAM,UAAU,MAAM,CAAC,EAAE,OAAO,EAAmC;IACjE,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,EAAE;QAC1B,MAAM,MAAM,GAAG,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,EAAE,CAChD,kBAAkB,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CACrD,CAAC;QAEF,OAAO,mBAAmB,CAAC;YACzB;gBACE,IAAI,EAAE,GAAG;gBACT,OAAO,EAAE,KAAC,MAAM,KAAG;gBACnB,YAAY,EAAE,KAAC,WAAW,KAAG;gBAC7B,QAAQ,EAAE,MAAM;aACjB;SACF,CAAC,CAAC;IACL,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IACd,OAAO,KAAC,cAAc,IAAC,MAAM,EAAE,MAAM,GAAI,CAAC;AAC5C,CAAC"}