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
@@ -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 { Navigate, type RouteObject } from \"react-router-dom\";\nimport { useTopNavigationItem } from \"../../components/context/DevPortalProvider.js\";\nimport { isPathItem } from \"../../components/navigation/util.js\";\nimport { traverseNavigation } from \"../../util/traverseNavigation.js\";\n\nimport {\n MarkdownPluginDefaultOptions,\n MarkdownPluginOptions,\n} from \"./index.js\";\n\nexport const generateRoutes = (\n markdownFiles: MarkdownPluginOptions[\"markdownFiles\"],\n defaultOptions?: MarkdownPluginDefaultOptions,\n): RouteObject[] => {\n const routes = Object.entries(markdownFiles).flatMap(\n ([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 const pathSegments = path.split(\"/\");\n const isIndexFile = pathSegments.at(-1) === \"index\";\n const routePath = isIndexFile\n ? pathSegments.slice(0, -1).join(\"/\")\n : path;\n\n return {\n path: routePath,\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 );\n\n const rootRoutes = Array.from(\n new Set(routes.map((route) => route.path.split(\"/\").at(0))),\n ).map((dir) => ({\n path: `/${dir}`,\n element: <Redirect />,\n }));\n\n return [...routes, ...rootRoutes];\n};\n\nconst Redirect = () => {\n const navItem = useTopNavigationItem();\n\n if (!navItem) return null;\n\n return traverseNavigation(navItem, (node, fullPath) => {\n if (\"children\" in node || !isPathItem(node)) return;\n return <Navigate to={fullPath} replace />;\n });\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 return {\n getRoutes() {\n return generateRoutes(markdownFiles, defaultOptions);\n },\n };\n};\n"],"names":["generateRoutes","markdownFiles","defaultOptions","routes","file","importPromise","match","path","pathSegments","MdxPage","Component","props","jsx","rootRoutes","route","dir","Redirect","navItem","useTopNavigationItem","traverseNavigation","node","fullPath","isPathItem","Navigate","markdownPlugin"],"mappings":";;;;AAUa,MAAAA,IAAiB,CAC5BC,GACAC,MACkB;AAClB,QAAMC,IAAS,OAAO,QAAQF,CAAa,EAAE;AAAA,IAC3C,CAAC,CAACG,GAAMC,CAAa,MAAM;AAEnB,YAAAC,IAAQF,EAAK,MAAM,mBAAmB,GACtCG,IAAOD,KAAA,gBAAAA,EAAO,GAAG;AAEnB,UAAA,CAACC,EAAM,QAAO;AAEZ,YAAAC,IAAeD,EAAK,MAAM,GAAG;AAM5B,aAAA;AAAA,QACL,MANkBC,EAAa,GAAG,EAAE,MAAM,UAExCA,EAAa,MAAM,GAAG,EAAE,EAAE,KAAK,GAAG,IAClCD;AAAA,QAIF,MAAM,YAAY;AAChB,gBAAM,EAAE,SAAAE,EAAA,IAAY,MAAM,OAAO,uBAAc,GACzC,EAAE,SAASC,GAAW,GAAGC,EAAM,IAAI,MAAMN;AACxC,iBAAA;AAAA,YACL,SACEO,gBAAAA,EAAA;AAAA,cAACH;AAAA,cAAA;AAAA,gBACC,cAAcC;AAAA,gBACb,GAAGC;AAAA,gBACJ,gBAAAT;AAAA,cAAA;AAAA,YACF;AAAA,UAAA;AAAA,QAGN;AAAA,MAAA;AAAA,IAEJ;AAAA,EAAA,GAGIW,IAAa,MAAM;AAAA,IACvB,IAAI,IAAIV,EAAO,IAAI,CAACW,MAAUA,EAAM,KAAK,MAAM,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC;AAAA,EAAA,EAC1D,IAAI,CAACC,OAAS;AAAA,IACd,MAAM,IAAIA,CAAG;AAAA,IACb,+BAAUC,GAAS,EAAA;AAAA,EACnB,EAAA;AAEF,SAAO,CAAC,GAAGb,GAAQ,GAAGU,CAAU;AAClC,GAEMG,IAAW,MAAM;AACrB,QAAMC,IAAUC;AAEZ,SAACD,IAEEE,EAAmBF,GAAS,CAACG,GAAMC,MAAa;AACrD,QAAI,gBAAcD,KAAQ,CAACE,EAAWF,CAAI;AAC1C,aAAQR,gBAAAA,EAAAA,IAAAW,GAAA,EAAS,IAAIF,GAAU,SAAO,GAAC,CAAA;AAAA,EAAA,CACxC,IALoB;AAMvB,GCtCaG,IAAiB,CAAC;AAAA,EAC7B,eAAAvB;AAAA,EACA,gBAAAC;AACF,OACS;AAAA,EACL,YAAY;AACH,WAAAF,EAAeC,GAAeC,CAAc;AAAA,EACrD;AAAA;"}
1
+ {"version":3,"file":"zudoku.plugin-markdown.js","sources":[],"sourcesContent":[],"names":[],"mappings":";"}
@@ -1,8 +1,10 @@
1
- import "./jsx-runtime-SV6hXQua.js";
2
- import { o as t } from "./index-Cpdpun6t.js";
1
+ import "./jsx-runtime-CM0TzjGp.js";
2
+ import { o as n } from "./index-BoWzKb_9.js";
3
3
  import "./urql-DMlBWUKL.js";
4
4
  import "virtual:zudoku-openapi-worker";
5
+ import "./MdxComponents-Ev_hBHb2.js";
6
+ import "./router-CcYTwKjf.js";
5
7
  export {
6
- t as openApiPlugin
8
+ n as openApiPlugin
7
9
  };
8
10
  //# sourceMappingURL=zudoku.plugin-openapi.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"zudoku.plugin-openapi.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;"}
1
+ {"version":3,"file":"zudoku.plugin-openapi.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;"}
@@ -1,12 +1,11 @@
1
- import { j as s } from "./jsx-runtime-SV6hXQua.js";
2
- import { N as i } from "./index-DLS6fPwU.js";
3
- const p = (t) => ({
4
- getRoutes: () => t.redirects.map(({ from: e, to: r, replace: o }) => ({
5
- path: e,
6
- element: /* @__PURE__ */ s.jsx(i, { to: r, replace: o })
1
+ import { b as o } from "./router-CcYTwKjf.js";
2
+ const i = (e) => ({
3
+ getRoutes: () => e.redirects.map(({ from: r, to: t, replace: a }) => ({
4
+ path: r,
5
+ loader: () => o(t)
7
6
  }))
8
7
  });
9
8
  export {
10
- p as redirectPlugin
9
+ i as redirectPlugin
11
10
  };
12
11
  //# sourceMappingURL=zudoku.plugin-redirect.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"zudoku.plugin-redirect.js","sources":["../src/lib/plugins/redirect/index.tsx"],"sourcesContent":["import { Navigate } from \"react-router-dom\";\nimport type { DevPortalPlugin } from \"../../core/plugins.js\";\n\nexport type Redirect = {\n from: string;\n to: string;\n replace?: boolean;\n};\n\nexport const redirectPlugin = (options: {\n redirects: Redirect[];\n}): DevPortalPlugin => {\n return {\n getRoutes: () =>\n options.redirects.map(({ from, to, replace }) => ({\n path: from,\n element: <Navigate to={to} replace={replace} />,\n })),\n };\n};\n"],"names":["redirectPlugin","options","from","to","replace","jsx","Navigate"],"mappings":";;AASa,MAAAA,IAAiB,CAACC,OAGtB;AAAA,EACL,WAAW,MACTA,EAAQ,UAAU,IAAI,CAAC,EAAE,MAAAC,GAAM,IAAAC,GAAI,SAAAC,SAAe;AAAA,IAChD,MAAMF;AAAA,IACN,SAASG,gBAAAA,EAAAA,IAACC,GAAS,EAAA,IAAAH,GAAQ,SAAAC,EAAkB,CAAA;AAAA,EAAA,EAC7C;AAAA;"}
1
+ {"version":3,"file":"zudoku.plugin-redirect.js","sources":["../src/lib/plugins/redirect/index.tsx"],"sourcesContent":["import { redirect } from \"react-router-dom\";\nimport type { DevPortalPlugin } from \"../../core/plugins.js\";\n\nexport type Redirect = {\n from: string;\n to: string;\n replace?: boolean;\n};\n\nexport const redirectPlugin = (options: {\n redirects: Redirect[];\n}): DevPortalPlugin => {\n return {\n getRoutes: () =>\n options.redirects.map(({ from, to, replace }) => ({\n path: from,\n loader: () => redirect(to),\n })),\n };\n};\n"],"names":["redirectPlugin","options","from","to","replace","redirect"],"mappings":";AASa,MAAAA,IAAiB,CAACC,OAGtB;AAAA,EACL,WAAW,MACTA,EAAQ,UAAU,IAAI,CAAC,EAAE,MAAAC,GAAM,IAAAC,GAAI,SAAAC,SAAe;AAAA,IAChD,MAAMF;AAAA,IACN,QAAQ,MAAMG,EAASF,CAAE;AAAA,EAAA,EACzB;AAAA;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zudoku",
3
- "version": "0.3.0-dev.31",
3
+ "version": "0.3.0-dev.32",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist",
@@ -64,6 +64,7 @@
64
64
  "dependencies": {
65
65
  "@envelop/core": "5.0.1",
66
66
  "@graphql-typed-document-node/core": "3.2.0",
67
+ "@hiogawa/vite-plugin-ssr-css": "0.0.0",
67
68
  "@lekoarts/rehype-meta-as-attributes": "3.0.1",
68
69
  "@mdx-js/react": "3.0.1",
69
70
  "@mdx-js/rollup": "3.0.1",
File without changes
@@ -0,0 +1,51 @@
1
+ import { StrictMode } from "react";
2
+ import { hydrateRoot } from "react-dom/client";
3
+ import { HelmetProvider } from "react-helmet-async";
4
+ import {
5
+ createBrowserRouter,
6
+ matchRoutes,
7
+ type RouteObject,
8
+ RouterProvider,
9
+ } from "react-router-dom";
10
+ import "virtual:vite-zudoku-custom-css.css";
11
+ import config from "virtual:zudoku-config";
12
+
13
+ import "virtual:vite-zudoku-custom-css.css";
14
+ import "./main.css";
15
+
16
+ import { getRoutesByConfig } from "./main.js";
17
+
18
+ void hydrate();
19
+
20
+ export async function hydrateLazyRoutes(routes: RouteObject[]) {
21
+ const lazyMatches = matchRoutes(routes, window.location)?.filter(
22
+ (m) => m.route.lazy,
23
+ );
24
+
25
+ if (lazyMatches?.length) {
26
+ await Promise.all(
27
+ lazyMatches.map(async (m) => {
28
+ const routeModule = await m.route.lazy!();
29
+ Object.assign(m.route, { ...routeModule, lazy: undefined });
30
+ }),
31
+ );
32
+ }
33
+ }
34
+
35
+ async function hydrate() {
36
+ const routes = getRoutesByConfig(config);
37
+
38
+ await hydrateLazyRoutes(routes);
39
+
40
+ const router = createBrowserRouter(routes);
41
+ const root = document.getElementById("root")!;
42
+
43
+ hydrateRoot(
44
+ root,
45
+ <StrictMode>
46
+ <HelmetProvider>
47
+ <RouterProvider router={router} />
48
+ </HelmetProvider>
49
+ </StrictMode>,
50
+ );
51
+ }
@@ -0,0 +1,158 @@
1
+ import type express from "express";
2
+ import logger from "loglevel";
3
+ import { Transform } from "node:stream";
4
+ import { StrictMode } from "react";
5
+ import { renderToPipeableStream, renderToStaticMarkup } from "react-dom/server";
6
+ import { HelmetData, HelmetProvider } from "react-helmet-async";
7
+ import { isRouteErrorResponse } from "react-router-dom";
8
+ import {
9
+ createStaticHandler,
10
+ createStaticRouter,
11
+ StaticRouterProvider,
12
+ } from "react-router-dom/server.js";
13
+ import "virtual:vite-zudoku-custom-css.css";
14
+ import config from "virtual:zudoku-config";
15
+ import { ServerError } from "../lib/errors/ServerError.js";
16
+ import "./main.css";
17
+ import { getRoutesByConfig } from "./main.js";
18
+
19
+ export const render = async ({
20
+ template,
21
+ expressRequest,
22
+ fetchRequest,
23
+ response,
24
+ }: {
25
+ template: string;
26
+ expressRequest?: express.Request;
27
+ fetchRequest?: Request;
28
+ response: express.Response;
29
+ }) => {
30
+ const routes = getRoutesByConfig(config);
31
+ const { query, dataRoutes } = createStaticHandler(routes);
32
+
33
+ const request = expressRequest
34
+ ? createFetchRequest(expressRequest, response)
35
+ : fetchRequest;
36
+
37
+ if (!request) {
38
+ throw new Error("Either fetchRequest or expressRequest must be provided");
39
+ }
40
+ const context = await query(request);
41
+ let status = 200;
42
+
43
+ if (context instanceof Response) {
44
+ if ([301, 302, 303, 307, 308].includes(context.status)) {
45
+ return response.redirect(
46
+ context.status,
47
+ context.headers.get("Location")!,
48
+ );
49
+ }
50
+
51
+ throw context;
52
+ } else if (context.errors) {
53
+ // when throwing a Response from a loader it will be caught here
54
+ // unfortunately it is not `instanceof Response` for some reason
55
+ const firstError = Object.values(context.errors).find(isRouteErrorResponse);
56
+
57
+ if (firstError?.status) {
58
+ status = firstError.status;
59
+ }
60
+ }
61
+
62
+ const router = createStaticRouter(dataRoutes, context);
63
+ const helmetContext = {} as HelmetData["context"];
64
+
65
+ const { pipe } = renderToPipeableStream(
66
+ <StrictMode>
67
+ <HelmetProvider context={helmetContext}>
68
+ <StaticRouterProvider router={router} context={context} />
69
+ </HelmetProvider>
70
+ </StrictMode>,
71
+ {
72
+ onShellError(error) {
73
+ response.status(500);
74
+ response.set({ "Content-Type": "text/html" });
75
+
76
+ const html = renderToStaticMarkup(<ServerError error={error} />);
77
+
78
+ response.send(html);
79
+ },
80
+ // for SSG we could use onAllReady instead of onShellReady
81
+ // https://react.dev/reference/react-dom/server/renderToPipeableStream#waiting-for-all-content-to-load-for-crawlers-and-static-generation
82
+ onShellReady() {
83
+ response.set({ "Content-Type": "text/html" });
84
+ response.status(status);
85
+
86
+ const transformStream = new Transform({
87
+ transform(chunk, encoding, callback) {
88
+ response.write(chunk, encoding);
89
+ callback();
90
+ },
91
+ });
92
+
93
+ const [htmlStart, htmlEnd] = template.split("<!--app-html-->");
94
+
95
+ response.write(
96
+ htmlStart.replace(
97
+ "<!--app-helmet-->",
98
+ [
99
+ helmetContext.helmet.title.toString(),
100
+ helmetContext.helmet.meta.toString(),
101
+ helmetContext.helmet.link.toString(),
102
+ helmetContext.helmet.style.toString(),
103
+ helmetContext.helmet.script.toString(),
104
+ ].join("\n"),
105
+ ),
106
+ );
107
+
108
+ transformStream.on("finish", () => {
109
+ response.end(htmlEnd);
110
+ });
111
+
112
+ pipe(transformStream);
113
+ },
114
+ onError(error) {
115
+ status = 500;
116
+ logger.error(error);
117
+ },
118
+ },
119
+ );
120
+ };
121
+
122
+ export function createFetchRequest(
123
+ req: express.Request,
124
+ res: express.Response,
125
+ ): Request {
126
+ const origin = `${req.protocol}://${req.get("host")}`;
127
+ // Note: This had to take originalUrl into account for presumably vite's proxying
128
+ const url = new URL(req.originalUrl || req.url, origin);
129
+
130
+ const controller = new AbortController();
131
+ res.on("close", () => controller.abort());
132
+
133
+ const headers = new Headers();
134
+
135
+ for (const [key, values] of Object.entries(req.headers)) {
136
+ if (values) {
137
+ if (Array.isArray(values)) {
138
+ for (const value of values) {
139
+ headers.append(key, value);
140
+ }
141
+ } else {
142
+ headers.set(key, values);
143
+ }
144
+ }
145
+ }
146
+
147
+ const init: RequestInit = {
148
+ method: req.method,
149
+ headers,
150
+ signal: controller.signal,
151
+ };
152
+
153
+ if (req.method !== "GET" && req.method !== "HEAD") {
154
+ init.body = req.body;
155
+ }
156
+
157
+ return new Request(url.href, init);
158
+ }
package/src/app/main.tsx CHANGED
@@ -1,51 +1,73 @@
1
- import { StrictMode } from "react";
2
- import { createRoot } from "react-dom/client";
3
-
4
- // Styles
5
- import "./main.css";
6
-
7
- // Logger
8
- import "../lib/util/logInit.js";
9
-
10
- // Config
11
- import config from "virtual:zudoku-config";
12
-
13
- // Plugins
1
+ import { type RouteObject } from "react-router-dom";
14
2
  import { configuredApiKeysPlugin } from "virtual:zudoku-api-keys-plugin";
15
3
  import { configuredApiPlugins } from "virtual:zudoku-api-plugins";
16
4
  import { configuredAuthProvider } from "virtual:zudoku-auth";
17
5
  import { configuredDocsPlugins } from "virtual:zudoku-docs-plugins";
18
6
  import { configuredRedirectPlugin } from "virtual:zudoku-redirect-plugin";
19
-
20
- // Base React Component
21
7
  import { DevPortal } from "zudoku/components";
8
+ import type { ZudokuConfig } from "../config/config.js";
9
+ import { Layout } from "../lib/components/Layout.js";
10
+ import { isNavigationPlugin } from "../lib/core/plugins.js";
11
+ import { RouterError } from "../lib/errors/RouterError.js";
12
+
13
+ import "virtual:vite-zudoku-custom-css.css";
14
+
15
+ export const convertZudokuConfigToOptions = (config: ZudokuConfig) => {
16
+ return {
17
+ page: {
18
+ logo: config.page?.logo ?? "https://cdn.zudoku.dev/logos/icon.svg",
19
+ pageTitle: "Developer Portal",
20
+ ...config.page,
21
+ },
22
+ metadata: {
23
+ favicon: "https://cdn.zudoku.dev/logos/icon.svg",
24
+ title: "%s | Developer Portal",
25
+ ...config.metadata,
26
+ },
27
+ navigation: config.navigation ?? [],
28
+ authentication: configuredAuthProvider,
29
+ plugins: [
30
+ ...configuredDocsPlugins,
31
+ ...configuredApiPlugins,
32
+ ...(configuredRedirectPlugin ? [configuredRedirectPlugin] : []),
33
+ ...(configuredApiKeysPlugin ? [configuredApiKeysPlugin] : []),
34
+ ...(configuredAuthProvider ? [configuredAuthProvider] : []),
35
+ ],
36
+ };
37
+ };
38
+
39
+ export const getRoutesByConfig = (config: ZudokuConfig): RouteObject[] => {
40
+ const options = convertZudokuConfigToOptions(config);
41
+
42
+ const allPlugins = [
43
+ ...options.plugins,
44
+ ...(options.authentication ? [options.authentication] : []),
45
+ ];
22
46
 
23
- // IMPORTANT: This component must not contain tailwind classes
24
- // This directory is not processed by the tailwind plugin
47
+ const routes = allPlugins
48
+ .flatMap((plugin) => (isNavigationPlugin(plugin) ? plugin.getRoutes() : []))
49
+ .concat({
50
+ path: "*",
51
+ loader: () => {
52
+ throw new Response("Not Found", { status: 404 });
53
+ },
54
+ });
25
55
 
26
- createRoot(document.getElementById("root")!).render(
27
- <StrictMode>
28
- <DevPortal
29
- page={{
30
- logo: config.page?.logo ?? "https://cdn.zudoku.dev/logos/icon.svg",
31
- pageTitle: "Developer Portal",
32
- ...config.page,
33
- }}
34
- metadata={{
35
- favicon: "https://cdn.zudoku.dev/logos/icon.svg",
36
- title: "%s | Developer Portal",
37
- ...config.metadata,
38
- }}
39
- navigation={config.navigation ?? []}
40
- authentication={configuredAuthProvider}
41
- mdxComponents={config.mdx?.components}
42
- plugins={[
43
- ...configuredDocsPlugins,
44
- ...configuredApiPlugins,
45
- configuredRedirectPlugin,
46
- ...(configuredApiKeysPlugin ? [configuredApiKeysPlugin] : []),
47
- ...(configuredAuthProvider ? [configuredAuthProvider] : []),
48
- ]}
49
- />
50
- </StrictMode>,
51
- );
56
+ return [
57
+ {
58
+ element: (
59
+ <DevPortal {...options}>
60
+ <Layout />
61
+ </DevPortal>
62
+ ),
63
+ errorElement: (
64
+ <DevPortal {...options}>
65
+ <Layout>
66
+ <RouterError />
67
+ </Layout>
68
+ </DevPortal>
69
+ ),
70
+ children: routes,
71
+ },
72
+ ];
73
+ };
@@ -2,8 +2,14 @@ import typographyPlugin from "@tailwindcss/typography";
2
2
  import type { Config } from "tailwindcss";
3
3
  import defaultTheme from "tailwindcss/defaultTheme.js";
4
4
 
5
+ const content = [
6
+ "./src/**/*.{js,ts,jsx,tsx,md,mdx}",
7
+ "./node_modules/zudoku/dist/**/*.{js,ts,jsx,tsx,md,mdx}",
8
+ ];
9
+
5
10
  const config: Omit<Config, "content"> = {
6
11
  darkMode: "selector",
12
+ content,
7
13
  theme: {
8
14
  extend: {
9
15
  fontFamily: {
@@ -0,0 +1,22 @@
1
+ import type { RouteObject } from "react-router-dom";
2
+ import config from "virtual:zudoku-config";
3
+ import { getRoutesByConfig } from "./main.js";
4
+
5
+ const routes = getRoutesByConfig(config);
6
+
7
+ const flattenPaths = (routes: RouteObject[], basePath = "") => {
8
+ return routes.reduce<string[]>((acc, route) => {
9
+ if (route.path) {
10
+ const fullPath = `${basePath}/${route.path}`.replace(/\/+/g, "/");
11
+ route.path !== "/" && acc.push(fullPath);
12
+ if (route.children) {
13
+ acc = acc.concat(flattenPaths(route.children, fullPath));
14
+ }
15
+ } else if (route.children) {
16
+ acc = acc.concat(flattenPaths(route.children, basePath));
17
+ }
18
+ return acc;
19
+ }, []);
20
+ };
21
+
22
+ export const paths = flattenPaths(routes);
@@ -9,6 +9,7 @@ const clerkAuth: AuthenticationProviderInitializer<
9
9
  let clerkApi: Clerk;
10
10
 
11
11
  const ensureLoaded = (async () => {
12
+ if (import.meta.env.SSR) return;
12
13
  const { Clerk } = await import("@clerk/clerk-js");
13
14
  clerkApi = new Clerk(clerkPubKey);
14
15
 
@@ -1,8 +1,14 @@
1
1
  import { MDXProvider } from "@mdx-js/react";
2
2
  import { QueryClientProvider } from "@tanstack/react-query";
3
- import { Fragment, memo, Suspense, useEffect, useMemo } from "react";
3
+ import {
4
+ Fragment,
5
+ memo,
6
+ type PropsWithChildren,
7
+ useEffect,
8
+ useMemo,
9
+ } from "react";
4
10
  import { ErrorBoundary } from "react-error-boundary";
5
- import { Helmet, HelmetProvider } from "react-helmet-async";
11
+ import { Helmet } from "react-helmet-async";
6
12
  import {
7
13
  DevPortalContext,
8
14
  queryClient,
@@ -18,9 +24,8 @@ import {
18
24
  import { DevPortalProvider } from "./context/DevPortalProvider.js";
19
25
  import { ThemeProvider } from "./context/ThemeContext.js";
20
26
  import { ViewportAnchorProvider } from "./context/ViewportAnchorContext.js";
21
- import { Router } from "./Router.js";
22
27
 
23
- const DevPortalSystemPaths = {
28
+ export const DevPortalSystemPaths = {
24
29
  Settings: "/settings",
25
30
  } as const;
26
31
 
@@ -28,7 +33,10 @@ export type DevPortalPath =
28
33
  | string
29
34
  | (typeof DevPortalSystemPaths)[keyof typeof DevPortalSystemPaths];
30
35
 
31
- const DevPortalInner = (props: ZudokuContextOptions) => {
36
+ const DevPortalInner = ({
37
+ children,
38
+ ...props
39
+ }: PropsWithChildren<ZudokuContextOptions>) => {
32
40
  const components = useMemo(
33
41
  () => ({ ...DEFAULT_COMPONENTS, ...props.overrides }),
34
42
  [props.overrides],
@@ -52,39 +60,23 @@ const DevPortalInner = (props: ZudokuContextOptions) => {
52
60
 
53
61
  return (
54
62
  <QueryClientProvider client={queryClient}>
55
- <HelmetProvider>
56
- <Helmet>{heads}</Helmet>
57
- <DevPortalProvider value={devPortalContext}>
58
- <MDXProvider components={mdxComponents}>
59
- <ThemeProvider>
60
- <ComponentsProvider value={components}>
61
- <ViewportAnchorProvider>
62
- <Suspense
63
- fallback={
64
- <div className="grid place-items-center h-full">
65
- Loading...
66
- </div>
67
- }
68
- >
69
- <Router
70
- plugins={[
71
- ...(props.plugins ?? []),
72
- ...(props.authentication ? [props.authentication] : []),
73
- ]}
74
- />
75
- </Suspense>
76
- </ViewportAnchorProvider>
77
- </ComponentsProvider>
78
- </ThemeProvider>
79
- </MDXProvider>
80
- </DevPortalProvider>
81
- </HelmetProvider>
63
+ <Helmet>{heads}</Helmet>
64
+ <DevPortalProvider value={devPortalContext}>
65
+ <MDXProvider components={mdxComponents}>
66
+ <ThemeProvider>
67
+ <ComponentsProvider value={components}>
68
+ <ViewportAnchorProvider>{children}</ViewportAnchorProvider>
69
+ </ComponentsProvider>
70
+ </ThemeProvider>
71
+ </MDXProvider>
72
+ </DevPortalProvider>
82
73
  </QueryClientProvider>
83
74
  );
84
75
  };
85
76
 
77
+ const Inner = memo(DevPortalInner);
78
+
86
79
  const DevPortal = (props: ZudokuContextOptions) => {
87
- const Inner = memo(DevPortalInner);
88
80
  return (
89
81
  <ErrorBoundary FallbackComponent={TopLevelError}>
90
82
  <Inner {...props} />
@@ -0,0 +1,28 @@
1
+ import type { ReactNode } from "react";
2
+ import { Link } from "react-router-dom";
3
+ import { CategoryHeading } from "./CategoryHeading.js";
4
+ import { Heading } from "./Heading.js";
5
+ import { ProseClasses } from "./Markdown.js";
6
+
7
+ export const ErrorPage = ({
8
+ title = "An error occurred",
9
+ message,
10
+ category,
11
+ }: {
12
+ title?: ReactNode;
13
+ message?: ReactNode;
14
+ category?: ReactNode;
15
+ }) => {
16
+ return (
17
+ <div className={ProseClasses + " h-full pt-[--padding-content-top]"}>
18
+ {category && <CategoryHeading>{category}</CategoryHeading>}
19
+ {title && (
20
+ <Heading level={1} className="flex gap-3.5 items-center">
21
+ {title}
22
+ </Heading>
23
+ )}
24
+ <p>{message}</p>
25
+ <Link to="/">Go back home</Link>
26
+ </div>
27
+ );
28
+ };
@@ -0,0 +1,19 @@
1
+ import type { ReactNode } from "react";
2
+ import { cn } from "../util/cn.js";
3
+
4
+ export const InlineCode = ({
5
+ className,
6
+ children,
7
+ }: {
8
+ className?: string;
9
+ children: ReactNode;
10
+ }) => (
11
+ <code
12
+ className={cn(
13
+ className,
14
+ "font-mono border border-border p-1 py-0.5 rounded bg-border/50 dark:bg-border/70 whitespace-nowrap",
15
+ )}
16
+ >
17
+ {children}
18
+ </code>
19
+ );
@@ -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
+ };