zudoku 0.3.0-dev.2 → 0.3.0-dev.20

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 (220) hide show
  1. package/dist/app/App.js +11 -8
  2. package/dist/app/App.js.map +1 -1
  3. package/dist/config/config.d.ts +8 -15
  4. package/dist/lib/authentication/authentication.d.ts +2 -2
  5. package/dist/lib/authentication/hook.d.ts +1 -0
  6. package/dist/lib/authentication/hook.js +1 -0
  7. package/dist/lib/authentication/hook.js.map +1 -1
  8. package/dist/lib/authentication/providers/auth0.js +1 -0
  9. package/dist/lib/authentication/providers/auth0.js.map +1 -1
  10. package/dist/lib/authentication/providers/clerk.js +2 -0
  11. package/dist/lib/authentication/providers/clerk.js.map +1 -1
  12. package/dist/lib/authentication/providers/openid.js +2 -0
  13. package/dist/lib/authentication/providers/openid.js.map +1 -1
  14. package/dist/lib/authentication/state.d.ts +1 -0
  15. package/dist/lib/authentication/state.js +1 -0
  16. package/dist/lib/authentication/state.js.map +1 -1
  17. package/dist/lib/components/DevPortal.d.ts +2 -20
  18. package/dist/lib/components/DevPortal.js +13 -9
  19. package/dist/lib/components/DevPortal.js.map +1 -1
  20. package/dist/lib/components/Header.js +4 -4
  21. package/dist/lib/components/Header.js.map +1 -1
  22. package/dist/lib/components/Heading.d.ts +9 -4
  23. package/dist/lib/components/Heading.js +17 -2
  24. package/dist/lib/components/Heading.js.map +1 -1
  25. package/dist/lib/components/Layout.js +1 -1
  26. package/dist/lib/components/Layout.js.map +1 -1
  27. package/dist/lib/components/SyntaxHighlight.js +5 -1
  28. package/dist/lib/components/SyntaxHighlight.js.map +1 -1
  29. package/dist/lib/components/context/DevPortalProvider.d.ts +1 -1
  30. package/dist/lib/components/context/DevPortalProvider.js +2 -2
  31. package/dist/lib/components/context/DevPortalProvider.js.map +1 -1
  32. package/dist/lib/components/index.d.ts +2 -0
  33. package/dist/lib/components/index.js +2 -0
  34. package/dist/lib/components/index.js.map +1 -1
  35. package/dist/lib/core/DevPortalContext.d.ts +33 -3
  36. package/dist/lib/core/DevPortalContext.js +8 -4
  37. package/dist/lib/core/DevPortalContext.js.map +1 -1
  38. package/dist/lib/core/plugins.d.ts +7 -4
  39. package/dist/lib/core/plugins.js +1 -0
  40. package/dist/lib/core/plugins.js.map +1 -1
  41. package/dist/lib/oas/graphql/index.js +1 -1
  42. package/dist/lib/oas/graphql/index.js.map +1 -1
  43. package/dist/lib/oas/parser/index.js +3 -1
  44. package/dist/lib/oas/parser/index.js.map +1 -1
  45. package/dist/lib/plugins/api-keys/CreateApiKey.d.ts +4 -0
  46. package/dist/lib/plugins/{api-key → api-keys}/CreateApiKey.js +1 -1
  47. package/dist/lib/plugins/api-keys/CreateApiKey.js.map +1 -0
  48. package/dist/lib/plugins/api-keys/SettingsApiKeys.d.ts +4 -0
  49. package/dist/lib/plugins/api-keys/SettingsApiKeys.js +38 -0
  50. package/dist/lib/plugins/api-keys/SettingsApiKeys.js.map +1 -0
  51. package/dist/lib/plugins/api-keys/index.js +94 -0
  52. package/dist/lib/plugins/api-keys/index.js.map +1 -0
  53. package/dist/lib/plugins/markdown/MdxPage.d.ts +3 -2
  54. package/dist/lib/plugins/markdown/MdxPage.js +5 -4
  55. package/dist/lib/plugins/markdown/MdxPage.js.map +1 -1
  56. package/dist/lib/plugins/markdown/generateRoutes.d.ts +2 -2
  57. package/dist/lib/plugins/markdown/generateRoutes.js +2 -2
  58. package/dist/lib/plugins/markdown/generateRoutes.js.map +1 -1
  59. package/dist/lib/plugins/markdown/index.d.ts +4 -1
  60. package/dist/lib/plugins/markdown/index.js +2 -2
  61. package/dist/lib/plugins/markdown/index.js.map +1 -1
  62. package/dist/lib/plugins/openapi/OperationList.js +4 -3
  63. package/dist/lib/plugins/openapi/OperationList.js.map +1 -1
  64. package/dist/lib/plugins/openapi/OperationListItem.js +8 -4
  65. package/dist/lib/plugins/openapi/OperationListItem.js.map +1 -1
  66. package/dist/lib/plugins/openapi/ParameterList.js +1 -1
  67. package/dist/lib/plugins/openapi/ParameterList.js.map +1 -1
  68. package/dist/lib/plugins/openapi/ParameterListItem.js +1 -1
  69. package/dist/lib/plugins/openapi/ParameterListItem.js.map +1 -1
  70. package/dist/lib/plugins/openapi/{MakeRequest.d.ts → PlaygroundDialogWrapper.d.ts} +1 -1
  71. package/dist/lib/plugins/openapi/{MakeRequest.js → PlaygroundDialogWrapper.js} +4 -4
  72. package/dist/lib/plugins/openapi/PlaygroundDialogWrapper.js.map +1 -0
  73. package/dist/lib/plugins/openapi/RequestBodySidecarBox.js +1 -9
  74. package/dist/lib/plugins/openapi/RequestBodySidecarBox.js.map +1 -1
  75. package/dist/lib/plugins/openapi/ResponsesSidecarBox.js +1 -1
  76. package/dist/lib/plugins/openapi/ResponsesSidecarBox.js.map +1 -1
  77. package/dist/lib/plugins/openapi/SchemaListView.js +4 -26
  78. package/dist/lib/plugins/openapi/SchemaListView.js.map +1 -1
  79. package/dist/lib/plugins/openapi/SchemaListViewItem.d.ts +7 -0
  80. package/dist/lib/plugins/openapi/SchemaListViewItem.js +16 -0
  81. package/dist/lib/plugins/openapi/SchemaListViewItem.js.map +1 -0
  82. package/dist/lib/plugins/openapi/SchemaListViewItemGroup.d.ts +8 -0
  83. package/dist/lib/plugins/openapi/SchemaListViewItemGroup.js +17 -0
  84. package/dist/lib/plugins/openapi/SchemaListViewItemGroup.js.map +1 -0
  85. package/dist/lib/plugins/openapi/Sidecar.js +10 -8
  86. package/dist/lib/plugins/openapi/Sidecar.js.map +1 -1
  87. package/dist/lib/plugins/openapi/{Select.d.ts → SimpleSelect.d.ts} +3 -2
  88. package/dist/lib/plugins/openapi/SimpleSelect.js +5 -0
  89. package/dist/lib/plugins/openapi/SimpleSelect.js.map +1 -0
  90. package/dist/lib/plugins/openapi/index.js +8 -0
  91. package/dist/lib/plugins/openapi/index.js.map +1 -1
  92. package/dist/lib/plugins/openapi/playground/Headers.d.ts +2 -3
  93. package/dist/lib/plugins/openapi/playground/Headers.js +16 -6
  94. package/dist/lib/plugins/openapi/playground/Headers.js.map +1 -1
  95. package/dist/lib/plugins/openapi/playground/Playground.d.ts +4 -3
  96. package/dist/lib/plugins/openapi/playground/Playground.js +8 -12
  97. package/dist/lib/plugins/openapi/playground/Playground.js.map +1 -1
  98. package/dist/lib/plugins/openapi/playground/PlaygroundDialog.d.ts +3 -0
  99. package/dist/lib/plugins/openapi/playground/PlaygroundDialog.js +10 -0
  100. package/dist/lib/plugins/openapi/playground/PlaygroundDialog.js.map +1 -0
  101. package/dist/lib/plugins/openapi/util/prose.d.ts +1 -0
  102. package/dist/lib/plugins/openapi/util/prose.js +4 -0
  103. package/dist/lib/plugins/openapi/util/prose.js.map +1 -0
  104. package/dist/lib/plugins/openapi/worker/worker.js +25 -1
  105. package/dist/lib/plugins/openapi/worker/worker.js.map +1 -1
  106. package/dist/lib/ui/button-variants.d.ts +1 -1
  107. package/dist/lib/util/MdxComponents.js +1 -1
  108. package/dist/lib/util/MdxComponents.js.map +1 -1
  109. package/dist/lib/util/objectEntries.d.ts +4 -0
  110. package/dist/lib/util/objectEntries.js +2 -0
  111. package/dist/lib/util/objectEntries.js.map +1 -0
  112. package/dist/lib/util/renderIf.d.ts +1 -0
  113. package/dist/lib/util/renderIf.js +2 -0
  114. package/dist/lib/util/renderIf.js.map +1 -0
  115. package/dist/vite/config.js +1 -2
  116. package/dist/vite/config.js.map +1 -1
  117. package/dist/vite/config.test.js +1 -1
  118. package/dist/vite/config.test.js.map +1 -1
  119. package/dist/vite/dev-server.js +1 -1
  120. package/dist/vite/dev-server.js.map +1 -1
  121. package/dist/vite/plugin-api-keys.js +2 -2
  122. package/dist/vite/plugin-api-keys.js.map +1 -1
  123. package/dist/vite/plugin-api.js +3 -3
  124. package/dist/vite/plugin-api.js.map +1 -1
  125. package/dist/vite/plugin-docs.js +2 -2
  126. package/dist/vite/plugin-docs.js.map +1 -1
  127. package/dist/vite/plugin-docs.test.js +1 -1
  128. package/dist/vite/plugin-docs.test.js.map +1 -1
  129. package/dist/vite/plugin-redirect.js +2 -2
  130. package/dist/vite/plugin-redirect.js.map +1 -1
  131. package/lib/DevPortalProvider-CRKuwoXc.js +4123 -0
  132. package/lib/Markdown-5LmPZyLV.js +8620 -0
  133. package/lib/MdxComponents-DYD_QPVF.js +3017 -0
  134. package/lib/Select-DR3PiqjV.js +4569 -0
  135. package/lib/Spinner-DjQ2eBxC.js +181 -0
  136. package/lib/assets/{worker-BCcpCNJ7.js → worker-DGvzLstc.js} +9843 -9800
  137. package/lib/hook-FCY9-FHO.js +24 -0
  138. package/lib/index-By9bEW57.js +411 -0
  139. package/lib/{index-DNx3xWa2.js → index-PyGcnQFX.js} +13 -12
  140. package/lib/loglevel-CA34MiFn.js +152 -0
  141. package/lib/prism-csharp.min-Yizuc34Y.js +34 -0
  142. package/lib/prism-objectivec.min-BXSWqpJJ.js +1 -0
  143. package/lib/{state-oycsxkHz.js → state-Ds_OxRHP.js} +19 -18
  144. package/lib/util-voKLTRDG.js +740 -0
  145. package/lib/zudoku.auth-auth0.js +2 -1
  146. package/lib/zudoku.auth-clerk.js +10 -8
  147. package/lib/zudoku.auth-openid.js +442 -588
  148. package/lib/zudoku.components.js +283 -292
  149. package/lib/zudoku.openapi-worker.js +12 -12
  150. package/lib/zudoku.plugin-api-keys.js +292 -0
  151. package/lib/zudoku.plugin-markdown.js +255 -0
  152. package/lib/zudoku.plugin-openapi.js +6240 -0
  153. package/lib/zudoku.plugin-redirect.js +10 -0
  154. package/package.json +17 -4
  155. package/src/app/App.tsx +12 -8
  156. package/src/lib/authentication/authentication.ts +2 -5
  157. package/src/lib/authentication/hook.ts +1 -0
  158. package/src/lib/authentication/providers/auth0.tsx +1 -0
  159. package/src/lib/authentication/providers/clerk.tsx +2 -0
  160. package/src/lib/authentication/providers/openid.tsx +2 -0
  161. package/src/lib/authentication/state.ts +2 -0
  162. package/src/lib/components/DevPortal.tsx +12 -28
  163. package/src/lib/components/Header.tsx +25 -22
  164. package/src/lib/components/Heading.tsx +26 -7
  165. package/src/lib/components/Layout.tsx +2 -2
  166. package/src/lib/components/SyntaxHighlight.tsx +5 -1
  167. package/src/lib/components/context/DevPortalProvider.ts +2 -2
  168. package/src/lib/components/index.ts +3 -0
  169. package/src/lib/core/DevPortalContext.ts +42 -12
  170. package/src/lib/core/plugins.ts +10 -5
  171. package/src/lib/oas/graphql/index.ts +2 -2
  172. package/src/lib/oas/parser/index.ts +3 -1
  173. package/src/lib/plugins/{api-key → api-keys}/CreateApiKey.tsx +2 -8
  174. package/src/lib/plugins/{api-key → api-keys}/SettingsApiKeys.tsx +21 -14
  175. package/src/lib/plugins/{api-key → api-keys}/index.tsx +67 -18
  176. package/src/lib/plugins/markdown/MdxPage.tsx +50 -33
  177. package/src/lib/plugins/markdown/generateRoutes.tsx +12 -2
  178. package/src/lib/plugins/markdown/index.tsx +8 -1
  179. package/src/lib/plugins/openapi/OperationList.tsx +9 -3
  180. package/src/lib/plugins/openapi/OperationListItem.tsx +66 -41
  181. package/src/lib/plugins/openapi/ParameterList.tsx +1 -1
  182. package/src/lib/plugins/openapi/ParameterListItem.tsx +3 -4
  183. package/src/lib/plugins/openapi/{MakeRequest.tsx → PlaygroundDialogWrapper.tsx} +3 -3
  184. package/src/lib/plugins/openapi/RequestBodySidecarBox.tsx +2 -16
  185. package/src/lib/plugins/openapi/ResponsesSidecarBox.tsx +3 -1
  186. package/src/lib/plugins/openapi/SchemaListView.tsx +15 -182
  187. package/src/lib/plugins/openapi/SchemaListViewItem.tsx +110 -0
  188. package/src/lib/plugins/openapi/SchemaListViewItemGroup.tsx +63 -0
  189. package/src/lib/plugins/openapi/Sidecar.tsx +15 -10
  190. package/src/lib/plugins/openapi/{Select.tsx → SimpleSelect.tsx} +5 -2
  191. package/src/lib/plugins/openapi/index.tsx +17 -4
  192. package/src/lib/plugins/openapi/playground/Headers.tsx +60 -33
  193. package/src/lib/plugins/openapi/playground/Playground.tsx +158 -193
  194. package/src/lib/plugins/openapi/playground/PlaygroundDialog.tsx +34 -0
  195. package/src/lib/plugins/openapi/util/prose.ts +7 -0
  196. package/src/lib/plugins/openapi/worker/worker.ts +27 -1
  197. package/src/lib/util/MdxComponents.tsx +1 -1
  198. package/src/lib/util/objectEntries.ts +5 -0
  199. package/src/lib/util/renderIf.ts +4 -0
  200. package/dist/lib/plugins/api-key/CreateApiKey.d.ts +0 -5
  201. package/dist/lib/plugins/api-key/CreateApiKey.js.map +0 -1
  202. package/dist/lib/plugins/api-key/SettingsApiKeys.d.ts +0 -5
  203. package/dist/lib/plugins/api-key/SettingsApiKeys.js +0 -38
  204. package/dist/lib/plugins/api-key/SettingsApiKeys.js.map +0 -1
  205. package/dist/lib/plugins/api-key/index.js +0 -62
  206. package/dist/lib/plugins/api-key/index.js.map +0 -1
  207. package/dist/lib/plugins/index.d.ts +0 -4
  208. package/dist/lib/plugins/index.js +0 -5
  209. package/dist/lib/plugins/index.js.map +0 -1
  210. package/dist/lib/plugins/openapi/MakeRequest.js.map +0 -1
  211. package/dist/lib/plugins/openapi/Select.js +0 -5
  212. package/dist/lib/plugins/openapi/Select.js.map +0 -1
  213. package/dist/vite/common.d.ts +0 -1
  214. package/dist/vite/common.js +0 -5
  215. package/dist/vite/common.js.map +0 -1
  216. package/lib/Spinner-7LezPqGn.js +0 -8393
  217. package/lib/clerk-Wslx_mPo.js +0 -19685
  218. package/lib/zudoku.plugins.js +0 -19857
  219. package/src/lib/plugins/index.ts +0 -4
  220. /package/dist/lib/plugins/{api-key → api-keys}/index.d.ts +0 -0
@@ -0,0 +1,10 @@
1
+ import { j as a, N as i } from "./index-PyGcnQFX.js";
2
+ const m = (e) => ({
3
+ getRoutes: () => e.redirects.map(({ from: t, to: r, replace: s }) => ({
4
+ path: t,
5
+ element: /* @__PURE__ */ a.jsx(i, { to: r, replace: s })
6
+ }))
7
+ });
8
+ export {
9
+ m as redirectPlugin
10
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zudoku",
3
- "version": "0.3.0-dev.2",
3
+ "version": "0.3.0-dev.20",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist",
@@ -27,8 +27,17 @@
27
27
  "./auth/openid": {
28
28
  "import": "./lib/zudoku.auth-openid.js"
29
29
  },
30
- "./plugins": {
31
- "import": "./lib/zudoku.plugins.js"
30
+ "./plugins/api-keys": {
31
+ "import": "./lib/zudoku.plugin-api-keys.js"
32
+ },
33
+ "./plugins/markdown": {
34
+ "import": "./lib/zudoku.plugin-markdown.js"
35
+ },
36
+ "./plugins/openapi": {
37
+ "import": "./lib/zudoku.plugin-openapi.js"
38
+ },
39
+ "./plugins/redirect": {
40
+ "import": "./lib/zudoku.plugin-redirect.js"
32
41
  },
33
42
  "./openapi-worker": {
34
43
  "import": "./lib/zudoku.openapi-worker.js"
@@ -53,6 +62,7 @@
53
62
  }
54
63
  },
55
64
  "dependencies": {
65
+ "@envelop/core": "5.0.1",
56
66
  "@graphql-typed-document-node/core": "3.2.0",
57
67
  "@lekoarts/rehype-meta-as-attributes": "3.0.1",
58
68
  "@mdx-js/react": "3.0.1",
@@ -96,10 +106,12 @@
96
106
  "remark-frontmatter": "5.0.0",
97
107
  "remark-gfm": "4.0.0",
98
108
  "remark-mdx-frontmatter": "5.0.0",
109
+ "rollup": "^4.18.1",
99
110
  "semver": "7.6.2",
100
111
  "slugify": "1.6.6",
101
112
  "strip-ansi": "7.1.0",
102
113
  "tailwindcss": "3.4.4",
114
+ "tiny-invariant": "1.3.3",
103
115
  "ulidx": "^2.3.0",
104
116
  "unist-util-visit": "5.0.0",
105
117
  "urql": "4.1.0",
@@ -116,12 +128,12 @@
116
128
  "@types/express": "^4.17.21",
117
129
  "@types/har-format": "^1.2.15",
118
130
  "@types/json-schema": "7.0.15",
119
- "@types/loglevel": "^1.6.3",
120
131
  "@types/mdx": "2.0.13",
121
132
  "@types/node": "20.12.10",
122
133
  "@types/object-hash": "^3.0.6",
123
134
  "@types/react": "18.3.3",
124
135
  "@types/react-dom": "18.3.0",
136
+ "@types/rollup": "^0.54.0",
125
137
  "@types/semver": "^7.5.8",
126
138
  "@types/yargs": "^17.0.32",
127
139
  "@zudoku/httpsnippet": "10.0.9",
@@ -134,6 +146,7 @@
134
146
  "react-helmet-async": "2.0.5",
135
147
  "react-markdown": "9.0.1",
136
148
  "react-router-dom": "6.24.1",
149
+ "rollup-plugin-visualizer": "^5.12.0",
137
150
  "tailwind-merge": "2.3.0",
138
151
  "typescript": "5.5.3",
139
152
  "zustand": "4.5.4"
package/src/app/App.tsx CHANGED
@@ -19,21 +19,25 @@ import { DevPortal } from "zudoku/components";
19
19
  export default function App() {
20
20
  return (
21
21
  <DevPortal
22
- meta={{
23
- headerTitle: config.ui?.headerTitle ?? "Developer Portal",
24
- pageTitle: config.ui?.pageTitle ?? "%s | Dev Portal",
25
- logo: config.ui?.logo ?? "https://cdn.zuplo.com/www/favicon.png",
26
- favicon:
27
- config.ui?.metadata?.favicon ??
28
- "https://cdn.zuplo.com/www/favicon.png",
22
+ page={{
23
+ logo: config.page?.logo ?? "https://cdn.zuplo.com/www/favicon.png",
24
+ pageTitle: "Developer Portal",
25
+ ...config.page,
26
+ }}
27
+ metadata={{
28
+ favicon: "https://cdn.zuplo.com/www/favicon.png",
29
+ title: "%s | Developer Portal",
30
+ ...config.metadata,
29
31
  }}
30
32
  navigation={config.navigation ?? []}
31
33
  authentication={configuredAuthProvider}
34
+ mdxComponents={config.mdx?.components}
32
35
  plugins={[
33
36
  ...configuredDocsPlugins,
34
37
  ...configuredApiPlugins,
35
- configuredApiKeysPlugin,
36
38
  configuredRedirectPlugin,
39
+ ...(configuredApiKeysPlugin ? [configuredApiKeysPlugin] : []),
40
+ ...(configuredAuthProvider ? [configuredAuthProvider] : []),
37
41
  ]}
38
42
  />
39
43
  );
@@ -1,9 +1,6 @@
1
- import {
2
- InitializationPlugin,
3
- NavigationPlugin,
4
- } from "../../lib/core/plugins.js";
1
+ import { CommonPlugin, NavigationPlugin } from "../../lib/core/plugins.js";
5
2
 
6
- type AuthenticationPlugin = NavigationPlugin & InitializationPlugin;
3
+ type AuthenticationPlugin = NavigationPlugin & CommonPlugin;
7
4
 
8
5
  export interface AuthenticationProvider extends AuthenticationPlugin {
9
6
  login(): Promise<void>;
@@ -8,6 +8,7 @@ export const useAuth = () => {
8
8
 
9
9
  return {
10
10
  isAuthEnabled,
11
+ isPending: authState.isPending,
11
12
  profile: authState.profile,
12
13
  isAuthenticated: authState.profile,
13
14
 
@@ -7,6 +7,7 @@ class Auth0AuthenticationProvider extends OpenIDAuthenticationProvider {
7
7
  override async logout(): Promise<void> {
8
8
  useAuthState.setState({
9
9
  isAuthenticated: false,
10
+ isPending: false,
10
11
  profile: undefined,
11
12
  });
12
13
  const as = await this.getAuthServer();
@@ -34,6 +34,7 @@ const clerkAuth: AuthenticationProviderInitializer<
34
34
  if (clerkApi.session) {
35
35
  useAuthState.setState({
36
36
  isAuthenticated: true,
37
+ isPending: false,
37
38
  profile: {
38
39
  sub: clerkApi.session.user.id,
39
40
  name: clerkApi.session.user.fullName ?? undefined,
@@ -46,6 +47,7 @@ const clerkAuth: AuthenticationProviderInitializer<
46
47
  } else {
47
48
  useAuthState.setState({
48
49
  isAuthenticated: false,
50
+ isPending: false,
49
51
  profile: undefined,
50
52
  });
51
53
  }
@@ -180,6 +180,7 @@ export class OpenIDAuthenticationProvider implements AuthenticationProvider {
180
180
  async logout(): Promise<void> {
181
181
  useAuthState.setState({
182
182
  isAuthenticated: false,
183
+ isPending: false,
183
184
  profile: undefined,
184
185
  });
185
186
 
@@ -293,6 +294,7 @@ export class OpenIDAuthenticationProvider implements AuthenticationProvider {
293
294
 
294
295
  useAuthState.setState({
295
296
  isAuthenticated: true,
297
+ isPending: false,
296
298
  profile,
297
299
  });
298
300
 
@@ -1,11 +1,13 @@
1
1
  import { create } from "zustand";
2
2
 
3
3
  export const useAuthState = create<AuthState>(() => ({
4
+ isPending: true,
4
5
  isAuthenticated: false,
5
6
  }));
6
7
 
7
8
  export interface AuthState {
8
9
  isAuthenticated: boolean;
10
+ isPending: boolean;
9
11
  profile?: UserProfile;
10
12
  }
11
13
 
@@ -1,24 +1,17 @@
1
- /* eslint-disable react/destructuring-assignment */
2
1
  import { MDXProvider } from "@mdx-js/react";
3
2
  import { QueryClientProvider } from "@tanstack/react-query";
4
- import { memo, Suspense, useEffect, useMemo } from "react";
3
+ import { Fragment, memo, Suspense, useEffect, useMemo } from "react";
5
4
  import {
6
5
  DevPortalContext,
7
6
  queryClient,
8
- type NavigationItem,
7
+ ZudokuContextOptions,
9
8
  } from "../core/DevPortalContext.js";
10
- import { HelmetProvider } from "../core/helmet.js";
11
- import { type DevPortalPlugin } from "../core/plugins.js";
12
-
13
- import { AuthenticationProvider } from "../authentication/authentication.js";
14
- import {
15
- MdxComponents,
16
- type MdxComponentsType,
17
- } from "../util/MdxComponents.js";
9
+ import { Helmet, HelmetProvider } from "../core/helmet.js";
10
+ import { hasHead } from "../core/plugins.js";
11
+ import { MdxComponents } from "../util/MdxComponents.js";
18
12
  import {
19
13
  ComponentsProvider,
20
14
  DEFAULT_COMPONENTS,
21
- type ComponentsContextType,
22
15
  } from "./context/ComponentsContext.js";
23
16
  import { DevPortalProvider } from "./context/DevPortalProvider.js";
24
17
  import { ThemeProvider } from "./context/ThemeContext.js";
@@ -33,22 +26,7 @@ export type DevPortalPath =
33
26
  | string
34
27
  | (typeof DevPortalSystemPaths)[keyof typeof DevPortalSystemPaths];
35
28
 
36
- export type DevPortalProps = {
37
- meta?: Partial<{
38
- headerTitle: string;
39
- pageTitle: string;
40
- description: string;
41
- logo: string;
42
- favicon: string;
43
- }>;
44
- authentication?: AuthenticationProvider;
45
- navigation: NavigationItem[];
46
- plugins?: DevPortalPlugin[];
47
- mdxComponents?: MdxComponentsType;
48
- overrides?: ComponentsContextType;
49
- };
50
-
51
- const DevPortalInner = (props: DevPortalProps) => {
29
+ const DevPortalInner = (props: ZudokuContextOptions) => {
52
30
  const components = useMemo(
53
31
  () => ({ ...DEFAULT_COMPONENTS, ...props.overrides }),
54
32
  [props.overrides],
@@ -65,9 +43,15 @@ const DevPortalInner = (props: DevPortalProps) => {
65
43
  void devPortalContext.initialize();
66
44
  }, [devPortalContext]);
67
45
 
46
+ const heads = props.plugins
47
+ ?.filter(hasHead)
48
+ // eslint-disable-next-line react/no-array-index-key
49
+ .map((plugin, i) => <Fragment key={i}>{plugin.getHead?.()}</Fragment>);
50
+
68
51
  return (
69
52
  <QueryClientProvider client={queryClient}>
70
53
  <HelmetProvider>
54
+ <Helmet>{heads}</Helmet>
71
55
  <DevPortalProvider value={devPortalContext}>
72
56
  <MDXProvider components={mdxComponents}>
73
57
  <ThemeProvider>
@@ -1,4 +1,4 @@
1
- import { MoonStarIcon, SearchIcon, SunIcon } from "lucide-react";
1
+ import { MoonStarIcon, SunIcon } from "lucide-react";
2
2
  import { memo } from "react";
3
3
 
4
4
  import { useAuth } from "../authentication/hook.js";
@@ -9,7 +9,7 @@ import { useTheme } from "./context/ThemeContext.js";
9
9
  export const Header = memo(function HeaderInner() {
10
10
  const [isDark, toggleTheme] = useTheme();
11
11
  const { isAuthenticated, profile, isAuthEnabled, login, logout } = useAuth();
12
- const { meta } = useDevPortal();
12
+ const { page } = useDevPortal();
13
13
 
14
14
  const ThemeIcon = isDark ? MoonStarIcon : SunIcon;
15
15
 
@@ -18,16 +18,16 @@ export const Header = memo(function HeaderInner() {
18
18
  <div className="max-w-screen-2xl mx-auto">
19
19
  <div className="grid grid-cols-[calc(var(--side-nav-width))_1fr] lg:gap-12 items-center border-b border-border px-12 h-[--top-header-height]">
20
20
  <div className="flex items-center gap-3.5">
21
- {meta?.logo && (
22
- <img src={meta.logo} alt="My Dev Portal" className="h-10" />
21
+ {page?.logo && (
22
+ <img src={page.logo} alt={page.pageTitle} className="h-10" />
23
23
  )}
24
24
  <span className="font-bold text-2xl text-foreground/85 tracking-wide">
25
- {meta?.headerTitle}
25
+ {page?.pageTitle}
26
26
  </span>
27
27
  </div>
28
28
  <div className="grid grid-cols-[--sidecar-grid-cols] items-center gap-8">
29
29
  <div className="w-full max-w-prose">
30
- <button className="flex items-center border border-input hover:bg-accent hover:text-accent-foreground p-4 relative h-8 justify-start rounded-lg bg-background text-sm text-muted-foreground shadow-none w-40 sm:w-72">
30
+ {/*<button className="flex items-center border border-input hover:bg-accent hover:text-accent-foreground p-4 relative h-8 justify-start rounded-lg bg-background text-sm text-muted-foreground shadow-none w-40 sm:w-72">
31
31
  <div className="flex items-center gap-2 flex-grow">
32
32
  <SearchIcon size={14} />
33
33
  Search
@@ -35,26 +35,29 @@ export const Header = memo(function HeaderInner() {
35
35
  <kbd className="absolute right-[0.3rem] top-[0.3rem] hidden h-5 select-none items-center gap-1 rounded border border-border bg-muted px-1.5 font-mono text-[11px] font-medium opacity-100 sm:flex">
36
36
  ⌘K
37
37
  </kbd>
38
- </button>
38
+ </button>*/}
39
39
  </div>
40
40
 
41
41
  <div className="items-center justify-self-end text-sm hidden lg:flex">
42
- {isAuthenticated ? (
43
- <button
44
- className="cursor-pointer hover:bg-secondary p-1 px-2 mx-2 rounded text-nowrap"
45
- onClick={logout}
46
- >
47
- Logout {profile?.email ? `(${profile.email})` : null}
48
- </button>
49
- ) : (
50
- <button
51
- className="cursor-pointer hover:bg-secondary p-1 px-2 mx-2 rounded"
52
- onClick={login}
53
- >
54
- Login
55
- </button>
42
+ {isAuthEnabled && (
43
+ <>
44
+ {isAuthenticated ? (
45
+ <button
46
+ className="cursor-pointer hover:bg-secondary p-1 px-2 mx-2 rounded text-nowrap"
47
+ onClick={logout}
48
+ >
49
+ Logout {profile?.email ? `(${profile.email})` : null}
50
+ </button>
51
+ ) : (
52
+ <button
53
+ className="cursor-pointer hover:bg-secondary p-1 px-2 mx-2 rounded"
54
+ onClick={login}
55
+ >
56
+ Login
57
+ </button>
58
+ )}
59
+ </>
56
60
  )}
57
-
58
61
  <button
59
62
  className="cursor-pointer hover:bg-secondary p-2.5 -m-2.5 rounded-full"
60
63
  onClick={toggleTheme}
@@ -1,7 +1,24 @@
1
- import { type ReactNode } from "react";
2
- import { cn } from "../util/cn.js";
1
+ import React, { type ReactNode } from "react";
3
2
  import { useRegisterAnchorElement } from "./context/ViewportAnchorContext.js";
4
3
 
4
+ import { cva, type VariantProps } from "class-variance-authority";
5
+
6
+ const heading = cva("group relative", {
7
+ variants: {
8
+ level: {
9
+ 6: "text-md",
10
+ 5: "text-lg",
11
+ 4: "text-xl",
12
+ 3: "text-xl font-semibold",
13
+ 2: "text-2xl font-bold",
14
+ 1: "text-4xl font-extrabold",
15
+ },
16
+ },
17
+ defaultVariants: {
18
+ level: 1,
19
+ },
20
+ });
21
+
5
22
  const getComponent = (level: number) => {
6
23
  switch (level) {
7
24
  case 1:
@@ -21,27 +38,29 @@ const getComponent = (level: number) => {
21
38
  }
22
39
  };
23
40
 
24
- export type HeadingProps = {
41
+ export interface HeadingProps
42
+ extends React.ButtonHTMLAttributes<HTMLButtonElement>,
43
+ VariantProps<typeof heading> {
25
44
  children: ReactNode;
26
45
  className?: string;
27
46
  id?: string;
28
47
  level?: 1 | 2 | 3 | 4 | 5 | 6;
29
48
  registerSidebarAnchor?: boolean;
30
- };
49
+ }
31
50
 
32
- export const Heading = ({
51
+ export const Heading: React.FC<HeadingProps> = ({
33
52
  level,
34
53
  children,
35
54
  id,
36
55
  className,
37
56
  registerSidebarAnchor,
38
- }: HeadingProps) => {
57
+ }) => {
39
58
  const Component = getComponent(level ?? 1);
40
59
  const { ref } = useRegisterAnchorElement();
41
60
 
42
61
  return (
43
62
  <Component
44
- className={cn("group relative", className)}
63
+ className={heading({ className, level })}
45
64
  ref={registerSidebarAnchor ? ref : undefined}
46
65
  id={id}
47
66
  >
@@ -29,7 +29,7 @@ export const Layout = ({ children }: { children?: ReactNode }) => {
29
29
 
30
30
  return (
31
31
  <>
32
- <Helmet titleTemplate={meta?.pageTitle}>
32
+ <Helmet titleTemplate={meta?.title}>
33
33
  <title>Home</title>
34
34
  {meta?.description && (
35
35
  <meta name="description" content={meta.description} />
@@ -48,7 +48,7 @@ export const Layout = ({ children }: { children?: ReactNode }) => {
48
48
  >
49
49
  <SideNavigation />
50
50
  <main
51
- className="dark:border-white/10 translate-x-0
51
+ className="dark:border-white/10 translate-x-0 h-full
52
52
  lg:overflow-visible
53
53
  lg:peer-data-[navigation=true]:w-[calc(100%-var(--side-nav-width))]
54
54
  lg:peer-data-[navigation=true]:translate-x-[--side-nav-width] peer-data-[navigation=true]:pl-12"
@@ -21,6 +21,10 @@ if (!import.meta.env.SSR) {
21
21
  import("prismjs/components/prism-json.min.js");
22
22
  // @ts-expect-error This is untyped
23
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");
24
28
  }
25
29
 
26
30
  import { useState } from "react";
@@ -67,7 +71,7 @@ export const SyntaxHighlight = ({
67
71
  disabled={isCopied}
68
72
  onClick={() => {
69
73
  setIsCopied(true);
70
- navigator.clipboard.writeText(
74
+ void navigator.clipboard.writeText(
71
75
  tokens
72
76
  .map((line) => line.map(({ content }) => content).join(""))
73
77
  .join("\n"),
@@ -1,4 +1,4 @@
1
- import { useSuspenseQuery } from "@tanstack/react-query";
1
+ import { useQuery, useSuspenseQuery } from "@tanstack/react-query";
2
2
  import { createContext, useContext } from "react";
3
3
  import { matchPath, useLocation } from "react-router-dom";
4
4
  import { DevPortalContext } from "../../core/DevPortalContext.js";
@@ -21,7 +21,7 @@ export const useDevPortal = () => {
21
21
 
22
22
  export const useApiIdentities = () => {
23
23
  const { getApiIdentities } = useDevPortal();
24
- return useSuspenseQuery({
24
+ return useQuery({
25
25
  queryFn: getApiIdentities,
26
26
  queryKey: ["api-identities"],
27
27
  });
@@ -1,3 +1,6 @@
1
+ import { Callout } from "../ui/Callout.js";
2
+
1
3
  export { useMDXComponents } from "@mdx-js/react";
2
4
  export { DevPortal } from "./DevPortal.js";
3
5
  export { Link } from "./Link.js";
6
+ export { Callout };
@@ -2,16 +2,15 @@ import { QueryClient } from "@tanstack/react-query";
2
2
  import { type ReactNode } from "react";
3
3
  import { create } from "zustand";
4
4
  import { type AuthenticationProvider } from "../authentication/authentication.js";
5
+ import type { ComponentsContextType } from "../components/context/ComponentsContext.js";
6
+ import { type DevPortalPath } from "../components/DevPortal.js";
7
+ import type { MdxComponentsType } from "../util/MdxComponents.js";
5
8
  import {
6
- type DevPortalPath,
7
- type DevPortalProps,
8
- } from "../components/DevPortal.js";
9
- import {
9
+ type DevPortalPlugin,
10
10
  isApiIdentityPlugin,
11
11
  isNavigationPlugin,
12
- needsInitialization,
13
- type DevPortalPlugin,
14
12
  type NavigationPlugin,
13
+ needsInitialization,
15
14
  } from "./plugins.js";
16
15
 
17
16
  export interface ApiIdentity {
@@ -66,28 +65,59 @@ export const useRoutingState = create<RoutingState>(() => ({}));
66
65
  export type ApiKeyCache = "api-keys";
67
66
  export type DevPortalCacheKey = ApiKeyCache | string;
68
67
 
68
+ export type ZudokuContextMetadataOptions = Partial<{
69
+ title: string;
70
+ description: string;
71
+ logo: string;
72
+ favicon: string;
73
+ generator: string;
74
+ applicationName: string;
75
+ referrer: string;
76
+ keywords: string[];
77
+ authors: string[];
78
+ creator: string;
79
+ publisher: string;
80
+ }>;
81
+ export type ZudokuContextPageOptions = Partial<{
82
+ pageTitle?: string;
83
+ logo?: string;
84
+ }>;
85
+ export type ZudokuContextOptions = {
86
+ metadata?: ZudokuContextMetadataOptions;
87
+ page?: ZudokuContextPageOptions;
88
+ authentication?: AuthenticationProvider;
89
+ navigation: NavigationItem[];
90
+ plugins?: DevPortalPlugin[];
91
+ mdxComponents?: MdxComponentsType;
92
+ overrides?: ComponentsContextType;
93
+ };
94
+
69
95
  export class DevPortalContext {
70
96
  private plugins: DevPortalPlugin[] = [];
71
97
  private navigationPlugins: NavigationPlugin[];
72
98
 
73
99
  public navigation: NavigationItem[];
74
- public meta: DevPortalProps["meta"];
100
+ public meta: ZudokuContextOptions["metadata"];
101
+ public page: ZudokuContextOptions["page"];
75
102
  public authentication?: AuthenticationProvider;
76
103
  public state: typeof useRoutingState;
77
104
 
78
- constructor(config: DevPortalProps) {
105
+ constructor(config: ZudokuContextOptions) {
79
106
  this.plugins = config.plugins ?? [];
80
107
  this.navigation = config.navigation;
81
108
  this.navigationPlugins = this.plugins.filter(isNavigationPlugin);
82
109
  this.authentication = config.authentication;
83
- this.meta = config.meta;
110
+ this.meta = config.metadata;
111
+ this.page = config.page;
84
112
  this.state = useRoutingState;
85
113
  }
86
114
 
87
115
  initialize = async () => {
88
- this.plugins
89
- .filter(needsInitialization)
90
- .forEach((plugin) => plugin.initialize(this));
116
+ await Promise.all([
117
+ this.plugins
118
+ .filter(needsInitialization)
119
+ .map((plugin) => plugin.initialize?.(this)),
120
+ ]);
91
121
  };
92
122
 
93
123
  invalidateCache = async (key: DevPortalCacheKey[]) => {
@@ -1,3 +1,4 @@
1
+ import { type ReactElement } from "react";
1
2
  import { type RouteObject } from "react-router-dom";
2
3
  import {
3
4
  DevPortalContext,
@@ -10,9 +11,9 @@ export type PluginNavigationCategory = {
10
11
  } & NavigationCategory;
11
12
 
12
13
  export type DevPortalPlugin =
14
+ | CommonPlugin
13
15
  | NavigationPlugin
14
- | ApiIdentityPlugin
15
- | InitializationPlugin;
16
+ | ApiIdentityPlugin;
16
17
 
17
18
  export interface NavigationPlugin {
18
19
  getRoutes: () => RouteObject[];
@@ -23,8 +24,9 @@ export interface ApiIdentityPlugin {
23
24
  getIdentities: (context: DevPortalContext) => Promise<ApiIdentity[]>;
24
25
  }
25
26
 
26
- export interface InitializationPlugin {
27
- initialize: (context: DevPortalContext) => Promise<void> | void;
27
+ export interface CommonPlugin {
28
+ initialize?: (context: DevPortalContext) => Promise<void> | void;
29
+ getHead?: () => ReactElement | undefined;
28
30
  }
29
31
 
30
32
  export const isNavigationPlugin = (
@@ -34,9 +36,12 @@ export const isNavigationPlugin = (
34
36
 
35
37
  export const needsInitialization = (
36
38
  obj: DevPortalPlugin,
37
- ): obj is InitializationPlugin =>
39
+ ): obj is CommonPlugin =>
38
40
  "initialize" in obj && typeof obj.initialize === "function";
39
41
 
42
+ export const hasHead = (obj: DevPortalPlugin): obj is CommonPlugin =>
43
+ "getHead" in obj && typeof obj.getHead === "function";
44
+
40
45
  export const isApiIdentityPlugin = (
41
46
  obj: DevPortalPlugin,
42
47
  ): obj is ApiIdentityPlugin =>
@@ -45,7 +45,7 @@ export const slugifyOperation = (operation: OperationLike, tag?: string) => {
45
45
  );
46
46
  };
47
47
 
48
- const cache = new LRUCache<string, OpenAPIDocument>({
48
+ const cache = new LRUCache<string, Promise<OpenAPIDocument>>({
49
49
  ttl: 60 * 10 * 1000,
50
50
  ttlAutopurge: true,
51
51
  });
@@ -384,7 +384,7 @@ const loadOpenAPISchema = async (input: NonNullable<unknown>) => {
384
384
  return cache.get(hash)!;
385
385
  }
386
386
 
387
- const schema = await validate(input);
387
+ const schema = validate(input);
388
388
 
389
389
  cache.set(hash, schema);
390
390
 
@@ -54,7 +54,9 @@ const parseSchemaInput = async (
54
54
  return JSON.parse(schemaInput);
55
55
  }
56
56
  if (schemaInput.includes("://")) {
57
- const response = await fetch(schemaInput);
57
+ const response = await fetch(schemaInput, {
58
+ cache: "force-cache",
59
+ });
58
60
  return (await response.json()) as JSONSchema;
59
61
  }
60
62
  const yaml = await import("yaml");
@@ -12,17 +12,11 @@ import {
12
12
  SelectValue,
13
13
  } from "../../components/Select.js";
14
14
  import { Button } from "../../ui/Button.js";
15
- import { type ApiKeyPluginOptions, ApiKeyService } from "./index.js";
15
+ import { ApiKeyService } from "./index.js";
16
16
 
17
17
  type CreateApiKey = { description: string; expiresOn?: string };
18
18
 
19
- export const CreateApiKey = ({
20
- options,
21
- service,
22
- }: {
23
- options: ApiKeyPluginOptions;
24
- service: ApiKeyService;
25
- }) => {
19
+ export const CreateApiKey = ({ service }: { service: ApiKeyService }) => {
26
20
  const context = useDevPortal();
27
21
  const navigate = useNavigate();
28
22
  const form = useForm<CreateApiKey>({