zudoku 0.3.0-dev.31 → 0.3.0-dev.32

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 (203) 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 +5 -0
  5. package/dist/app/entry.client.js +28 -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/redirect/index.js +2 -3
  67. package/dist/lib/plugins/redirect/index.js.map +1 -1
  68. package/dist/lib/ui/Callout.js +1 -1
  69. package/dist/lib/ui/Callout.js.map +1 -1
  70. package/dist/lib/ui/button-variants.d.ts +1 -1
  71. package/dist/lib/util/MdxComponents.js +2 -2
  72. package/dist/lib/util/MdxComponents.js.map +1 -1
  73. package/dist/lib/util/groupBy.d.ts +1 -6
  74. package/dist/lib/util/groupBy.js +10 -8
  75. package/dist/lib/util/groupBy.js.map +1 -1
  76. package/dist/vite/build.js +23 -10
  77. package/dist/vite/build.js.map +1 -1
  78. package/dist/vite/config.d.ts +2 -1
  79. package/dist/vite/config.js +33 -7
  80. package/dist/vite/config.js.map +1 -1
  81. package/dist/vite/dev-server.d.ts +1 -1
  82. package/dist/vite/dev-server.js +15 -9
  83. package/dist/vite/dev-server.js.map +1 -1
  84. package/dist/vite/html.js +5 -4
  85. package/dist/vite/html.js.map +1 -1
  86. package/dist/vite/plugin-custom-css.d.ts +6 -0
  87. package/dist/vite/plugin-custom-css.js +55 -0
  88. package/dist/vite/plugin-custom-css.js.map +1 -0
  89. package/dist/vite/plugin-docs.js +14 -5
  90. package/dist/vite/plugin-docs.js.map +1 -1
  91. package/dist/vite/plugin-openapi-worker.js +4 -1
  92. package/dist/vite/plugin-openapi-worker.js.map +1 -1
  93. package/dist/vite/plugin.js +2 -0
  94. package/dist/vite/plugin.js.map +1 -1
  95. package/dist/vite/prerender.d.ts +1 -0
  96. package/dist/vite/prerender.js +57 -0
  97. package/dist/vite/prerender.js.map +1 -0
  98. package/lib/{DevPortalProvider-BMk-RCE0.js → DevPortalProvider-BlxLX6GG.js} +230 -250
  99. package/lib/DevPortalProvider-BlxLX6GG.js.map +1 -0
  100. package/lib/{Markdown-DDmW47R9.js → Markdown-CL8KPvJN.js} +8 -9
  101. package/lib/{Markdown-DDmW47R9.js.map → Markdown-CL8KPvJN.js.map} +1 -1
  102. package/lib/MdxComponents-Ev_hBHb2.js +5885 -0
  103. package/lib/MdxComponents-Ev_hBHb2.js.map +1 -0
  104. package/lib/{MdxPage-DyJAHF9y.js → MdxPage-Z3HKNTrj.js} +92 -89
  105. package/lib/MdxPage-Z3HKNTrj.js.map +1 -0
  106. package/lib/{OperationList-Dz9rHM9r.js → OperationList-KoITgfDT.js} +1967 -1785
  107. package/lib/OperationList-KoITgfDT.js.map +1 -0
  108. package/lib/Route-Bf1_D_vC.js +13 -0
  109. package/lib/{Route-CN_7-e5r.js.map → Route-Bf1_D_vC.js.map} +1 -1
  110. package/lib/Select-DSa3bN4t.js +4770 -0
  111. package/lib/Select-DSa3bN4t.js.map +1 -0
  112. package/lib/assets/{worker-BXS8hiSM.js → worker-BjPv-hjP.js} +3100 -2720
  113. package/lib/assets/worker-BjPv-hjP.js.map +1 -0
  114. package/lib/hook-CTmJ6CWq.js +35 -0
  115. package/lib/hook-CTmJ6CWq.js.map +1 -0
  116. package/lib/index-BdWBDosx.js +74 -0
  117. package/lib/index-BdWBDosx.js.map +1 -0
  118. package/lib/{index-Cpdpun6t.js → index-BoWzKb_9.js} +57 -41
  119. package/lib/index-BoWzKb_9.js.map +1 -0
  120. package/lib/{AnchorLink-ptdQk87q.js → index.esm-CPEExBJE.js} +156 -168
  121. package/lib/index.esm-CPEExBJE.js.map +1 -0
  122. package/lib/jsx-runtime-CM0TzjGp.js +866 -0
  123. package/lib/jsx-runtime-CM0TzjGp.js.map +1 -0
  124. package/lib/mutation-91kw0lHb.js +208 -0
  125. package/lib/mutation-91kw0lHb.js.map +1 -0
  126. package/lib/router-CcYTwKjf.js +183 -0
  127. package/lib/router-CcYTwKjf.js.map +1 -0
  128. package/lib/zudoku.auth-clerk.js.map +1 -1
  129. package/lib/zudoku.auth-openid.js +588 -441
  130. package/lib/zudoku.auth-openid.js.map +1 -1
  131. package/lib/zudoku.components.js +284 -595
  132. package/lib/zudoku.components.js.map +1 -1
  133. package/lib/zudoku.openapi-worker.js +18 -18
  134. package/lib/zudoku.plugin-api-keys.js +143 -98
  135. package/lib/zudoku.plugin-api-keys.js.map +1 -1
  136. package/lib/zudoku.plugin-markdown.js +2 -49
  137. package/lib/zudoku.plugin-markdown.js.map +1 -1
  138. package/lib/zudoku.plugin-openapi.js +5 -3
  139. package/lib/zudoku.plugin-openapi.js.map +1 -1
  140. package/lib/zudoku.plugin-redirect.js +6 -7
  141. package/lib/zudoku.plugin-redirect.js.map +1 -1
  142. package/package.json +2 -1
  143. package/src/app/App.tsx +0 -0
  144. package/src/app/entry.client.tsx +51 -0
  145. package/src/app/entry.server.tsx +158 -0
  146. package/src/app/main.tsx +65 -43
  147. package/src/app/tailwind.ts +6 -0
  148. package/src/app/zudoku-manifest.ts +22 -0
  149. package/src/lib/authentication/providers/clerk.tsx +1 -0
  150. package/src/lib/components/DevPortal.tsx +25 -33
  151. package/src/lib/components/ErrorPage.tsx +28 -0
  152. package/src/lib/components/InlineCode.tsx +19 -0
  153. package/src/lib/components/Layout.tsx +7 -4
  154. package/src/lib/components/NotFoundPage.tsx +39 -0
  155. package/src/lib/components/SyntaxHighlight.tsx +26 -22
  156. package/src/lib/errors/RouterError.tsx +8 -7
  157. package/src/lib/errors/ServerError.tsx +5 -0
  158. package/src/lib/oas/parser/index.ts +41 -22
  159. package/src/lib/plugins/api-keys/index.tsx +4 -16
  160. package/src/lib/plugins/markdown/generateRoutes.tsx +1 -1
  161. package/src/lib/plugins/markdown/index.tsx +3 -7
  162. package/src/lib/plugins/openapi/OperationList.tsx +30 -0
  163. package/src/lib/plugins/openapi/OperationListItem.tsx +3 -1
  164. package/src/lib/plugins/openapi/SchemaListView.tsx +8 -10
  165. package/src/lib/plugins/openapi/client/createMemoryClient.ts +1 -1
  166. package/src/lib/plugins/openapi/index.tsx +18 -1
  167. package/src/lib/plugins/redirect/index.tsx +2 -2
  168. package/src/lib/ui/Callout.tsx +2 -2
  169. package/src/lib/util/MdxComponents.tsx +2 -11
  170. package/src/lib/util/groupBy.ts +7 -12
  171. package/dist/lib/components/Router.d.ts +0 -4
  172. package/dist/lib/components/Router.js +0 -21
  173. package/dist/lib/components/Router.js.map +0 -1
  174. package/lib/AnchorLink-ptdQk87q.js.map +0 -1
  175. package/lib/DevPortalProvider-BMk-RCE0.js.map +0 -1
  176. package/lib/MdxComponents-C0R6zobS.js +0 -3019
  177. package/lib/MdxComponents-C0R6zobS.js.map +0 -1
  178. package/lib/MdxPage-DyJAHF9y.js.map +0 -1
  179. package/lib/OperationList-Dz9rHM9r.js.map +0 -1
  180. package/lib/Route-CN_7-e5r.js +0 -14
  181. package/lib/Select-D-Jtx53Q.js +0 -4572
  182. package/lib/Select-D-Jtx53Q.js.map +0 -1
  183. package/lib/Spinner-BG1JnYy0.js +0 -182
  184. package/lib/Spinner-BG1JnYy0.js.map +0 -1
  185. package/lib/assets/worker-BXS8hiSM.js.map +0 -1
  186. package/lib/cn-DpqTslo9.js +0 -2342
  187. package/lib/cn-DpqTslo9.js.map +0 -1
  188. package/lib/hook-BzBeIPL4.js +0 -25
  189. package/lib/hook-BzBeIPL4.js.map +0 -1
  190. package/lib/index-BaOOUFsA.js +0 -412
  191. package/lib/index-BaOOUFsA.js.map +0 -1
  192. package/lib/index-CPvRaBBB.js +0 -713
  193. package/lib/index-CPvRaBBB.js.map +0 -1
  194. package/lib/index-Cpdpun6t.js.map +0 -1
  195. package/lib/index-DLS6fPwU.js +0 -464
  196. package/lib/index-DLS6fPwU.js.map +0 -1
  197. package/lib/jsx-runtime-SV6hXQua.js +0 -3009
  198. package/lib/jsx-runtime-SV6hXQua.js.map +0 -1
  199. package/lib/loglevel-CA34MiFn.js +0 -153
  200. package/lib/loglevel-CA34MiFn.js.map +0 -1
  201. package/lib/util-CCWvaWo7.js +0 -41
  202. package/lib/util-CCWvaWo7.js.map +0 -1
  203. package/src/lib/components/Router.tsx +0 -24
@@ -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,
@@ -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"}