zudoku 0.10.0 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (164) hide show
  1. package/README.md +121 -0
  2. package/dist/config/config.d.ts +2 -6
  3. package/dist/config/validators/InputSidebarSchema.d.ts +1 -0
  4. package/dist/config/validators/validate.d.ts +151 -37
  5. package/dist/config/validators/validate.js +14 -11
  6. package/dist/config/validators/validate.js.map +1 -1
  7. package/dist/index.d.ts +1 -1
  8. package/dist/lib/authentication/state.d.ts +16 -0
  9. package/dist/lib/authentication/state.js +5 -0
  10. package/dist/lib/authentication/state.js.map +1 -1
  11. package/dist/lib/components/ErrorPage.js +1 -2
  12. package/dist/lib/components/ErrorPage.js.map +1 -1
  13. package/dist/lib/components/InlineCode.d.ts +2 -1
  14. package/dist/lib/components/InlineCode.js +9 -1
  15. package/dist/lib/components/InlineCode.js.map +1 -1
  16. package/dist/lib/components/Layout.js +1 -1
  17. package/dist/lib/components/Layout.js.map +1 -1
  18. package/dist/lib/oas/graphql/index.d.ts +2 -1
  19. package/dist/lib/oas/graphql/index.js +22 -10
  20. package/dist/lib/oas/graphql/index.js.map +1 -1
  21. package/dist/lib/oas/parser/index.d.ts +1 -0
  22. package/dist/lib/oas/parser/index.js.map +1 -1
  23. package/dist/lib/plugins/markdown/MdxPage.js +2 -2
  24. package/dist/lib/plugins/markdown/MdxPage.js.map +1 -1
  25. package/dist/lib/plugins/markdown/generateRoutes.d.ts +1 -1
  26. package/dist/lib/plugins/markdown/generateRoutes.js +8 -6
  27. package/dist/lib/plugins/markdown/generateRoutes.js.map +1 -1
  28. package/dist/lib/plugins/markdown/index.d.ts +2 -1
  29. package/dist/lib/plugins/markdown/index.js +2 -2
  30. package/dist/lib/plugins/markdown/index.js.map +1 -1
  31. package/dist/lib/plugins/openapi/Endpoint.d.ts +1 -3
  32. package/dist/lib/plugins/openapi/Endpoint.js +46 -8
  33. package/dist/lib/plugins/openapi/Endpoint.js.map +1 -1
  34. package/dist/lib/plugins/openapi/OperationList.js +1 -1
  35. package/dist/lib/plugins/openapi/OperationList.js.map +1 -1
  36. package/dist/lib/plugins/openapi/OperationListItem.js +1 -1
  37. package/dist/lib/plugins/openapi/OperationListItem.js.map +1 -1
  38. package/dist/lib/plugins/openapi/PlaygroundDialogWrapper.d.ts +2 -1
  39. package/dist/lib/plugins/openapi/PlaygroundDialogWrapper.js +2 -2
  40. package/dist/lib/plugins/openapi/PlaygroundDialogWrapper.js.map +1 -1
  41. package/dist/lib/plugins/openapi/Sidecar.js +14 -3
  42. package/dist/lib/plugins/openapi/Sidecar.js.map +1 -1
  43. package/dist/lib/plugins/openapi/SimpleSelect.d.ts +2 -1
  44. package/dist/lib/plugins/openapi/SimpleSelect.js +1 -1
  45. package/dist/lib/plugins/openapi/SimpleSelect.js.map +1 -1
  46. package/dist/lib/plugins/openapi/graphql/gql.d.ts +10 -2
  47. package/dist/lib/plugins/openapi/graphql/gql.js +2 -1
  48. package/dist/lib/plugins/openapi/graphql/gql.js.map +1 -1
  49. package/dist/lib/plugins/openapi/graphql/graphql.d.ts +29 -3
  50. package/dist/lib/plugins/openapi/graphql/graphql.js +87 -0
  51. package/dist/lib/plugins/openapi/graphql/graphql.js.map +1 -1
  52. package/dist/lib/plugins/openapi/interfaces.d.ts +3 -0
  53. package/dist/lib/plugins/openapi/playground/Playground.d.ts +2 -1
  54. package/dist/lib/plugins/openapi/playground/Playground.js +13 -5
  55. package/dist/lib/plugins/openapi/playground/Playground.js.map +1 -1
  56. package/dist/lib/plugins/openapi/playground/ResponseTab.js +1 -1
  57. package/dist/lib/plugins/openapi/playground/ResponseTab.js.map +1 -1
  58. package/dist/lib/plugins/openapi/playground/createUrl.js +3 -1
  59. package/dist/lib/plugins/openapi/playground/createUrl.js.map +1 -1
  60. package/dist/vite/config.d.ts +1 -1
  61. package/dist/vite/config.js +19 -15
  62. package/dist/vite/config.js.map +1 -1
  63. package/dist/vite/dev-server.d.ts +1 -0
  64. package/dist/vite/dev-server.js +7 -13
  65. package/dist/vite/dev-server.js.map +1 -1
  66. package/dist/vite/plugin-api.js +4 -7
  67. package/dist/vite/plugin-api.js.map +1 -1
  68. package/dist/vite/plugin-config-reload.js +9 -4
  69. package/dist/vite/plugin-config-reload.js.map +1 -1
  70. package/dist/vite/plugin-docs.js +7 -5
  71. package/dist/vite/plugin-docs.js.map +1 -1
  72. package/dist/vite/plugin-frontmatter.d.ts +2 -0
  73. package/dist/vite/plugin-frontmatter.js +30 -0
  74. package/dist/vite/plugin-frontmatter.js.map +1 -0
  75. package/dist/vite/plugin-sidebar.js +14 -1
  76. package/dist/vite/plugin-sidebar.js.map +1 -1
  77. package/dist/vite/plugin.js +2 -2
  78. package/dist/vite/plugin.js.map +1 -1
  79. package/lib/{CategoryHeading-XnFqN2lJ.js → CategoryHeading-ovR-zHRq.js} +2 -2
  80. package/lib/{CategoryHeading-XnFqN2lJ.js.map → CategoryHeading-ovR-zHRq.js.map} +1 -1
  81. package/lib/{DeveloperHint-FBb2uXJe.js → DeveloperHint-YeWHKvyr.js} +2 -2
  82. package/lib/{DeveloperHint-FBb2uXJe.js.map → DeveloperHint-YeWHKvyr.js.map} +1 -1
  83. package/lib/ErrorPage-CsZAN_za.js +16 -0
  84. package/lib/ErrorPage-CsZAN_za.js.map +1 -0
  85. package/lib/{Input-BEDZAKw0.js → Input-CtVUl3eT.js} +3 -3
  86. package/lib/{Input-BEDZAKw0.js.map → Input-CtVUl3eT.js.map} +1 -1
  87. package/lib/{Markdown-B4aR03g6.js → Markdown-DapSf3wG.js} +795 -793
  88. package/lib/Markdown-DapSf3wG.js.map +1 -0
  89. package/lib/{MdxPage-BZyQsH8Z.js → MdxPage-BqBWsXZ1.js} +23 -23
  90. package/lib/MdxPage-BqBWsXZ1.js.map +1 -0
  91. package/lib/{OperationList-2NeWEM0u.js → OperationList-CYrmxPa8.js} +151 -109
  92. package/lib/OperationList-CYrmxPa8.js.map +1 -0
  93. package/lib/{Route-BZPewmrN.js → Route-Q5mqNQrv.js} +2 -2
  94. package/lib/{Route-BZPewmrN.js.map → Route-Q5mqNQrv.js.map} +1 -1
  95. package/lib/{SidebarBadge-COz0hgfa.js → SidebarBadge-Dx7jtnoA.js} +3 -3
  96. package/lib/{SidebarBadge-COz0hgfa.js.map → SidebarBadge-Dx7jtnoA.js.map} +1 -1
  97. package/lib/{SlotletProvider-DJMaOUDs.js → SlotletProvider-D3UD5Go3.js} +4 -4
  98. package/lib/{SlotletProvider-DJMaOUDs.js.map → SlotletProvider-D3UD5Go3.js.map} +1 -1
  99. package/lib/assets/{worker-BvD7B6MG.js → worker-Bcj4NA2p.js} +3430 -1351
  100. package/lib/assets/worker-Bcj4NA2p.js.map +1 -0
  101. package/lib/{index-Dv2KZuEw.js → index-BlJ2rj99.js} +1774 -1644
  102. package/lib/index-BlJ2rj99.js.map +1 -0
  103. package/lib/index-Bn6Lc9tq.js +9 -0
  104. package/lib/index-Bn6Lc9tq.js.map +1 -0
  105. package/lib/{index-1EDgIO6b.js → index-BngPzhKn.js} +3 -3
  106. package/lib/{index-1EDgIO6b.js.map → index-BngPzhKn.js.map} +1 -1
  107. package/lib/{index-Zezcv0xb.js → index-Dolisrci.js} +3 -3
  108. package/lib/{index-Zezcv0xb.js.map → index-Dolisrci.js.map} +1 -1
  109. package/lib/index-LNp6rxyU.js +2094 -0
  110. package/lib/index-LNp6rxyU.js.map +1 -0
  111. package/lib/state-hNe1dw4B.js +548 -0
  112. package/lib/state-hNe1dw4B.js.map +1 -0
  113. package/lib/zudoku.auth-auth0.js +1 -1
  114. package/lib/zudoku.auth-clerk.js +1 -1
  115. package/lib/zudoku.auth-openid.js +4 -4
  116. package/lib/zudoku.components.js +6 -6
  117. package/lib/zudoku.components.js.map +1 -1
  118. package/lib/zudoku.openapi-worker.js +497 -489
  119. package/lib/zudoku.openapi-worker.js.map +1 -1
  120. package/lib/zudoku.plugin-api-keys.js +5 -5
  121. package/lib/zudoku.plugin-custom-page.js +1 -1
  122. package/lib/zudoku.plugin-markdown.js +18 -15
  123. package/lib/zudoku.plugin-markdown.js.map +1 -1
  124. package/lib/zudoku.plugin-openapi.js +4 -4
  125. package/package.json +14 -4
  126. package/src/lib/authentication/state.ts +17 -0
  127. package/src/lib/components/ErrorPage.tsx +0 -2
  128. package/src/lib/components/InlineCode.tsx +10 -0
  129. package/src/lib/components/Layout.tsx +1 -1
  130. package/src/lib/oas/graphql/index.ts +33 -13
  131. package/src/lib/oas/parser/index.ts +1 -0
  132. package/src/lib/plugins/markdown/MdxPage.tsx +2 -2
  133. package/src/lib/plugins/markdown/generateRoutes.tsx +8 -5
  134. package/src/lib/plugins/markdown/index.tsx +3 -1
  135. package/src/lib/plugins/openapi/Endpoint.tsx +86 -22
  136. package/src/lib/plugins/openapi/OperationList.tsx +3 -1
  137. package/src/lib/plugins/openapi/OperationListItem.tsx +1 -1
  138. package/src/lib/plugins/openapi/PlaygroundDialogWrapper.tsx +3 -0
  139. package/src/lib/plugins/openapi/Sidecar.tsx +17 -2
  140. package/src/lib/plugins/openapi/SimpleSelect.tsx +10 -2
  141. package/src/lib/plugins/openapi/graphql/gql.ts +11 -3
  142. package/src/lib/plugins/openapi/graphql/graphql.ts +116 -4
  143. package/src/lib/plugins/openapi/interfaces.ts +4 -1
  144. package/src/lib/plugins/openapi/playground/Playground.tsx +39 -5
  145. package/src/lib/plugins/openapi/playground/ResponseTab.tsx +0 -1
  146. package/src/lib/plugins/openapi/playground/createUrl.ts +6 -1
  147. package/dist/lib/util/slugify.d.ts +0 -2
  148. package/dist/lib/util/slugify.js +0 -3
  149. package/dist/lib/util/slugify.js.map +0 -1
  150. package/dist/vite/plugin-icons.d.ts +0 -3
  151. package/dist/vite/plugin-icons.js +0 -47
  152. package/dist/vite/plugin-icons.js.map +0 -1
  153. package/lib/ErrorPage-knunPbKI.js +0 -18
  154. package/lib/ErrorPage-knunPbKI.js.map +0 -1
  155. package/lib/Markdown-B4aR03g6.js.map +0 -1
  156. package/lib/MdxPage-BZyQsH8Z.js.map +0 -1
  157. package/lib/OperationList-2NeWEM0u.js.map +0 -1
  158. package/lib/assets/worker-BvD7B6MG.js.map +0 -1
  159. package/lib/index-Dv2KZuEw.js.map +0 -1
  160. package/lib/slugify-DbLhpSPt.js +0 -28
  161. package/lib/slugify-DbLhpSPt.js.map +0 -1
  162. package/lib/state-lIwt9isb.js +0 -288
  163. package/lib/state-lIwt9isb.js.map +0 -1
  164. package/src/lib/util/slugify.ts +0 -3
@@ -1,13 +1,13 @@
1
1
  import { j as e } from "./jsx-runtime-B6kdoens.js";
2
- import { S as x, R as f } from "./SlotletProvider-DJMaOUDs.js";
3
- import { u as g, a as d, I as j, S as v, b as w, c as b, d as k, e as K, f as m } from "./Input-BEDZAKw0.js";
2
+ import { S as x, R as f } from "./SlotletProvider-D3UD5Go3.js";
3
+ import { u as g, a as d, I as j, S as v, b as w, c as b, d as k, e as K, f as m } from "./Input-CtVUl3eT.js";
4
4
  import { a as N, L as u, O as I } from "./index-BG0g4WW0.js";
5
5
  import { u as h, a as E, b as S } from "./ZudokuContext-cr-pTRY1.js";
6
- import { B as l, m as A } from "./index-Zezcv0xb.js";
7
- import { D as C } from "./DeveloperHint-FBb2uXJe.js";
6
+ import { B as l, m as A } from "./index-Dolisrci.js";
7
+ import { D as C } from "./DeveloperHint-YeWHKvyr.js";
8
8
  import { RotateCwIcon as P, TrashIcon as D, EyeOffIcon as R, EyeIcon as q, CheckIcon as O, CopyIcon as z } from "lucide-react";
9
9
  import { useState as p } from "react";
10
- import { a as T } from "./Markdown-B4aR03g6.js";
10
+ import { a as T } from "./Markdown-DapSf3wG.js";
11
11
  function c(t, s) {
12
12
  if (t)
13
13
  return;
@@ -1,5 +1,5 @@
1
1
  import { j as m } from "./jsx-runtime-B6kdoens.js";
2
- import { P as o } from "./Markdown-B4aR03g6.js";
2
+ import { P as o } from "./Markdown-DapSf3wG.js";
3
3
  const l = (s) => ({
4
4
  getRoutes: () => s.map(({ path: e, element: t }) => ({
5
5
  path: e,
@@ -1,29 +1,32 @@
1
- import { j as c } from "./jsx-runtime-B6kdoens.js";
2
- const i = (t, e) => Object.entries(t).flatMap(([a, s]) => {
3
- const n = a.match(/pages\/(.*).mdx?$/), o = n == null ? void 0 : n.at(1);
4
- return o ? {
5
- path: o,
1
+ import { j as u } from "./jsx-runtime-B6kdoens.js";
2
+ const x = (t, e, n) => Object.entries(t).flatMap(([a, p]) => {
3
+ let o = e.split("**")[0];
4
+ o = o.replace("/**", "/");
5
+ const c = new RegExp(`^${o}(.*).mdx?`), r = a.match(c), s = r == null ? void 0 : r.at(1);
6
+ return s ? {
7
+ path: s,
6
8
  lazy: async () => {
7
- const { MdxPage: r } = await import("./MdxPage-BZyQsH8Z.js"), { default: p, ...m } = await s();
9
+ const { MdxPage: i } = await import("./MdxPage-BqBWsXZ1.js"), { default: m, ...l } = await p();
8
10
  return {
9
- element: /* @__PURE__ */ c.jsx(
10
- r,
11
+ element: /* @__PURE__ */ u.jsx(
12
+ i,
11
13
  {
12
- mdxComponent: p,
13
- ...m,
14
- defaultOptions: e
14
+ mdxComponent: m,
15
+ ...l,
16
+ defaultOptions: n
15
17
  }
16
18
  )
17
19
  };
18
20
  }
19
21
  } : [];
20
- }), x = ({
22
+ }), f = ({
21
23
  markdownFiles: t,
22
- defaultOptions: e
24
+ defaultOptions: e,
25
+ filesPath: n
23
26
  }) => ({
24
- getRoutes: () => i(t, e)
27
+ getRoutes: () => x(t, n, e)
25
28
  });
26
29
  export {
27
- x as markdownPlugin
30
+ f as markdownPlugin
28
31
  };
29
32
  //# sourceMappingURL=zudoku.plugin-markdown.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"zudoku.plugin-markdown.js","sources":["../src/lib/plugins/markdown/generateRoutes.tsx","../src/lib/plugins/markdown/index.tsx"],"sourcesContent":["import { type RouteObject } from \"react-router-dom\";\n\nimport {\n MarkdownPluginDefaultOptions,\n MarkdownPluginOptions,\n} from \"./index.js\";\n\nexport const generateRoutes = (\n markdownFiles: MarkdownPluginOptions[\"markdownFiles\"],\n defaultOptions?: MarkdownPluginDefaultOptions,\n): RouteObject[] =>\n Object.entries(markdownFiles).flatMap(([file, importPromise]) => {\n // @todo we can pass in the folder name and then filter the markdown files based on that path\n const match = file.match(/pages\\/(.*).mdx?$/);\n const path = match?.at(1);\n\n if (!path) return [];\n\n return {\n path,\n lazy: async () => {\n const { MdxPage } = await import(\"./MdxPage.js\");\n const { default: Component, ...props } = await importPromise();\n return {\n element: (\n <MdxPage\n mdxComponent={Component}\n {...props}\n defaultOptions={defaultOptions}\n />\n ),\n };\n },\n } satisfies RouteObject;\n });\n","import type { Toc } from \"@stefanprobst/rehype-extract-toc\";\nimport type { MDXProps } from \"mdx/types.js\";\nimport type { DevPortalPlugin } from \"../../core/plugins.js\";\nimport { generateRoutes } from \"./generateRoutes.js\";\n\nexport type MarkdownPluginOptions = {\n markdownFiles: Record<string, () => Promise<MDXImport>>;\n defaultOptions?: MarkdownPluginDefaultOptions;\n};\nexport type MarkdownPluginDefaultOptions = Pick<\n Frontmatter,\n \"toc\" | \"disablePager\"\n>;\n\nexport type Frontmatter = {\n title?: string;\n description?: string;\n category?: string;\n toc?: boolean;\n disablePager?: boolean;\n};\n\nexport type MDXImport = {\n tableOfContents: Toc;\n frontmatter: Frontmatter;\n default: (props: MDXProps) => JSX.Element;\n};\n\nexport const markdownPlugin = ({\n markdownFiles,\n defaultOptions,\n}: MarkdownPluginOptions): DevPortalPlugin => ({\n getRoutes: () => generateRoutes(markdownFiles, defaultOptions),\n});\n"],"names":["generateRoutes","markdownFiles","defaultOptions","file","importPromise","match","path","MdxPage","Component","props","jsx","markdownPlugin"],"mappings":";AAOO,MAAMA,IAAiB,CAC5BC,GACAC,MAEA,OAAO,QAAQD,CAAa,EAAE,QAAQ,CAAC,CAACE,GAAMC,CAAa,MAAM;AAEzD,QAAAC,IAAQF,EAAK,MAAM,mBAAmB,GACtCG,IAAOD,KAAA,gBAAAA,EAAO,GAAG;AAEnB,SAACC,IAEE;AAAA,IACL,MAAAA;AAAA,IACA,MAAM,YAAY;AAChB,YAAM,EAAE,SAAAC,EAAA,IAAY,MAAM,OAAO,uBAAc,GACzC,EAAE,SAASC,GAAW,GAAGC,EAAM,IAAI,MAAML;AACxC,aAAA;AAAA,QACL,SACEM,gBAAAA,EAAA;AAAA,UAACH;AAAA,UAAA;AAAA,YACC,cAAcC;AAAA,YACb,GAAGC;AAAA,YACJ,gBAAAP;AAAA,UAAA;AAAA,QACF;AAAA,MAAA;AAAA,IAGN;AAAA,EAAA,IAhBgB;AAkBpB,CAAC,GCNUS,IAAiB,CAAC;AAAA,EAC7B,eAAAV;AAAA,EACA,gBAAAC;AACF,OAA+C;AAAA,EAC7C,WAAW,MAAMF,EAAeC,GAAeC,CAAc;AAC/D;"}
1
+ {"version":3,"file":"zudoku.plugin-markdown.js","sources":["../src/lib/plugins/markdown/generateRoutes.tsx","../src/lib/plugins/markdown/index.tsx"],"sourcesContent":["import { type RouteObject } from \"react-router-dom\";\n\nimport {\n MarkdownPluginDefaultOptions,\n MarkdownPluginOptions,\n} from \"./index.js\";\n\nexport const generateRoutes = (\n markdownFiles: MarkdownPluginOptions[\"markdownFiles\"],\n filesPath: string,\n defaultOptions?: MarkdownPluginDefaultOptions,\n): RouteObject[] =>\n Object.entries(markdownFiles).flatMap(([file, importPromise]) => {\n let rootDir = filesPath.split(\"**\")[0];\n rootDir = rootDir.replace(\"/**\", \"/\");\n const re = new RegExp(`^${rootDir}(.*).mdx?`);\n const match = file.match(re);\n const fsPath = match?.at(1);\n\n if (!fsPath) return [];\n\n return {\n path: fsPath,\n lazy: async () => {\n const { MdxPage } = await import(\"./MdxPage.js\");\n const { default: Component, ...props } = await importPromise();\n return {\n element: (\n <MdxPage\n mdxComponent={Component}\n {...props}\n defaultOptions={defaultOptions}\n />\n ),\n };\n },\n } satisfies RouteObject;\n });\n","import type { Toc } from \"@stefanprobst/rehype-extract-toc\";\nimport type { MDXProps } from \"mdx/types.js\";\nimport type { DevPortalPlugin } from \"../../core/plugins.js\";\nimport { generateRoutes } from \"./generateRoutes.js\";\n\nexport type MarkdownPluginOptions = {\n markdownFiles: Record<string, () => Promise<MDXImport>>;\n defaultOptions?: MarkdownPluginDefaultOptions;\n filesPath: string;\n};\nexport type MarkdownPluginDefaultOptions = Pick<\n Frontmatter,\n \"toc\" | \"disablePager\"\n>;\n\nexport type Frontmatter = {\n title?: string;\n description?: string;\n category?: string;\n toc?: boolean;\n disablePager?: boolean;\n};\n\nexport type MDXImport = {\n tableOfContents: Toc;\n frontmatter: Frontmatter;\n default: (props: MDXProps) => JSX.Element;\n};\n\nexport const markdownPlugin = ({\n markdownFiles,\n defaultOptions,\n filesPath,\n}: MarkdownPluginOptions): DevPortalPlugin => ({\n getRoutes: () => generateRoutes(markdownFiles, filesPath, defaultOptions),\n});\n"],"names":["generateRoutes","markdownFiles","filesPath","defaultOptions","file","importPromise","rootDir","re","match","fsPath","MdxPage","Component","props","jsx","markdownPlugin"],"mappings":";AAOO,MAAMA,IAAiB,CAC5BC,GACAC,GACAC,MAEA,OAAO,QAAQF,CAAa,EAAE,QAAQ,CAAC,CAACG,GAAMC,CAAa,MAAM;AAC/D,MAAIC,IAAUJ,EAAU,MAAM,IAAI,EAAE,CAAC;AAC3B,EAAAI,IAAAA,EAAQ,QAAQ,OAAO,GAAG;AACpC,QAAMC,IAAK,IAAI,OAAO,IAAID,CAAO,WAAW,GACtCE,IAAQJ,EAAK,MAAMG,CAAE,GACrBE,IAASD,KAAA,gBAAAA,EAAO,GAAG;AAErB,SAACC,IAEE;AAAA,IACL,MAAMA;AAAA,IACN,MAAM,YAAY;AAChB,YAAM,EAAE,SAAAC,EAAA,IAAY,MAAM,OAAO,uBAAc,GACzC,EAAE,SAASC,GAAW,GAAGC,EAAM,IAAI,MAAMP;AACxC,aAAA;AAAA,QACL,SACEQ,gBAAAA,EAAA;AAAA,UAACH;AAAA,UAAA;AAAA,YACC,cAAcC;AAAA,YACb,GAAGC;AAAA,YACJ,gBAAAT;AAAA,UAAA;AAAA,QACF;AAAA,MAAA;AAAA,IAGN;AAAA,EAAA,IAhBkB;AAkBtB,CAAC,GCRUW,IAAiB,CAAC;AAAA,EAC7B,eAAAb;AAAA,EACA,gBAAAE;AAAA,EACA,WAAAD;AACF,OAA+C;AAAA,EAC7C,WAAW,MAAMF,EAAeC,GAAeC,GAAWC,CAAc;AAC1E;"}
@@ -1,12 +1,12 @@
1
1
  import "./jsx-runtime-B6kdoens.js";
2
- import { o as u } from "./index-Dv2KZuEw.js";
2
+ import { o as u } from "./index-BlJ2rj99.js";
3
3
  import "./urql-YhcsXYy8.js";
4
4
  import "./ZudokuContext-cr-pTRY1.js";
5
5
  import "lucide-react";
6
6
  import "zudoku/openapi-worker";
7
- import "./index-Zezcv0xb.js";
8
- import "./ErrorPage-knunPbKI.js";
9
- import "./Markdown-B4aR03g6.js";
7
+ import "./index-Dolisrci.js";
8
+ import "./ErrorPage-CsZAN_za.js";
9
+ import "./Markdown-DapSf3wG.js";
10
10
  import "./joinPath-B7kNnUX4.js";
11
11
  import "./router-D2p7Olpn.js";
12
12
  import "./index-BG0g4WW0.js";
package/package.json CHANGED
@@ -1,7 +1,16 @@
1
1
  {
2
2
  "name": "zudoku",
3
- "version": "0.10.0",
3
+ "version": "0.12.0",
4
4
  "type": "module",
5
+ "homepage": "https://zudoku.dev",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/zuplo/zudoku.git"
9
+ },
10
+ "bugs": {
11
+ "url": "https://github.com/zuplo/zudoku/issues"
12
+ },
13
+ "description": "Framework for building high quality, interactive API documentation.",
5
14
  "files": [
6
15
  "dist",
7
16
  "lib",
@@ -102,6 +111,7 @@
102
111
  "@radix-ui/react-select": "2.1.1",
103
112
  "@radix-ui/react-visually-hidden": "1.1.0",
104
113
  "@sentry/node": "8.11.0",
114
+ "@sindresorhus/slugify": "2.2.1",
105
115
  "@stefanprobst/rehype-extract-toc": "2.2.0",
106
116
  "@tailwindcss/typography": "0.5.13",
107
117
  "@tanstack/react-query": "5.50.1",
@@ -111,12 +121,13 @@
111
121
  "chokidar": "^3.6.0",
112
122
  "class-variance-authority": "0.7.0",
113
123
  "dotenv": "16.4.5",
114
- "express": "4.19.2",
124
+ "express": "4.20.0",
115
125
  "glob": "^11.0.0",
116
126
  "graphql": "16.9.0",
117
127
  "graphql-type-json": "0.3.2",
118
128
  "graphql-yoga": "5.2.0",
119
129
  "gray-matter": "^4.0.3",
130
+ "http-terminator": "^3.2.0",
120
131
  "loglevel": "^1.9.1",
121
132
  "lru-cache": "11.0.0",
122
133
  "lucide-react": "0.438.0",
@@ -146,7 +157,6 @@
146
157
  "rollup": "^4.21.2",
147
158
  "semver": "7.6.2",
148
159
  "sitemap": "^8.0.0",
149
- "slugify": "1.6.6",
150
160
  "strip-ansi": "7.1.0",
151
161
  "tailwind-merge": "2.5.2",
152
162
  "tailwindcss": "3.4.4",
@@ -155,7 +165,7 @@
155
165
  "unist-util-visit": "5.0.0",
156
166
  "urql": "4.1.0",
157
167
  "vaul": "0.9.2",
158
- "vite": "5.3.3",
168
+ "vite": "5.3.6",
159
169
  "yaml": "2.5.0",
160
170
  "yargs": "17.7.2",
161
171
  "zod": "3.23.8",
@@ -1,4 +1,5 @@
1
1
  import { create } from "zustand";
2
+ import { persist } from "zustand/middleware";
2
3
 
3
4
  export const useAuthState = create<AuthState>(() => ({
4
5
  isPending: false,
@@ -19,3 +20,19 @@ export interface UserProfile {
19
20
  pictureUrl: string | undefined;
20
21
  [key: string]: string | boolean | undefined;
21
22
  }
23
+
24
+ interface SelectedServerState {
25
+ selectedServer?: string;
26
+ setSelectedServer: (newServer: string) => void;
27
+ }
28
+
29
+ export const useSelectedServerStore = create<SelectedServerState>()(
30
+ persist(
31
+ (set) => ({
32
+ selectedServer: undefined,
33
+ setSelectedServer: (newServer: string) =>
34
+ set({ selectedServer: newServer }),
35
+ }),
36
+ { name: "zudoku-selected-server" },
37
+ ),
38
+ );
@@ -1,5 +1,4 @@
1
1
  import type { ReactNode } from "react";
2
- import { Link } from "react-router-dom";
3
2
  import { CategoryHeading } from "./CategoryHeading.js";
4
3
  import { Heading } from "./Heading.js";
5
4
  import { ProseClasses } from "./Markdown.js";
@@ -22,7 +21,6 @@ export const ErrorPage = ({
22
21
  </Heading>
23
22
  )}
24
23
  <p>{message}</p>
25
- <Link to="/">Go back home</Link>
26
24
  </div>
27
25
  );
28
26
  };
@@ -4,11 +4,21 @@ import { cn } from "../util/cn.js";
4
4
  export const InlineCode = ({
5
5
  className,
6
6
  children,
7
+ selectOnClick,
7
8
  }: {
8
9
  className?: string;
9
10
  children: ReactNode;
11
+ selectOnClick?: boolean;
10
12
  }) => (
11
13
  <code
14
+ onClick={(e) => {
15
+ if (!selectOnClick) return;
16
+ const selection = window.getSelection();
17
+ const range = document.createRange();
18
+ range.selectNodeContents(e.currentTarget);
19
+ selection?.removeAllRanges();
20
+ selection?.addRange(range);
21
+ }}
12
22
  className={cn(
13
23
  "font-mono border p-1 py-0.5 rounded bg-border/50 dark:bg-border/70 whitespace-nowrap",
14
24
  className,
@@ -53,7 +53,7 @@ export const Layout = ({ children }: { children?: ReactNode }) => {
53
53
  <div className="w-full max-w-screen-2xl mx-auto px-10 lg:px-12">
54
54
  <Suspense
55
55
  fallback={
56
- <main className="grid h-full place-items-center">
56
+ <main className="grid h-[calc(100vh-var(--header-height))] place-items-center">
57
57
  <Spinner />
58
58
  </main>
59
59
  }
@@ -1,10 +1,13 @@
1
1
  /* eslint-disable @typescript-eslint/no-explicit-any */
2
2
  import SchemaBuilder from "@pothos/core";
3
+ import {
4
+ slugifyWithCounter,
5
+ type CountableSlugify,
6
+ } from "@sindresorhus/slugify";
3
7
  import { GraphQLJSON, GraphQLJSONObject } from "graphql-type-json";
4
8
  import { createYoga, type YogaServerOptions } from "graphql-yoga";
5
9
  import { LRUCache } from "lru-cache";
6
10
  import hashit from "object-hash";
7
- import slugify from "../../util/slugify.js";
8
11
  import {
9
12
  HttpMethods,
10
13
  validate,
@@ -15,6 +18,7 @@ import {
15
18
  type ParameterObject,
16
19
  type PathsObject,
17
20
  type SchemaObject,
21
+ type ServerObject,
18
22
  type TagObject,
19
23
  } from "../parser/index.js";
20
24
 
@@ -35,7 +39,12 @@ type OperationLike = {
35
39
  path: string;
36
40
  method: string;
37
41
  };
38
- export const slugifyOperation = (operation: OperationLike, tag?: string) => {
42
+
43
+ export const createOperationSlug = (
44
+ slugify: CountableSlugify,
45
+ operation: OperationLike,
46
+ tag?: string,
47
+ ) => {
39
48
  const summary =
40
49
  (operation.summary ?? "") +
41
50
  (operation.operationId
@@ -46,7 +55,6 @@ export const slugifyOperation = (operation: OperationLike, tag?: string) => {
46
55
  return slugify(
47
56
  (tag ? tag + "-" : "") +
48
57
  (summary || `${operation.method}-${operation.path}`),
49
- { lower: true, trim: true },
50
58
  );
51
59
  };
52
60
 
@@ -88,6 +96,8 @@ const getAllTags = (schema: OpenAPIDocument): TagObject[] => {
88
96
  };
89
97
 
90
98
  const getAllOperations = (paths?: PathsObject, tag?: string) => {
99
+ const slugify = slugifyWithCounter();
100
+
91
101
  return Object.entries(paths ?? {}).flatMap(([path, value]) =>
92
102
  HttpMethods.flatMap((method) => {
93
103
  if (!value?.[method]) return [];
@@ -109,21 +119,20 @@ const getAllOperations = (paths?: PathsObject, tag?: string) => {
109
119
  ...operationParameters,
110
120
  ];
111
121
 
122
+ const slugData = {
123
+ summary: operation.summary,
124
+ operationId: operation.operationId,
125
+ path,
126
+ method,
127
+ };
128
+
112
129
  return {
113
130
  ...operation,
114
131
  method,
115
132
  path,
116
133
  parameters,
117
134
  tags: operation.tags ?? [],
118
- slug: slugifyOperation(
119
- {
120
- summary: operation.summary,
121
- operationId: operation.operationId,
122
- path,
123
- method,
124
- },
125
- tag,
126
- ),
135
+ slug: createOperationSlug(slugify, slugData, tag),
127
136
  };
128
137
  }),
129
138
  );
@@ -150,6 +159,13 @@ const SchemaTag = builder.objectRef<TagObject>("SchemaTag").implement({
150
159
  }),
151
160
  });
152
161
 
162
+ const ServerItem = builder.objectRef<ServerObject>("Server").implement({
163
+ fields: (t) => ({
164
+ url: t.exposeString("url"),
165
+ description: t.exposeString("description", { nullable: true }),
166
+ }),
167
+ });
168
+
153
169
  const PathItem = builder
154
170
  .objectRef<{
155
171
  path: string;
@@ -363,6 +379,10 @@ const Schema = builder.objectRef<OpenAPIDocument>("Schema").implement({
363
379
  fields: (t) => ({
364
380
  openapi: t.string({ resolve: (root) => root.openapi }),
365
381
  url: t.string({ resolve: (root) => root.servers?.at(0)?.url ?? "/" }),
382
+ servers: t.field({
383
+ type: [ServerItem],
384
+ resolve: (root) => root.servers ?? [],
385
+ }),
366
386
  title: t.string({ resolve: (root) => root.info.title }),
367
387
  version: t.string({ resolve: (root) => root.info.version }),
368
388
  description: t.string({
@@ -422,7 +442,7 @@ const loadOpenAPISchema = async (input: NonNullable<unknown>) => {
422
442
  };
423
443
 
424
444
  const SchemaSource = builder.enumType("SchemaType", {
425
- values: ["url", "file"] as const,
445
+ values: ["url", "file", "raw"] as const,
426
446
  });
427
447
 
428
448
  builder.queryType({
@@ -20,6 +20,7 @@ export type TagObject = DeepOmitReference<OpenAPIV3_1.TagObject>;
20
20
  export type ExampleObject = DeepOmitReference<OpenAPIV3_1.ExampleObject>;
21
21
  export type EncodingObject = DeepOmitReference<OpenAPIV3_1.EncodingObject>;
22
22
  export type SchemaObject = DeepOmitReference<OpenAPIV3_1.SchemaObject>;
23
+ export type ServerObject = DeepOmitReference<OpenAPIV3_1.ServerObject>;
23
24
 
24
25
  export const HttpMethods = Object.values(OpenAPIV3.HttpMethods);
25
26
 
@@ -1,4 +1,5 @@
1
1
  import { useMDXComponents } from "@mdx-js/react";
2
+ import slugify from "@sindresorhus/slugify";
2
3
  import { Helmet } from "@zudoku/react-helmet-async";
3
4
  import { type PropsWithChildren } from "react";
4
5
  import { Link } from "react-router-dom";
@@ -11,7 +12,6 @@ import {
11
12
  } from "../../components/navigation/utils.js";
12
13
  import type { MdxComponentsType } from "../../util/MdxComponents.js";
13
14
  import { cn } from "../../util/cn.js";
14
- import slugify from "../../util/slugify.js";
15
15
  import { Toc } from "./Toc.js";
16
16
  import { MarkdownPluginDefaultOptions, MDXImport } from "./index.js";
17
17
 
@@ -71,7 +71,7 @@ export const MdxPage = ({
71
71
  <header>
72
72
  {category && <CategoryHeading>{category}</CategoryHeading>}
73
73
  {title && (
74
- <Heading level={1} id={slugify(title, { lower: true })}>
74
+ <Heading level={1} id={slugify(title)}>
75
75
  {title}
76
76
  </Heading>
77
77
  )}
@@ -7,17 +7,20 @@ import {
7
7
 
8
8
  export const generateRoutes = (
9
9
  markdownFiles: MarkdownPluginOptions["markdownFiles"],
10
+ filesPath: string,
10
11
  defaultOptions?: MarkdownPluginDefaultOptions,
11
12
  ): RouteObject[] =>
12
13
  Object.entries(markdownFiles).flatMap(([file, importPromise]) => {
13
- // @todo we can pass in the folder name and then filter the markdown files based on that path
14
- const match = file.match(/pages\/(.*).mdx?$/);
15
- const path = match?.at(1);
14
+ let rootDir = filesPath.split("**")[0];
15
+ rootDir = rootDir.replace("/**", "/");
16
+ const re = new RegExp(`^${rootDir}(.*).mdx?`);
17
+ const match = file.match(re);
18
+ const fsPath = match?.at(1);
16
19
 
17
- if (!path) return [];
20
+ if (!fsPath) return [];
18
21
 
19
22
  return {
20
- path,
23
+ path: fsPath,
21
24
  lazy: async () => {
22
25
  const { MdxPage } = await import("./MdxPage.js");
23
26
  const { default: Component, ...props } = await importPromise();
@@ -6,6 +6,7 @@ import { generateRoutes } from "./generateRoutes.js";
6
6
  export type MarkdownPluginOptions = {
7
7
  markdownFiles: Record<string, () => Promise<MDXImport>>;
8
8
  defaultOptions?: MarkdownPluginDefaultOptions;
9
+ filesPath: string;
9
10
  };
10
11
  export type MarkdownPluginDefaultOptions = Pick<
11
12
  Frontmatter,
@@ -29,6 +30,7 @@ export type MDXImport = {
29
30
  export const markdownPlugin = ({
30
31
  markdownFiles,
31
32
  defaultOptions,
33
+ filesPath,
32
34
  }: MarkdownPluginOptions): DevPortalPlugin => ({
33
- getRoutes: () => generateRoutes(markdownFiles, defaultOptions),
35
+ getRoutes: () => generateRoutes(markdownFiles, filesPath, defaultOptions),
34
36
  });
@@ -1,31 +1,95 @@
1
1
  import { CheckIcon, CopyIcon } from "lucide-react";
2
- import { useState } from "react";
2
+ import { useState, useTransition } from "react";
3
+ import { useSelectedServerStore } from "../../authentication/state.js";
3
4
  import { InlineCode } from "../../components/InlineCode.js";
5
+ import { Button } from "../../ui/Button.js";
6
+ import { useOasConfig } from "./context.js";
7
+ import { graphql } from "./graphql/index.js";
8
+ import { SimpleSelect } from "./SimpleSelect.js";
9
+ import { useQuery } from "./util/urql.js";
4
10
 
5
- export const Endpoint = ({ url }: { url: string }) => {
11
+ const ServersQuery = graphql(/* GraphQL */ `
12
+ query ServersQuery($input: JSON!, $type: SchemaType!) {
13
+ schema(input: $input, type: $type) {
14
+ url
15
+ servers {
16
+ url
17
+ }
18
+ }
19
+ }
20
+ `);
21
+
22
+ const CopyButton = ({ url }: { url: string }) => {
6
23
  const [isCopied, setIsCopied] = useState(false);
7
24
 
8
25
  return (
9
- <div className="my-4 flex items-center justify-end gap-2 text-sm">
10
- <span className="font-medium">Endpoint:</span>
11
- <InlineCode className="p-1.5 flex gap-2.5 items-center text-xs">
12
- {url}
13
- <button
14
- onClick={() => {
15
- void navigator.clipboard.writeText(url).then(() => {
16
- setIsCopied(true);
17
- setTimeout(() => setIsCopied(false), 2000);
18
- });
19
- }}
20
- type="button"
21
- >
22
- {isCopied ? (
23
- <CheckIcon className="text-green-600" size={14} />
24
- ) : (
25
- <CopyIcon size={14} strokeWidth={1.3} />
26
- )}
27
- </button>
28
- </InlineCode>
26
+ <Button
27
+ onClick={() => {
28
+ void navigator.clipboard.writeText(url).then(() => {
29
+ setIsCopied(true);
30
+ setTimeout(() => setIsCopied(false), 2000);
31
+ });
32
+ }}
33
+ variant="ghost"
34
+ size="icon"
35
+ >
36
+ {isCopied ? (
37
+ <CheckIcon className="text-green-600" size={14} />
38
+ ) : (
39
+ <CopyIcon size={14} strokeWidth={1.3} />
40
+ )}
41
+ </Button>
42
+ );
43
+ };
44
+
45
+ const context = { suspense: true } as const;
46
+
47
+ export const Endpoint = () => {
48
+ const [result] = useQuery({
49
+ query: ServersQuery,
50
+ variables: useOasConfig(),
51
+ context,
52
+ });
53
+ const [, startTransition] = useTransition();
54
+ const { selectedServer, setSelectedServer } = useSelectedServerStore();
55
+
56
+ if (!result.data) return null;
57
+
58
+ const { servers } = result.data.schema;
59
+
60
+ if (servers.length === 1) {
61
+ return (
62
+ <div className="flex items-center gap-2">
63
+ <span className="font-medium text-sm">Endpoint:</span>
64
+ <InlineCode className="text-xs px-2 py-1.5" selectOnClick>
65
+ {servers[0].url}
66
+ </InlineCode>
67
+ <CopyButton url={servers[0].url} />
68
+ </div>
69
+ );
70
+ }
71
+
72
+ return (
73
+ <div className="flex flex-wrap items-center gap-2">
74
+ <span className="font-medium text-sm">
75
+ {servers.length > 1 ? "Endpoints" : "Endpoint"}:
76
+ </span>
77
+
78
+ <SimpleSelect
79
+ className="font-mono text-xs bg-border/50 dark:bg-border/70 py-1.5 max-w-[450px] truncate"
80
+ onChange={(e) =>
81
+ startTransition(() => {
82
+ setSelectedServer(e.target.value);
83
+ })
84
+ }
85
+ value={selectedServer ?? result.data.schema.url}
86
+ showChevrons={servers.length > 1}
87
+ options={servers.map((server) => ({
88
+ value: server.url,
89
+ label: server.url,
90
+ }))}
91
+ />
92
+ <CopyButton url={selectedServer ?? result.data.schema.url} />
29
93
  </div>
30
94
  );
31
95
  };
@@ -133,7 +133,9 @@ export const OperationList = () => {
133
133
  <Markdown content={result.data.schema.description ?? ""} />
134
134
  </div>
135
135
  <hr />
136
- <Endpoint url={result.data.schema.url} />
136
+ <div className="my-4 flex justify-end">
137
+ <Endpoint />
138
+ </div>
137
139
 
138
140
  {result.data.schema.tags
139
141
  .filter((tag) => tag.operations.length > 0)
@@ -91,7 +91,7 @@ export const OperationListItem = ({
91
91
  <TabsTrigger
92
92
  value={response.statusCode}
93
93
  key={response.statusCode}
94
- title={response.description}
94
+ title={response.description ?? undefined}
95
95
  >
96
96
  {response.statusCode}
97
97
  </TabsTrigger>
@@ -3,9 +3,11 @@ import { PlaygroundDialog } from "./playground/PlaygroundDialog.js";
3
3
 
4
4
  export const PlaygroundDialogWrapper = ({
5
5
  server,
6
+ servers,
6
7
  operation,
7
8
  }: {
8
9
  server: string;
10
+ servers?: string[];
9
11
  operation: OperationListItemResult;
10
12
  }) => {
11
13
  const headers = operation.parameters
@@ -29,6 +31,7 @@ export const PlaygroundDialogWrapper = ({
29
31
  return (
30
32
  <PlaygroundDialog
31
33
  server={server}
34
+ servers={servers}
32
35
  method={operation.method}
33
36
  url={operation.path}
34
37
  headers={headers}
@@ -1,6 +1,7 @@
1
1
  import { HTTPSnippet } from "@zudoku/httpsnippet";
2
2
  import { Fragment, useMemo, useTransition } from "react";
3
3
  import { useSearchParams } from "react-router-dom";
4
+ import { useSelectedServerStore } from "../../authentication/state.js";
4
5
  import { TextColorMap } from "../../components/navigation/SidebarBadge.js";
5
6
  import { SyntaxHighlight } from "../../components/SyntaxHighlight.js";
6
7
  import type { SchemaObject } from "../../oas/parser/index.js";
@@ -65,6 +66,9 @@ export const GetServerQuery = graphql(/* GraphQL */ `
65
66
  query getServerQuery($input: JSON!, $type: SchemaType!) {
66
67
  schema(input: $input, type: $type) {
67
68
  url
69
+ servers {
70
+ url
71
+ }
68
72
  }
69
73
  }
70
74
  `);
@@ -135,6 +139,8 @@ export const Sidecar = ({
135
139
  );
136
140
  });
137
141
 
142
+ const { selectedServer } = useSelectedServerStore();
143
+
138
144
  const code = useMemo(() => {
139
145
  const example = requestBodyContent?.[0]?.schema
140
146
  ? generateSchemaExample(requestBodyContent[0].schema as SchemaObject)
@@ -143,7 +149,7 @@ export const Sidecar = ({
143
149
  const snippet = new HTTPSnippet({
144
150
  method: operation.method.toLocaleUpperCase(),
145
151
  url:
146
- (result.data?.schema.url ?? "") +
152
+ (selectedServer ?? result.data?.schema.url ?? "") +
147
153
  operation.path.replaceAll("{", ":").replaceAll("}", ""),
148
154
  postData: example
149
155
  ? {
@@ -160,7 +166,13 @@ export const Sidecar = ({
160
166
  });
161
167
 
162
168
  return getConverted(snippet, selectedLang);
163
- }, [selectedLang, operation.method, operation.path, requestBodyContent]);
169
+ }, [
170
+ selectedServer,
171
+ selectedLang,
172
+ operation.method,
173
+ operation.path,
174
+ requestBodyContent,
175
+ ]);
164
176
 
165
177
  return (
166
178
  <aside className="flex flex-col overflow-hidden sticky top-[--scroll-padding] gap-4">
@@ -175,6 +187,9 @@ export const Sidecar = ({
175
187
  </span>
176
188
  <PlaygroundDialogWrapper
177
189
  server={result.data?.schema.url ?? ""}
190
+ servers={
191
+ result.data?.schema.servers.map((server) => server.url) ?? []
192
+ }
178
193
  operation={operation}
179
194
  />
180
195
  </SidecarBox.Head>