zudoku 0.3.0-dev.55 → 0.3.0-dev.57

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 (181) hide show
  1. package/dist/app/demo.js +6 -1
  2. package/dist/app/demo.js.map +1 -1
  3. package/dist/app/entry.client.d.ts +1 -1
  4. package/dist/app/entry.client.js +1 -1
  5. package/dist/app/entry.client.js.map +1 -1
  6. package/dist/app/entry.server.d.ts +1 -1
  7. package/dist/app/entry.server.js +1 -1
  8. package/dist/app/entry.server.js.map +1 -1
  9. package/dist/app/main.d.ts +1 -1
  10. package/dist/app/main.js +9 -2
  11. package/dist/app/main.js.map +1 -1
  12. package/dist/app/standalone.js +6 -1
  13. package/dist/app/standalone.js.map +1 -1
  14. package/dist/config/validators/validate.d.ts +77 -17
  15. package/dist/config/validators/validate.js +7 -1
  16. package/dist/config/validators/validate.js.map +1 -1
  17. package/dist/lib/components/DeveloperHint.d.ts +5 -0
  18. package/dist/lib/components/DeveloperHint.js +10 -0
  19. package/dist/lib/components/DeveloperHint.js.map +1 -0
  20. package/dist/lib/components/Header.js +1 -1
  21. package/dist/lib/components/Header.js.map +1 -1
  22. package/dist/lib/components/NotFoundPage.js +2 -2
  23. package/dist/lib/components/NotFoundPage.js.map +1 -1
  24. package/dist/lib/components/navigation/SideNavigationCategory.js +2 -2
  25. package/dist/lib/components/navigation/SideNavigationCategory.js.map +1 -1
  26. package/dist/lib/core/DevPortalContext.d.ts +8 -1
  27. package/dist/lib/core/DevPortalContext.js.map +1 -1
  28. package/dist/lib/oas/graphql/index.js +5 -3
  29. package/dist/lib/oas/graphql/index.js.map +1 -1
  30. package/dist/lib/plugins/api-keys/ProtectedRoute.d.ts +1 -0
  31. package/dist/lib/plugins/api-keys/ProtectedRoute.js +14 -0
  32. package/dist/lib/plugins/api-keys/ProtectedRoute.js.map +1 -0
  33. package/dist/lib/plugins/api-keys/index.js +2 -12
  34. package/dist/lib/plugins/api-keys/index.js.map +1 -1
  35. package/dist/lib/plugins/openapi/OperationList.js +4 -3
  36. package/dist/lib/plugins/openapi/OperationList.js.map +1 -1
  37. package/dist/lib/plugins/openapi/StaggeredRender.d.ts +5 -0
  38. package/dist/lib/plugins/openapi/StaggeredRender.js +13 -0
  39. package/dist/lib/plugins/openapi/StaggeredRender.js.map +1 -0
  40. package/dist/lib/plugins/openapi/playground/PlaygroundDialog.js +3 -3
  41. package/dist/lib/plugins/openapi/playground/PlaygroundDialog.js.map +1 -1
  42. package/dist/vite/plugin-custom-css.js +2 -3
  43. package/dist/vite/plugin-custom-css.js.map +1 -1
  44. package/lib/AnchorLink-GNsUeGSX.js +705 -0
  45. package/lib/{AnchorLink-BaXHjhF-.js.map → AnchorLink-GNsUeGSX.js.map} +1 -1
  46. package/lib/Button-DpHMZvVs.js +4571 -0
  47. package/lib/Button-DpHMZvVs.js.map +1 -0
  48. package/lib/DevPortalProvider-Do9oJqme.js +1081 -0
  49. package/lib/{DevPortalProvider-GjdO0Xr-.js.map → DevPortalProvider-Do9oJqme.js.map} +1 -1
  50. package/lib/Markdown-DtLFdxD1.js +15031 -0
  51. package/lib/Markdown-DtLFdxD1.js.map +1 -0
  52. package/lib/MdxPage-CbwYRKf5.js +190 -0
  53. package/lib/{MdxPage-Dlujuj-J.js.map → MdxPage-CbwYRKf5.js.map} +1 -1
  54. package/lib/OperationList-DypxLtSC.js +5578 -0
  55. package/lib/OperationList-DypxLtSC.js.map +1 -0
  56. package/lib/Route-C1LyvITr.js +13 -0
  57. package/lib/{Route-CR6TEwVC.js.map → Route-C1LyvITr.js.map} +1 -1
  58. package/lib/Spinner-Bhbs5aPI.js +182 -0
  59. package/lib/Spinner-Bhbs5aPI.js.map +1 -0
  60. package/lib/_commonjsHelpers-BVfed4GL.js +29 -0
  61. package/lib/_commonjsHelpers-BVfed4GL.js.map +1 -0
  62. package/lib/assets/index-BPdJm2ty.js +4765 -0
  63. package/lib/assets/{index-CpIig0AX.js.map → index-BPdJm2ty.js.map} +1 -1
  64. package/lib/assets/worker-BWwCA-wk.js +14900 -0
  65. package/lib/assets/{worker-B5k2aBV9.js.map → worker-BWwCA-wk.js.map} +1 -1
  66. package/lib/context-_fYfJFgk.js +14 -0
  67. package/lib/{context-BoN_3uxi.js.map → context-_fYfJFgk.js.map} +1 -1
  68. package/lib/hook-Biq3zYel.js +92 -0
  69. package/lib/hook-Biq3zYel.js.map +1 -0
  70. package/lib/{index-Dih8IAqw.js → index-Bg82-bqR.js} +83 -103
  71. package/lib/{index-Dih8IAqw.js.map → index-Bg82-bqR.js.map} +1 -1
  72. package/lib/index-gsAuUwQh.js +418 -0
  73. package/lib/index-gsAuUwQh.js.map +1 -0
  74. package/lib/index-pI9JkN46.js +4765 -0
  75. package/lib/{index-Bn03IPZt.js.map → index-pI9JkN46.js.map} +1 -1
  76. package/lib/jsx-runtime-CJZJivg2.js +1526 -0
  77. package/lib/{jsx-runtime-DvZ6OKMM.js.map → jsx-runtime-CJZJivg2.js.map} +1 -1
  78. package/lib/prism-bash.min-DadFsM4Z.js +7 -0
  79. package/lib/{prism-bash.min-BtBk0onv.js.map → prism-bash.min-DadFsM4Z.js.map} +1 -1
  80. package/lib/prism-csharp.min-Yizuc34Y.js +35 -0
  81. package/lib/{prism-csharp.min-Cv7D49bv.js.map → prism-csharp.min-Yizuc34Y.js.map} +1 -1
  82. package/lib/prism-java.min-d5iT_mOd.js +7 -0
  83. package/lib/{prism-java.min-tNK-JX6x.js.map → prism-java.min-d5iT_mOd.js.map} +1 -1
  84. package/lib/prism-json.min-B1GJqK1k.js +2 -0
  85. package/lib/{prism-json.min-Cdtv-CME.js.map → prism-json.min-B1GJqK1k.js.map} +1 -1
  86. package/lib/prism-markup-templating-DZrrEs0A.js +62 -0
  87. package/lib/{prism-markup-templating-iotg2sCU.js.map → prism-markup-templating-DZrrEs0A.js.map} +1 -1
  88. package/lib/prism-objectivec.min-BXSWqpJJ.js +2 -0
  89. package/lib/{prism-objectivec.min-CY4WGixz.js.map → prism-objectivec.min-BXSWqpJJ.js.map} +1 -1
  90. package/lib/prism-php.min-o7FpoMP_.js +11 -0
  91. package/lib/{prism-php.min-T6sIVgED.js.map → prism-php.min-o7FpoMP_.js.map} +1 -1
  92. package/lib/prism-ruby.min-C7LwcKyz.js +10 -0
  93. package/lib/{prism-ruby.min-B-2KAa4y.js.map → prism-ruby.min-C7LwcKyz.js.map} +1 -1
  94. package/lib/router-CBw2vqJE.js +2973 -0
  95. package/lib/{router-ButO1QyY.js.map → router-CBw2vqJE.js.map} +1 -1
  96. package/lib/slugify-CiPVjteN.js +28 -0
  97. package/lib/{slugify-CmS97Vy8.js.map → slugify-CiPVjteN.js.map} +1 -1
  98. package/lib/state-DKdaQzvh.js +288 -0
  99. package/lib/{state-CmGfNKhR.js.map → state-DKdaQzvh.js.map} +1 -1
  100. package/lib/urql-DMlBWUKL.js +1592 -0
  101. package/lib/{urql-DtVKPBx_.js.map → urql-DMlBWUKL.js.map} +1 -1
  102. package/lib/util-_jwUlTBU.js +41 -0
  103. package/lib/{util-B5KX4h4M.js.map → util-_jwUlTBU.js.map} +1 -1
  104. package/lib/zudoku.auth-auth0.js +18 -24
  105. package/lib/zudoku.auth-auth0.js.map +1 -1
  106. package/lib/zudoku.auth-clerk.js +34 -43
  107. package/lib/zudoku.auth-clerk.js.map +1 -1
  108. package/lib/zudoku.auth-openid.js +734 -1121
  109. package/lib/zudoku.auth-openid.js.map +1 -1
  110. package/lib/zudoku.components.js +830 -1076
  111. package/lib/zudoku.components.js.map +1 -1
  112. package/lib/zudoku.openapi-worker.js +9689 -13781
  113. package/lib/zudoku.openapi-worker.js.map +1 -1
  114. package/lib/zudoku.plugin-api-keys.js +171 -208
  115. package/lib/zudoku.plugin-api-keys.js.map +1 -1
  116. package/lib/zudoku.plugin-markdown.js +33 -41
  117. package/lib/zudoku.plugin-markdown.js.map +1 -1
  118. package/lib/zudoku.plugin-openapi.js +6 -6
  119. package/lib/zudoku.plugin-redirect.js +8 -10
  120. package/lib/zudoku.plugin-redirect.js.map +1 -1
  121. package/package.json +2 -2
  122. package/src/app/demo.tsx +6 -1
  123. package/src/app/entry.client.tsx +1 -1
  124. package/src/app/entry.server.tsx +1 -1
  125. package/src/app/main.tsx +11 -2
  126. package/src/app/standalone.tsx +6 -1
  127. package/src/lib/components/DeveloperHint.tsx +25 -0
  128. package/src/lib/components/Header.tsx +6 -1
  129. package/src/lib/components/NotFoundPage.tsx +8 -14
  130. package/src/lib/components/navigation/SideNavigationCategory.tsx +3 -3
  131. package/src/lib/core/DevPortalContext.ts +8 -1
  132. package/src/lib/oas/graphql/index.ts +7 -3
  133. package/src/lib/plugins/api-keys/ProtectedRoute.tsx +29 -0
  134. package/src/lib/plugins/api-keys/index.tsx +2 -21
  135. package/src/lib/plugins/openapi/OperationList.tsx +14 -14
  136. package/src/lib/plugins/openapi/StaggeredRender.tsx +17 -0
  137. package/src/lib/plugins/openapi/playground/PlaygroundDialog.tsx +3 -5
  138. package/lib/AnchorLink-BaXHjhF-.js +0 -989
  139. package/lib/Combination-BfufJFkX.js +0 -1365
  140. package/lib/Combination-BfufJFkX.js.map +0 -1
  141. package/lib/DevPortalProvider-GjdO0Xr-.js +0 -1610
  142. package/lib/Markdown-B8nPVql1.js +0 -19708
  143. package/lib/Markdown-B8nPVql1.js.map +0 -1
  144. package/lib/MdxPage-Dlujuj-J.js +0 -223
  145. package/lib/OperationList-krPgt6sE.js +0 -8041
  146. package/lib/OperationList-krPgt6sE.js.map +0 -1
  147. package/lib/Playground-DOHxca0P.js +0 -539
  148. package/lib/Playground-DOHxca0P.js.map +0 -1
  149. package/lib/Route-CR6TEwVC.js +0 -13
  150. package/lib/Select-Boi_pe3L.js +0 -5298
  151. package/lib/Select-Boi_pe3L.js.map +0 -1
  152. package/lib/Spinner-oU0QJmi_.js +0 -16
  153. package/lib/Spinner-oU0QJmi_.js.map +0 -1
  154. package/lib/_commonjsHelpers-BxmBWJD2.js +0 -34
  155. package/lib/_commonjsHelpers-BxmBWJD2.js.map +0 -1
  156. package/lib/assets/index-CpIig0AX.js +0 -6341
  157. package/lib/assets/worker-B5k2aBV9.js +0 -18921
  158. package/lib/context-BoN_3uxi.js +0 -17
  159. package/lib/hook-CIuFuyBT.js +0 -90
  160. package/lib/hook-CIuFuyBT.js.map +0 -1
  161. package/lib/index-BL1P4Gqq.js +0 -280
  162. package/lib/index-BL1P4Gqq.js.map +0 -1
  163. package/lib/index-Bn03IPZt.js +0 -6341
  164. package/lib/index-FprhHF51.js +0 -253
  165. package/lib/index-FprhHF51.js.map +0 -1
  166. package/lib/jsx-runtime-DvZ6OKMM.js +0 -2110
  167. package/lib/mutation-DWY9x2Uc.js +0 -250
  168. package/lib/mutation-DWY9x2Uc.js.map +0 -1
  169. package/lib/prism-bash.min-BtBk0onv.js +0 -7
  170. package/lib/prism-csharp.min-Cv7D49bv.js +0 -30
  171. package/lib/prism-java.min-tNK-JX6x.js +0 -7
  172. package/lib/prism-json.min-Cdtv-CME.js +0 -2
  173. package/lib/prism-markup-templating-iotg2sCU.js +0 -94
  174. package/lib/prism-objectivec.min-CY4WGixz.js +0 -2
  175. package/lib/prism-php.min-T6sIVgED.js +0 -11
  176. package/lib/prism-ruby.min-B-2KAa4y.js +0 -8
  177. package/lib/router-ButO1QyY.js +0 -4062
  178. package/lib/slugify-CmS97Vy8.js +0 -50
  179. package/lib/state-CmGfNKhR.js +0 -436
  180. package/lib/urql-DtVKPBx_.js +0 -2567
  181. package/lib/util-B5KX4h4M.js +0 -55
@@ -1 +1 @@
1
- {"version":3,"file":"zudoku.plugin-api-keys.js","sources":["../../../node_modules/.pnpm/lucide-react@0.378.0_react@18.3.1/node_modules/lucide-react/dist/esm/icons/eye-off.js","../../../node_modules/.pnpm/lucide-react@0.378.0_react@18.3.1/node_modules/lucide-react/dist/esm/icons/eye.js","../../../node_modules/.pnpm/lucide-react@0.378.0_react@18.3.1/node_modules/lucide-react/dist/esm/icons/rotate-cw.js","../../../node_modules/.pnpm/lucide-react@0.378.0_react@18.3.1/node_modules/lucide-react/dist/esm/icons/trash.js","../../../node_modules/.pnpm/tiny-invariant@1.3.3/node_modules/tiny-invariant/dist/esm/tiny-invariant.js","../src/lib/components/Input.tsx","../src/lib/plugins/api-keys/CreateApiKey.tsx","../src/lib/plugins/api-keys/SettingsApiKeys.tsx","../src/lib/plugins/api-keys/index.tsx"],"sourcesContent":["/**\n * @license lucide-react v0.378.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst EyeOff = createLucideIcon(\"EyeOff\", [\n [\"path\", { d: \"M9.88 9.88a3 3 0 1 0 4.24 4.24\", key: \"1jxqfv\" }],\n [\n \"path\",\n {\n d: \"M10.73 5.08A10.43 10.43 0 0 1 12 5c7 0 10 7 10 7a13.16 13.16 0 0 1-1.67 2.68\",\n key: \"9wicm4\"\n }\n ],\n [\n \"path\",\n { d: \"M6.61 6.61A13.526 13.526 0 0 0 2 12s3 7 10 7a9.74 9.74 0 0 0 5.39-1.61\", key: \"1jreej\" }\n ],\n [\"line\", { x1: \"2\", x2: \"22\", y1: \"2\", y2: \"22\", key: \"a6p6uj\" }]\n]);\n\nexport { EyeOff as default };\n//# sourceMappingURL=eye-off.js.map\n","/**\n * @license lucide-react v0.378.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst Eye = createLucideIcon(\"Eye\", [\n [\"path\", { d: \"M2 12s3-7 10-7 10 7 10 7-3 7-10 7-10-7-10-7Z\", key: \"rwhkz3\" }],\n [\"circle\", { cx: \"12\", cy: \"12\", r: \"3\", key: \"1v7zrd\" }]\n]);\n\nexport { Eye as default };\n//# sourceMappingURL=eye.js.map\n","/**\n * @license lucide-react v0.378.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst RotateCw = createLucideIcon(\"RotateCw\", [\n [\"path\", { d: \"M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8\", key: \"1p45f6\" }],\n [\"path\", { d: \"M21 3v5h-5\", key: \"1q7to0\" }]\n]);\n\nexport { RotateCw as default };\n//# sourceMappingURL=rotate-cw.js.map\n","/**\n * @license lucide-react v0.378.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst Trash = createLucideIcon(\"Trash\", [\n [\"path\", { d: \"M3 6h18\", key: \"d0wm0j\" }],\n [\"path\", { d: \"M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6\", key: \"4alrt4\" }],\n [\"path\", { d: \"M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2\", key: \"v07s0e\" }]\n]);\n\nexport { Trash as default };\n//# sourceMappingURL=trash.js.map\n","var isProduction = process.env.NODE_ENV === 'production';\nvar prefix = 'Invariant failed';\nfunction invariant(condition, message) {\n if (condition) {\n return;\n }\n if (isProduction) {\n throw new Error(prefix);\n }\n var provided = typeof message === 'function' ? message() : message;\n var value = provided ? \"\".concat(prefix, \": \").concat(provided) : prefix;\n throw new Error(value);\n}\n\nexport { invariant as default };\n","import * as React from \"react\";\nimport { cn } from \"../util/cn.js\";\n\nexport interface InputProps\n extends React.InputHTMLAttributes<HTMLInputElement> {}\n\nconst Input = React.forwardRef<HTMLInputElement, InputProps>(\n ({ className, type, ...props }, ref) => {\n return (\n <input\n type={type}\n className={cn(\n \"flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50\",\n className,\n )}\n ref={ref}\n {...props}\n />\n );\n },\n);\nInput.displayName = \"Input\";\n\nexport { Input };\n","import { useMutation } from \"@tanstack/react-query\";\nimport { useForm } from \"react-hook-form\";\nimport { Link, useNavigate } from \"react-router-dom\";\nimport { useDevPortal } from \"../../components/context/DevPortalProvider.js\";\nimport { Input } from \"../../components/Input.js\";\nimport {\n Select,\n SelectContent,\n SelectGroup,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from \"../../components/Select.js\";\nimport { Button } from \"../../ui/Button.js\";\nimport { ApiKeyService } from \"./index.js\";\n\ntype CreateApiKey = { description: string; expiresOn?: string };\n\nexport const CreateApiKey = ({ service }: { service: ApiKeyService }) => {\n const context = useDevPortal();\n const navigate = useNavigate();\n const form = useForm<CreateApiKey>({\n defaultValues: {\n expiresOn: \"30\",\n },\n });\n const createKeyMutation = useMutation({\n mutationFn: ({ description, expiresOn }: CreateApiKey) => {\n if (!service.createKey) {\n throw new Error(\"deleteKey not implemented\");\n }\n\n const expiresOnDate =\n expiresOn !== \"never\" ? addDaysToDate(Number(expiresOn)) : undefined;\n\n return service.createKey(\n { description: description, expiresOn: expiresOnDate },\n context,\n );\n },\n onSuccess: () => navigate(\"/settings/api-keys/\"),\n });\n\n if (!service.createKey) {\n return null;\n }\n\n return (\n <div className=\"max-w-screen-lg pt-[--padding-content-top] pb-[--padding-content-bottom]\">\n <div className=\"flex justify-between mb-4 border-b border-border pb-1\">\n <h1 className=\"font-medium text-2xl\">New API Key</h1>\n </div>\n <form\n onSubmit={form.handleSubmit((data) => createKeyMutation.mutate(data))}\n >\n <div className=\"flex gap-2 flex-col\">\n Note\n <Input {...form.register(\"description\")} />\n Expiration\n <Select\n onValueChange={(value) => form.setValue(\"expiresOn\", value)}\n defaultValue={form.getValues(\"expiresOn\")}\n >\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectGroup>\n {[7, 30, 60, 90].map((option) => (\n <SelectItem value={String(option)} key={option}>\n {option} days\n </SelectItem>\n ))}\n <SelectItem value=\"never\">Never</SelectItem>\n </SelectGroup>\n </SelectContent>\n </Select>\n <div className=\"flex gap-2\">\n <Button>Generate Key</Button>\n <Button variant=\"outline\" asChild>\n <Link to=\"/settings/api-keys/\">Cancel</Link>\n </Button>\n </div>\n </div>\n </form>\n </div>\n );\n};\n\nconst addDaysToDate = (days: number): string => {\n const date = new Date();\n date.setDate(date.getDate() + days);\n return date.toISOString();\n};\n","import {\n useMutation,\n useQueryClient,\n useSuspenseQuery,\n} from \"@tanstack/react-query\";\nimport { EyeIcon, EyeOffIcon, RotateCwIcon, TrashIcon } from \"lucide-react\";\nimport { useState } from \"react\";\nimport { Link } from \"react-router-dom\";\nimport { useDevPortal } from \"../../components/context/DevPortalProvider.js\";\nimport { Button } from \"../../ui/Button.js\";\nimport { cn } from \"../../util/cn.js\";\nimport { ApiKeyService } from \"./index.js\";\n\nexport const SettingsApiKeys = ({ service }: { service: ApiKeyService }) => {\n const context = useDevPortal();\n const queryClient = useQueryClient();\n const { data } = useSuspenseQuery({\n queryFn: () => service.getKeys(context),\n queryKey: [\"api-keys\"],\n retry: false,\n });\n\n const deleteKeyMutation = useMutation({\n mutationFn: (id: string) => {\n if (!service.deleteKey) {\n throw new Error(\"deleteKey not implemented\");\n }\n\n return service.deleteKey(id, context);\n },\n onSuccess: () => {\n void queryClient.invalidateQueries({ queryKey: [\"api-keys\"] });\n },\n });\n\n return (\n <div className=\"max-w-screen-lg h-full pt-[--padding-content-top] pb-[--padding-content-bottom]\">\n <div className=\"flex justify-between mb-4 border-b border-border pb-3\">\n <h1 className=\"font-medium text-2xl\">API Keys</h1>\n {service.createKey && (\n <Button asChild>\n <Link to=\"/settings/api-keys/new\">Create API Key</Link>\n </Button>\n )}\n </div>\n\n {data.length === 0 ? (\n <div className=\"flex flex-col justify-center gap-4 items-center h-1/2 my-8\">\n <div className=\"text-center\">\n No API keys created yet.\n <br />\n Get started and create the first one now\n </div>\n {service.createKey && (\n <Button asChild>\n <Link to=\"/settings/api-keys/new\">Create API Key</Link>\n </Button>\n )}\n </div>\n ) : (\n <ul\n className={cn(\n \"grid grid-cols-1 rounded border-border border\",\n \"lg:grid-cols-[minmax(250px,min-content)_1fr_min-content]\",\n )}\n >\n {data.map((key) => (\n <li\n className=\"border-b border-border p-5 grid grid-cols-subgrid col-span-full gap-2 items-center\"\n key={key.id}\n >\n <div className=\"flex flex-col gap-1 text-sm\">\n {key.description ?? key.id}\n <div className=\"text-muted-foreground text-xs\">\n {key.createdOn && (\n <div>\n Created on {new Date(key.createdOn).toLocaleDateString()}\n </div>\n )}\n {key.expiresOn && (\n <div>\n Expires on {new Date(key.expiresOn).toLocaleDateString()}\n </div>\n )}\n </div>\n </div>\n <div className=\"items-center flex lg:justify-center\">\n <RevealApiKey apiKey={key.key} />\n </div>\n <div className=\"flex gap-2\">\n {service.rollKey && (\n <Button size=\"icon\">\n <RotateCwIcon size={16} />\n </Button>\n )}\n {service.deleteKey && (\n <Button\n variant=\"ghost\"\n size=\"icon\"\n onClick={() => {\n if (!confirm(\"Do you want to delete this key?\")) {\n return;\n }\n\n deleteKeyMutation.mutate(key.id);\n }}\n disabled={deleteKeyMutation.isPending}\n >\n <TrashIcon size={16} />\n </Button>\n )}\n </div>\n </li>\n ))}\n </ul>\n )}\n </div>\n );\n};\n\nconst RevealApiKey = ({ apiKey }: { apiKey: string }) => {\n const [revealed, setRevealed] = useState(false);\n\n return (\n <div className=\"flex gap-2 items-center text-sm w-full\">\n <input\n className=\"border border-border rounded bg-gray-100 dark:bg-gray-950 p-1 font-mono max-w-min\"\n value={revealed ? apiKey : \"•\".repeat(apiKey.length)}\n />\n <Button\n variant=\"outline\"\n onClick={() => setRevealed((prev) => !prev)}\n size=\"icon\"\n >\n {revealed ? <EyeOffIcon size={16} /> : <EyeIcon size={16} />}\n </Button>\n </div>\n );\n};\n","import { Outlet, type RouteObject } from \"react-router-dom\";\nimport invariant from \"tiny-invariant\";\nimport { useAuth } from \"../../authentication/hook.js\";\nimport { DevPortalContext } from \"../../core/DevPortalContext.js\";\nimport {\n type ApiIdentityPlugin,\n type DevPortalPlugin,\n} from \"../../core/plugins.js\";\nimport { RouterError } from \"../../errors/RouterError.js\";\nimport { Button } from \"../../ui/Button.js\";\nimport { CreateApiKey } from \"./CreateApiKey.js\";\nimport { SettingsApiKeys } from \"./SettingsApiKeys.js\";\n\nconst DEFAULT_API_KEY_ENDPOINT =\n \"https://zudoku-rewiringamerica-main-ef9c9c0.d2.zuplo.dev\";\n\nexport type ApiKeyService = {\n getKeys: (context: DevPortalContext) => Promise<ApiKey[]>;\n rollKey?: (id: string, context: DevPortalContext) => Promise<void>;\n deleteKey?: (id: string, context: DevPortalContext) => Promise<void>;\n updateKeyDescription?: (\n apiKey: { id: string; description: string },\n context: DevPortalContext,\n ) => Promise<void>;\n getUsage?: (apiKeys: string[], context: DevPortalContext) => Promise<void>;\n createKey?: (\n apiKey: { description: string; expiresOn?: string },\n context: DevPortalContext,\n ) => Promise<void>;\n};\n\nexport type GetApiKeysOptions = ApiKeyService | { endpoint: string } | object;\n\nexport type ApiKeyPluginOptions = object & GetApiKeysOptions;\n\nexport interface ApiKey {\n id: string;\n description?: string;\n createdOn?: string;\n updatedOn?: string;\n expiresOn?: string;\n key: string;\n}\n\nconst createDefaultHandler = (endpoint: string): ApiKeyService => {\n return {\n deleteKey: async (id, context) => {\n const request = new Request(endpoint + `/v1/developer/api-keys/${id}`, {\n method: \"DELETE\",\n });\n\n await context.signRequest(request);\n\n const response = await fetch(request);\n invariant(response.ok, \"Failed to delete API key\");\n },\n createKey: async (apiKey, context) => {\n const request = new Request(endpoint + `/v1/developer/api-keys`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(apiKey),\n });\n\n await context.signRequest(request);\n\n const response = await fetch(request);\n invariant(response.ok, \"Failed to create API key\");\n },\n getKeys: async (context) => {\n const request = new Request(endpoint + `/v1/developer/api-keys`);\n\n await context.signRequest(request);\n\n const keys = await fetch(request);\n invariant(keys.ok, \"Failed to fetch API keys\");\n\n return await keys.json();\n },\n };\n};\n\nconst ProtectedRoute = () => {\n const auth = useAuth();\n\n // TODO: should we suspend here somehow?\n if (auth.isPending) {\n return null;\n }\n\n return auth.isAuthenticated ? (\n <Outlet />\n ) : (\n <div className=\"flex flex-col justify-center gap-2 items-center h-1/2 my-12\">\n Please login first to view this page\n <Button onClick={() => auth.login()}>Login</Button>\n </div>\n );\n};\n\nexport const apiKeyPlugin = (\n options: ApiKeyPluginOptions,\n): DevPortalPlugin & ApiIdentityPlugin => {\n const endpoint =\n \"endpoint\" in options ? options.endpoint : DEFAULT_API_KEY_ENDPOINT;\n\n const service =\n \"getKeys\" in options ? options : createDefaultHandler(endpoint);\n\n return {\n getIdentities: async (context) => {\n try {\n const keys = await service.getKeys(context);\n\n return keys.map((key) => ({\n authorizeRequest: (request) => {\n request.headers.set(\"Authorization\", `Bearer ${key.key}`);\n return request;\n },\n id: key.id,\n label: key.description ?? key.id,\n }));\n } catch {\n return [];\n }\n },\n getRoutes: (): RouteObject[] => {\n // TODO: Make lazy\n return [\n {\n element: <ProtectedRoute />,\n errorElement: <RouterError />,\n children: [\n {\n path: \"/settings/api-keys\",\n element: <SettingsApiKeys service={service} />,\n },\n {\n path: \"/settings/api-keys/new\",\n element: <CreateApiKey service={service} />,\n },\n ],\n },\n ];\n },\n };\n};\n"],"names":["jsx","jsxs","RotateCwIcon","TrashIcon","EyeOffIcon","EyeIcon"],"mappings":"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","x_google_ignoreList":[0,1,2,3,4]}
1
+ {"version":3,"file":"zudoku.plugin-api-keys.js","sources":["../../../node_modules/.pnpm/lucide-react@0.378.0_react@18.3.1/node_modules/lucide-react/dist/esm/icons/eye-off.js","../../../node_modules/.pnpm/lucide-react@0.378.0_react@18.3.1/node_modules/lucide-react/dist/esm/icons/eye.js","../../../node_modules/.pnpm/lucide-react@0.378.0_react@18.3.1/node_modules/lucide-react/dist/esm/icons/rotate-cw.js","../../../node_modules/.pnpm/lucide-react@0.378.0_react@18.3.1/node_modules/lucide-react/dist/esm/icons/trash.js","../../../node_modules/.pnpm/tiny-invariant@1.3.3/node_modules/tiny-invariant/dist/esm/tiny-invariant.js","../src/lib/components/Input.tsx","../src/lib/plugins/api-keys/CreateApiKey.tsx","../src/lib/plugins/api-keys/ProtectedRoute.tsx","../src/lib/plugins/api-keys/SettingsApiKeys.tsx","../src/lib/plugins/api-keys/index.tsx"],"sourcesContent":["/**\n * @license lucide-react v0.378.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst EyeOff = createLucideIcon(\"EyeOff\", [\n [\"path\", { d: \"M9.88 9.88a3 3 0 1 0 4.24 4.24\", key: \"1jxqfv\" }],\n [\n \"path\",\n {\n d: \"M10.73 5.08A10.43 10.43 0 0 1 12 5c7 0 10 7 10 7a13.16 13.16 0 0 1-1.67 2.68\",\n key: \"9wicm4\"\n }\n ],\n [\n \"path\",\n { d: \"M6.61 6.61A13.526 13.526 0 0 0 2 12s3 7 10 7a9.74 9.74 0 0 0 5.39-1.61\", key: \"1jreej\" }\n ],\n [\"line\", { x1: \"2\", x2: \"22\", y1: \"2\", y2: \"22\", key: \"a6p6uj\" }]\n]);\n\nexport { EyeOff as default };\n//# sourceMappingURL=eye-off.js.map\n","/**\n * @license lucide-react v0.378.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst Eye = createLucideIcon(\"Eye\", [\n [\"path\", { d: \"M2 12s3-7 10-7 10 7 10 7-3 7-10 7-10-7-10-7Z\", key: \"rwhkz3\" }],\n [\"circle\", { cx: \"12\", cy: \"12\", r: \"3\", key: \"1v7zrd\" }]\n]);\n\nexport { Eye as default };\n//# sourceMappingURL=eye.js.map\n","/**\n * @license lucide-react v0.378.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst RotateCw = createLucideIcon(\"RotateCw\", [\n [\"path\", { d: \"M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8\", key: \"1p45f6\" }],\n [\"path\", { d: \"M21 3v5h-5\", key: \"1q7to0\" }]\n]);\n\nexport { RotateCw as default };\n//# sourceMappingURL=rotate-cw.js.map\n","/**\n * @license lucide-react v0.378.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst Trash = createLucideIcon(\"Trash\", [\n [\"path\", { d: \"M3 6h18\", key: \"d0wm0j\" }],\n [\"path\", { d: \"M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6\", key: \"4alrt4\" }],\n [\"path\", { d: \"M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2\", key: \"v07s0e\" }]\n]);\n\nexport { Trash as default };\n//# sourceMappingURL=trash.js.map\n","var isProduction = process.env.NODE_ENV === 'production';\nvar prefix = 'Invariant failed';\nfunction invariant(condition, message) {\n if (condition) {\n return;\n }\n if (isProduction) {\n throw new Error(prefix);\n }\n var provided = typeof message === 'function' ? message() : message;\n var value = provided ? \"\".concat(prefix, \": \").concat(provided) : prefix;\n throw new Error(value);\n}\n\nexport { invariant as default };\n","import * as React from \"react\";\nimport { cn } from \"../util/cn.js\";\n\nexport interface InputProps\n extends React.InputHTMLAttributes<HTMLInputElement> {}\n\nconst Input = React.forwardRef<HTMLInputElement, InputProps>(\n ({ className, type, ...props }, ref) => {\n return (\n <input\n type={type}\n className={cn(\n \"flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50\",\n className,\n )}\n ref={ref}\n {...props}\n />\n );\n },\n);\nInput.displayName = \"Input\";\n\nexport { Input };\n","import { useMutation } from \"@tanstack/react-query\";\nimport { useForm } from \"react-hook-form\";\nimport { Link, useNavigate } from \"react-router-dom\";\nimport { useDevPortal } from \"../../components/context/DevPortalProvider.js\";\nimport { Input } from \"../../components/Input.js\";\nimport {\n Select,\n SelectContent,\n SelectGroup,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from \"../../components/Select.js\";\nimport { Button } from \"../../ui/Button.js\";\nimport { ApiKeyService } from \"./index.js\";\n\ntype CreateApiKey = { description: string; expiresOn?: string };\n\nexport const CreateApiKey = ({ service }: { service: ApiKeyService }) => {\n const context = useDevPortal();\n const navigate = useNavigate();\n const form = useForm<CreateApiKey>({\n defaultValues: {\n expiresOn: \"30\",\n },\n });\n const createKeyMutation = useMutation({\n mutationFn: ({ description, expiresOn }: CreateApiKey) => {\n if (!service.createKey) {\n throw new Error(\"deleteKey not implemented\");\n }\n\n const expiresOnDate =\n expiresOn !== \"never\" ? addDaysToDate(Number(expiresOn)) : undefined;\n\n return service.createKey(\n { description: description, expiresOn: expiresOnDate },\n context,\n );\n },\n onSuccess: () => navigate(\"/settings/api-keys/\"),\n });\n\n if (!service.createKey) {\n return null;\n }\n\n return (\n <div className=\"max-w-screen-lg pt-[--padding-content-top] pb-[--padding-content-bottom]\">\n <div className=\"flex justify-between mb-4 border-b border-border pb-1\">\n <h1 className=\"font-medium text-2xl\">New API Key</h1>\n </div>\n <form\n onSubmit={form.handleSubmit((data) => createKeyMutation.mutate(data))}\n >\n <div className=\"flex gap-2 flex-col\">\n Note\n <Input {...form.register(\"description\")} />\n Expiration\n <Select\n onValueChange={(value) => form.setValue(\"expiresOn\", value)}\n defaultValue={form.getValues(\"expiresOn\")}\n >\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectGroup>\n {[7, 30, 60, 90].map((option) => (\n <SelectItem value={String(option)} key={option}>\n {option} days\n </SelectItem>\n ))}\n <SelectItem value=\"never\">Never</SelectItem>\n </SelectGroup>\n </SelectContent>\n </Select>\n <div className=\"flex gap-2\">\n <Button>Generate Key</Button>\n <Button variant=\"outline\" asChild>\n <Link to=\"/settings/api-keys/\">Cancel</Link>\n </Button>\n </div>\n </div>\n </form>\n </div>\n );\n};\n\nconst addDaysToDate = (days: number): string => {\n const date = new Date();\n date.setDate(date.getDate() + days);\n return date.toISOString();\n};\n","import { Outlet } from \"react-router-dom\";\nimport { useAuth } from \"../../authentication/hook.js\";\nimport { DeveloperHint } from \"../../components/DeveloperHint.js\";\nimport { Button } from \"../../ui/Button.js\";\n\nexport const ProtectedRoute = () => {\n const auth = useAuth();\n\n // TODO: should we suspend here somehow?\n if (auth.isAuthEnabled && auth.isPending) {\n return null;\n }\n\n return auth.isAuthenticated ? (\n <Outlet />\n ) : !auth.isAuthEnabled ? (\n <div className=\"flex flex-col justify-center gap-2 items-center h-1/2\">\n <DeveloperHint className=\"max-w-[600px]\">\n Authentication needs to be enabled for API keys to work. Enable it in\n your Zudoku configuration under <code>authentication</code>.\n </DeveloperHint>\n </div>\n ) : (\n <div className=\"flex flex-col justify-center gap-2 items-center h-1/2\">\n Please login first to view this page\n <Button onClick={() => auth.login()}>Login</Button>\n </div>\n );\n};\n","import {\n useMutation,\n useQueryClient,\n useSuspenseQuery,\n} from \"@tanstack/react-query\";\nimport { EyeIcon, EyeOffIcon, RotateCwIcon, TrashIcon } from \"lucide-react\";\nimport { useState } from \"react\";\nimport { Link } from \"react-router-dom\";\nimport { useDevPortal } from \"../../components/context/DevPortalProvider.js\";\nimport { Button } from \"../../ui/Button.js\";\nimport { cn } from \"../../util/cn.js\";\nimport { ApiKeyService } from \"./index.js\";\n\nexport const SettingsApiKeys = ({ service }: { service: ApiKeyService }) => {\n const context = useDevPortal();\n const queryClient = useQueryClient();\n const { data } = useSuspenseQuery({\n queryFn: () => service.getKeys(context),\n queryKey: [\"api-keys\"],\n retry: false,\n });\n\n const deleteKeyMutation = useMutation({\n mutationFn: (id: string) => {\n if (!service.deleteKey) {\n throw new Error(\"deleteKey not implemented\");\n }\n\n return service.deleteKey(id, context);\n },\n onSuccess: () => {\n void queryClient.invalidateQueries({ queryKey: [\"api-keys\"] });\n },\n });\n\n return (\n <div className=\"max-w-screen-lg h-full pt-[--padding-content-top] pb-[--padding-content-bottom]\">\n <div className=\"flex justify-between mb-4 border-b border-border pb-3\">\n <h1 className=\"font-medium text-2xl\">API Keys</h1>\n {service.createKey && (\n <Button asChild>\n <Link to=\"/settings/api-keys/new\">Create API Key</Link>\n </Button>\n )}\n </div>\n\n {data.length === 0 ? (\n <div className=\"flex flex-col justify-center gap-4 items-center h-1/2 my-8\">\n <div className=\"text-center\">\n No API keys created yet.\n <br />\n Get started and create the first one now\n </div>\n {service.createKey && (\n <Button asChild>\n <Link to=\"/settings/api-keys/new\">Create API Key</Link>\n </Button>\n )}\n </div>\n ) : (\n <ul\n className={cn(\n \"grid grid-cols-1 rounded border-border border\",\n \"lg:grid-cols-[minmax(250px,min-content)_1fr_min-content]\",\n )}\n >\n {data.map((key) => (\n <li\n className=\"border-b border-border p-5 grid grid-cols-subgrid col-span-full gap-2 items-center\"\n key={key.id}\n >\n <div className=\"flex flex-col gap-1 text-sm\">\n {key.description ?? key.id}\n <div className=\"text-muted-foreground text-xs\">\n {key.createdOn && (\n <div>\n Created on {new Date(key.createdOn).toLocaleDateString()}\n </div>\n )}\n {key.expiresOn && (\n <div>\n Expires on {new Date(key.expiresOn).toLocaleDateString()}\n </div>\n )}\n </div>\n </div>\n <div className=\"items-center flex lg:justify-center\">\n <RevealApiKey apiKey={key.key} />\n </div>\n <div className=\"flex gap-2\">\n {service.rollKey && (\n <Button size=\"icon\">\n <RotateCwIcon size={16} />\n </Button>\n )}\n {service.deleteKey && (\n <Button\n variant=\"ghost\"\n size=\"icon\"\n onClick={() => {\n if (!confirm(\"Do you want to delete this key?\")) {\n return;\n }\n\n deleteKeyMutation.mutate(key.id);\n }}\n disabled={deleteKeyMutation.isPending}\n >\n <TrashIcon size={16} />\n </Button>\n )}\n </div>\n </li>\n ))}\n </ul>\n )}\n </div>\n );\n};\n\nconst RevealApiKey = ({ apiKey }: { apiKey: string }) => {\n const [revealed, setRevealed] = useState(false);\n\n return (\n <div className=\"flex gap-2 items-center text-sm w-full\">\n <input\n className=\"border border-border rounded bg-gray-100 dark:bg-gray-950 p-1 font-mono max-w-min\"\n value={revealed ? apiKey : \"•\".repeat(apiKey.length)}\n />\n <Button\n variant=\"outline\"\n onClick={() => setRevealed((prev) => !prev)}\n size=\"icon\"\n >\n {revealed ? <EyeOffIcon size={16} /> : <EyeIcon size={16} />}\n </Button>\n </div>\n );\n};\n","import { type RouteObject } from \"react-router-dom\";\nimport invariant from \"tiny-invariant\";\nimport { DevPortalContext } from \"../../core/DevPortalContext.js\";\nimport {\n type ApiIdentityPlugin,\n type DevPortalPlugin,\n} from \"../../core/plugins.js\";\nimport { RouterError } from \"../../errors/RouterError.js\";\nimport { CreateApiKey } from \"./CreateApiKey.js\";\nimport { ProtectedRoute } from \"./ProtectedRoute.js\";\nimport { SettingsApiKeys } from \"./SettingsApiKeys.js\";\n\nconst DEFAULT_API_KEY_ENDPOINT =\n \"https://zudoku-rewiringamerica-main-ef9c9c0.d2.zuplo.dev\";\n\nexport type ApiKeyService = {\n getKeys: (context: DevPortalContext) => Promise<ApiKey[]>;\n rollKey?: (id: string, context: DevPortalContext) => Promise<void>;\n deleteKey?: (id: string, context: DevPortalContext) => Promise<void>;\n updateKeyDescription?: (\n apiKey: { id: string; description: string },\n context: DevPortalContext,\n ) => Promise<void>;\n getUsage?: (apiKeys: string[], context: DevPortalContext) => Promise<void>;\n createKey?: (\n apiKey: { description: string; expiresOn?: string },\n context: DevPortalContext,\n ) => Promise<void>;\n};\n\nexport type GetApiKeysOptions = ApiKeyService | { endpoint: string } | object;\n\nexport type ApiKeyPluginOptions = object & GetApiKeysOptions;\n\nexport interface ApiKey {\n id: string;\n description?: string;\n createdOn?: string;\n updatedOn?: string;\n expiresOn?: string;\n key: string;\n}\n\nconst createDefaultHandler = (endpoint: string): ApiKeyService => {\n return {\n deleteKey: async (id, context) => {\n const request = new Request(endpoint + `/v1/developer/api-keys/${id}`, {\n method: \"DELETE\",\n });\n\n await context.signRequest(request);\n\n const response = await fetch(request);\n invariant(response.ok, \"Failed to delete API key\");\n },\n createKey: async (apiKey, context) => {\n const request = new Request(endpoint + `/v1/developer/api-keys`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify(apiKey),\n });\n\n await context.signRequest(request);\n\n const response = await fetch(request);\n invariant(response.ok, \"Failed to create API key\");\n },\n getKeys: async (context) => {\n const request = new Request(endpoint + `/v1/developer/api-keys`);\n\n await context.signRequest(request);\n\n const keys = await fetch(request);\n invariant(keys.ok, \"Failed to fetch API keys\");\n\n return await keys.json();\n },\n };\n};\n\nexport const apiKeyPlugin = (\n options: ApiKeyPluginOptions,\n): DevPortalPlugin & ApiIdentityPlugin => {\n const endpoint =\n \"endpoint\" in options ? options.endpoint : DEFAULT_API_KEY_ENDPOINT;\n\n const service =\n \"getKeys\" in options ? options : createDefaultHandler(endpoint);\n\n return {\n getIdentities: async (context) => {\n try {\n const keys = await service.getKeys(context);\n\n return keys.map((key) => ({\n authorizeRequest: (request) => {\n request.headers.set(\"Authorization\", `Bearer ${key.key}`);\n return request;\n },\n id: key.id,\n label: key.description ?? key.id,\n }));\n } catch {\n return [];\n }\n },\n getRoutes: (): RouteObject[] => {\n // TODO: Make lazy\n return [\n {\n element: <ProtectedRoute />,\n errorElement: <RouterError />,\n children: [\n {\n path: \"/settings/api-keys\",\n element: <SettingsApiKeys service={service} />,\n },\n {\n path: \"/settings/api-keys/new\",\n element: <CreateApiKey service={service} />,\n },\n ],\n },\n ];\n },\n };\n};\n"],"names":["EyeOff","createLucideIcon","Eye","RotateCw","Trash","isProduction","prefix","invariant","condition","message","provided","value","Input","React","className","type","props","ref","jsx","cn","CreateApiKey","service","context","useDevPortal","navigate","useNavigate","form","useForm","createKeyMutation","useMutation","description","expiresOn","expiresOnDate","addDaysToDate","jsxs","data","Select","SelectTrigger","SelectValue","SelectContent","SelectGroup","option","SelectItem","Button","Link","days","date","ProtectedRoute","auth","useAuth","Outlet","DeveloperHint","SettingsApiKeys","queryClient","useQueryClient","useSuspenseQuery","deleteKeyMutation","id","key","RevealApiKey","RotateCwIcon","TrashIcon","apiKey","revealed","setRevealed","useState","prev","EyeOffIcon","EyeIcon","DEFAULT_API_KEY_ENDPOINT","createDefaultHandler","endpoint","request","response","keys","apiKeyPlugin","options","RouterError"],"mappings":"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","x_google_ignoreList":[0,1,2,3,4]}
@@ -1,57 +1,49 @@
1
- import { j as jsxRuntimeExports, N as Navigate } from "./jsx-runtime-DvZ6OKMM.js";
2
- import { k as useTopNavigationItem } from "./DevPortalProvider-GjdO0Xr-.js";
3
- import { t as traverseNavigation, i as isPathItem } from "./util-B5KX4h4M.js";
4
- const generateRoutes = (markdownFiles, defaultOptions) => {
5
- const routes = Object.entries(markdownFiles).flatMap(
6
- ([file, importPromise]) => {
7
- const match = file.match(/pages\/(.*).mdx?$/);
8
- const path = match == null ? void 0 : match.at(1);
9
- if (!path) return [];
10
- const pathSegments = path.split("/");
11
- const isIndexFile = pathSegments.at(-1) === "index";
12
- const routePath = isIndexFile ? pathSegments.slice(0, -1).join("/") : path;
1
+ import { j as s, N as x } from "./jsx-runtime-CJZJivg2.js";
2
+ import { k as d } from "./DevPortalProvider-Do9oJqme.js";
3
+ import { t as f, i as g } from "./util-_jwUlTBU.js";
4
+ const h = (t, e) => {
5
+ const r = Object.entries(t).flatMap(
6
+ ([n, m]) => {
7
+ const a = n.match(/pages\/(.*).mdx?$/), o = a == null ? void 0 : a.at(1);
8
+ if (!o) return [];
9
+ const i = o.split("/");
13
10
  return {
14
- path: routePath,
11
+ path: i.at(-1) === "index" ? i.slice(0, -1).join("/") : o,
15
12
  lazy: async () => {
16
- const { MdxPage } = await import("./MdxPage-Dlujuj-J.js");
17
- const { default: Component, ...props } = await importPromise();
13
+ const { MdxPage: u } = await import("./MdxPage-CbwYRKf5.js"), { default: c, ...l } = await m();
18
14
  return {
19
- element: /* @__PURE__ */ jsxRuntimeExports.jsx(
20
- MdxPage,
15
+ element: /* @__PURE__ */ s.jsx(
16
+ u,
21
17
  {
22
- mdxComponent: Component,
23
- ...props,
24
- defaultOptions
18
+ mdxComponent: c,
19
+ ...l,
20
+ defaultOptions: e
25
21
  }
26
22
  )
27
23
  };
28
24
  }
29
25
  };
30
26
  }
31
- );
32
- const rootRoutes = Array.from(
33
- new Set(routes.map((route) => route.path.split("/").at(0)))
34
- ).map((dir) => ({
35
- path: `/${dir}`,
36
- element: /* @__PURE__ */ jsxRuntimeExports.jsx(Redirect, {})
27
+ ), p = Array.from(
28
+ new Set(r.map((n) => n.path.split("/").at(0)))
29
+ ).map((n) => ({
30
+ path: `/${n}`,
31
+ element: /* @__PURE__ */ s.jsx(j, {})
37
32
  }));
38
- return [...routes, ...rootRoutes];
39
- };
40
- const Redirect = () => {
41
- const navItem = useTopNavigationItem();
42
- if (!navItem) return null;
43
- return traverseNavigation(navItem, (node, fullPath) => {
44
- if ("children" in node || !isPathItem(node)) return;
45
- return /* @__PURE__ */ jsxRuntimeExports.jsx(Navigate, { to: fullPath, replace: true });
46
- });
47
- };
48
- const markdownPlugin = ({
49
- markdownFiles,
50
- defaultOptions
33
+ return [...r, ...p];
34
+ }, j = () => {
35
+ const t = d();
36
+ return t ? f(t, (e, r) => {
37
+ if (!("children" in e || !g(e)))
38
+ return /* @__PURE__ */ s.jsx(x, { to: r, replace: !0 });
39
+ }) : null;
40
+ }, N = ({
41
+ markdownFiles: t,
42
+ defaultOptions: e
51
43
  }) => ({
52
- getRoutes: () => generateRoutes(markdownFiles, defaultOptions)
44
+ getRoutes: () => h(t, e)
53
45
  });
54
46
  export {
55
- markdownPlugin
47
+ N as markdownPlugin
56
48
  };
57
49
  //# 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 { 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: RouteObject[] = 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 getRoutes: () => generateRoutes(markdownFiles, defaultOptions),\n});\n"],"names":["jsx"],"mappings":";;;AAUa,MAAA,iBAAiB,CAC5B,eACA,mBACkB;AAClB,QAAM,SAAS,OAAO,QAAQ,aAAa,EAAE;AAAA,IAC3C,CAAC,CAAC,MAAM,aAAa,MAAM;AAEnB,YAAA,QAAQ,KAAK,MAAM,mBAAmB;AACtC,YAAA,OAAO,+BAAO,GAAG;AAEnB,UAAA,CAAC,KAAM,QAAO;AAEZ,YAAA,eAAe,KAAK,MAAM,GAAG;AACnC,YAAM,cAAc,aAAa,GAAG,EAAE,MAAM;AACtC,YAAA,YAAY,cACd,aAAa,MAAM,GAAG,EAAE,EAAE,KAAK,GAAG,IAClC;AAEG,aAAA;AAAA,QACL,MAAM;AAAA,QACN,MAAM,YAAY;AAChB,gBAAM,EAAE,QAAA,IAAY,MAAM,OAAO,uBAAc;AAC/C,gBAAM,EAAE,SAAS,WAAW,GAAG,MAAM,IAAI,MAAM;AACxC,iBAAA;AAAA,YACL,SACEA,kCAAA;AAAA,cAAC;AAAA,cAAA;AAAA,gBACC,cAAc;AAAA,gBACb,GAAG;AAAA,gBACJ;AAAA,cAAA;AAAA,YACF;AAAA,UAAA;AAAA,QAGN;AAAA,MAAA;AAAA,IAEJ;AAAA,EAAA;AAGF,QAAM,aAA4B,MAAM;AAAA,IACtC,IAAI,IAAI,OAAO,IAAI,CAAC,UAAU,MAAM,KAAK,MAAM,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC;AAAA,EAAA,EAC1D,IAAI,CAAC,SAAS;AAAA,IACd,MAAM,IAAI,GAAG;AAAA,IACb,+CAAU,UAAS,EAAA;AAAA,EACnB,EAAA;AAEF,SAAO,CAAC,GAAG,QAAQ,GAAG,UAAU;AAClC;AAEA,MAAM,WAAW,MAAM;AACrB,QAAM,UAAU;AAEZ,MAAA,CAAC,QAAgB,QAAA;AAErB,SAAO,mBAAmB,SAAS,CAAC,MAAM,aAAa;AACrD,QAAI,cAAc,QAAQ,CAAC,WAAW,IAAI,EAAG;AAC7C,WAAQA,kCAAAA,IAAA,UAAA,EAAS,IAAI,UAAU,SAAO,KAAC,CAAA;AAAA,EAAA,CACxC;AACH;ACtCO,MAAM,iBAAiB,CAAC;AAAA,EAC7B;AAAA,EACA;AACF,OAA+C;AAAA,EAC7C,WAAW,MAAM,eAAe,eAAe,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 { 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: RouteObject[] = 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 getRoutes: () => generateRoutes(markdownFiles, defaultOptions),\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,IAA4B,MAAM;AAAA,IACtC,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,OAA+C;AAAA,EAC7C,WAAW,MAAMF,EAAeC,GAAeC,CAAc;AAC/D;"}
@@ -1,10 +1,10 @@
1
- import "./jsx-runtime-DvZ6OKMM.js";
2
- import { o } from "./index-Dih8IAqw.js";
3
- import "./urql-DtVKPBx_.js";
1
+ import "./jsx-runtime-CJZJivg2.js";
2
+ import { o as n } from "./index-Bg82-bqR.js";
3
+ import "./urql-DMlBWUKL.js";
4
4
  import "zudoku/openapi-worker";
5
- import "./Markdown-B8nPVql1.js";
6
- import "./router-ButO1QyY.js";
5
+ import "./Markdown-DtLFdxD1.js";
6
+ import "./router-CBw2vqJE.js";
7
7
  export {
8
- o as openApiPlugin
8
+ n as openApiPlugin
9
9
  };
10
10
  //# sourceMappingURL=zudoku.plugin-openapi.js.map
@@ -1,13 +1,11 @@
1
- import { q as redirect } from "./router-ButO1QyY.js";
2
- const redirectPlugin = (options) => {
3
- return {
4
- getRoutes: () => options.redirects.map(({ from, to }) => ({
5
- path: from,
6
- loader: () => redirect(to)
7
- }))
8
- };
9
- };
1
+ import { q as o } from "./router-CBw2vqJE.js";
2
+ const a = (r) => ({
3
+ getRoutes: () => r.redirects.map(({ from: e, to: t }) => ({
4
+ path: e,
5
+ loader: () => o(t)
6
+ }))
7
+ });
10
8
  export {
11
- redirectPlugin
9
+ a as redirectPlugin
12
10
  };
13
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 { redirect } from \"react-router-dom\";\nimport type { DevPortalPlugin } from \"../../core/plugins.js\";\n\nexport type Redirect = {\n from: string;\n to: string;\n};\n\nexport const redirectPlugin = (options: {\n redirects: Redirect[];\n}): DevPortalPlugin => {\n return {\n getRoutes: () =>\n options.redirects.map(({ from, to }) => ({\n path: from,\n loader: () => redirect(to),\n })),\n };\n};\n"],"names":[],"mappings":";AAQa,MAAA,iBAAiB,CAAC,YAER;AACd,SAAA;AAAA,IACL,WAAW,MACT,QAAQ,UAAU,IAAI,CAAC,EAAE,MAAM,UAAU;AAAA,MACvC,MAAM;AAAA,MACN,QAAQ,MAAM,SAAS,EAAE;AAAA,IAAA,EACzB;AAAA,EAAA;AAER;"}
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};\n\nexport const redirectPlugin = (options: {\n redirects: Redirect[];\n}): DevPortalPlugin => {\n return {\n getRoutes: () =>\n options.redirects.map(({ from, to }) => ({\n path: from,\n loader: () => redirect(to),\n })),\n };\n};\n"],"names":["redirectPlugin","options","from","to","redirect"],"mappings":";AAQa,MAAAA,IAAiB,CAACC,OAGtB;AAAA,EACL,WAAW,MACTA,EAAQ,UAAU,IAAI,CAAC,EAAE,MAAAC,GAAM,IAAAC,SAAU;AAAA,IACvC,MAAMD;AAAA,IACN,QAAQ,MAAME,EAASD,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.55",
3
+ "version": "0.3.0-dev.57",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist",
@@ -67,7 +67,7 @@
67
67
  "dependencies": {
68
68
  "@envelop/core": "5.0.1",
69
69
  "@graphql-typed-document-node/core": "3.2.0",
70
- "@hiogawa/vite-plugin-ssr-css": "0.0.0",
70
+ "@hiogawa/vite-plugin-ssr-css": "0.0.1",
71
71
  "@lekoarts/rehype-meta-as-attributes": "3.0.1",
72
72
  "@mdx-js/react": "3.0.1",
73
73
  "@mdx-js/rollup": "3.0.1",
package/src/app/demo.tsx CHANGED
@@ -24,7 +24,12 @@ createRoot(document.getElementById("root")!).render(
24
24
  <StrictMode>
25
25
  <DevPortal
26
26
  page={{
27
- logo: "https://cdn.zudoku.dev/logos/icon.svg",
27
+ logo: {
28
+ src: {
29
+ light: "https://cdn.zudoku.dev/logos/icon.svg",
30
+ dark: "https://cdn.zudoku.dev/logos/icon.svg",
31
+ },
32
+ },
28
33
  pageTitle: "Developer Portal",
29
34
  }}
30
35
  navigation={[
@@ -5,7 +5,7 @@ import {
5
5
  type RouteObject,
6
6
  } from "react-router-dom";
7
7
  import config from "virtual:zudoku-config";
8
- import "virtual:zudoku-custom-css.css";
8
+ import "virtual:zudoku-theme.css";
9
9
  import { Bootstrap } from "zudoku/components";
10
10
  import "./main.css";
11
11
  import { getRoutesByConfig } from "./main.js";
@@ -8,7 +8,7 @@ import {
8
8
  createStaticHandler,
9
9
  createStaticRouter,
10
10
  } from "react-router-dom/server.js";
11
- import "virtual:zudoku-custom-css.css";
11
+ import "virtual:zudoku-theme.css";
12
12
  import { BootstrapStatic, ServerError } from "zudoku/components";
13
13
  import type { ZudokuConfig } from "../config/config.js";
14
14
  import type { FileWritingResponse } from "../vite/prerender.js";
package/src/app/main.tsx CHANGED
@@ -2,9 +2,9 @@ import { type RouteObject } from "react-router-dom";
2
2
  import { configuredApiKeysPlugin } from "virtual:zudoku-api-keys-plugin";
3
3
  import { configuredApiPlugins } from "virtual:zudoku-api-plugins";
4
4
  import { configuredAuthProvider } from "virtual:zudoku-auth";
5
- import "virtual:zudoku-custom-css.css";
6
5
  import { configuredDocsPlugins } from "virtual:zudoku-docs-plugins";
7
6
  import { configuredRedirectPlugin } from "virtual:zudoku-redirect-plugin";
7
+ import "virtual:zudoku-theme.css";
8
8
  import { DevPortal, Layout, RouterError } from "zudoku/components";
9
9
  import { isNavigationPlugin } from "zudoku/internal";
10
10
  import type { ZudokuConfig } from "../config/config.js";
@@ -13,11 +13,20 @@ import type { ZudokuContextOptions } from "../lib/core/DevPortalContext.js";
13
13
  export const convertZudokuConfigToOptions = (
14
14
  config: ZudokuConfig,
15
15
  ): ZudokuContextOptions => {
16
+ const fallbackLogo =
17
+ config.page?.logoUrl ?? "https://cdn.zudoku.dev/logos/icon.svg";
18
+
16
19
  return {
17
20
  page: {
18
- logo: "https://cdn.zudoku.dev/logos/icon.svg",
19
21
  pageTitle: "Developer Portal",
20
22
  ...config.page,
23
+ logo: {
24
+ ...config.page?.logo,
25
+ src: {
26
+ light: config.page?.logo?.src?.light ?? fallbackLogo,
27
+ dark: config.page?.logo?.src?.dark ?? fallbackLogo,
28
+ },
29
+ },
21
30
  },
22
31
  metadata: {
23
32
  favicon: "https://cdn.zudoku.dev/logos/icon.svg",
@@ -29,7 +29,12 @@ createRoot(root).render(
29
29
  <StrictMode>
30
30
  <DevPortal
31
31
  page={{
32
- logo: logoUrl ?? "https://cdn.zudoku.dev/logos/icon.svg",
32
+ logo: {
33
+ src: {
34
+ light: logoUrl ?? "https://cdn.zudoku.dev/logos/icon.svg",
35
+ dark: logoUrl ?? "https://cdn.zudoku.dev/logos/icon.svg",
36
+ },
37
+ },
33
38
  // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
34
39
  pageTitle: pageTitle ?? "Developer Portal",
35
40
  }}
@@ -0,0 +1,25 @@
1
+ import type { ReactNode } from "react";
2
+ import { Callout } from "../ui/Callout.js";
3
+
4
+ export const DeveloperHint = ({
5
+ children,
6
+ className,
7
+ }: {
8
+ children: ReactNode;
9
+ className?: string;
10
+ }) => {
11
+ // TODO: figure out a way to do that in consumer dev mode not "internal"
12
+ // so this doesn't get stripped out in the build
13
+ if (!import.meta.env.DEV) return;
14
+
15
+ return (
16
+ <Callout type="caution" title="Developer hint" className={className}>
17
+ <div className="flex flex-col gap-2">
18
+ <div>{children}</div>
19
+ <small className="italic">
20
+ Note: This hint is only shown in development mode.
21
+ </small>
22
+ </div>
23
+ </Callout>
24
+ );
25
+ };
@@ -19,7 +19,12 @@ export const Header = memo(function HeaderInner() {
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
21
  {page?.logo && (
22
- <img src={page.logo} alt={page.pageTitle} className="h-10" />
22
+ <img
23
+ src={isDark ? page.logo.src.dark : page.logo.src.light}
24
+ alt={page.logo.alt ?? page.pageTitle}
25
+ style={{ width: page.logo.width }}
26
+ className="h-10"
27
+ />
23
28
  )}
24
29
  <span className="font-bold text-2xl text-foreground/85 tracking-wide">
25
30
  {page?.pageTitle}
@@ -1,7 +1,7 @@
1
1
  import { UnlinkIcon } from "lucide-react";
2
2
  import { Link, useParams } from "react-router-dom";
3
- import { Callout } from "../ui/Callout.js";
4
3
  import { CategoryHeading } from "./CategoryHeading.js";
4
+ import { DeveloperHint } from "./DeveloperHint.js";
5
5
  import { Heading } from "./Heading.js";
6
6
  import { ProseClasses } from "./Markdown.js";
7
7
 
@@ -15,19 +15,13 @@ export const NotFoundPage = () => {
15
15
  Page not found
16
16
  <UnlinkIcon size={24} />
17
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
- )}
18
+ <DeveloperHint>
19
+ Start by adding a file at{" "}
20
+ <code>
21
+ {"{PROJECT_ROOT}"}/{params["*"]}.mdx
22
+ </code>{" "}
23
+ and add some content to make this error go away.
24
+ </DeveloperHint>
31
25
  <p>
32
26
  It seems that the page you are looking for does not exist or may have
33
27
  been moved. Please check the URL for any typos or use the navigation
@@ -8,7 +8,7 @@ import { useTopNavigationItem } from "../context/DevPortalProvider.js";
8
8
  import { useViewportAnchor } from "../context/ViewportAnchorContext.js";
9
9
  import { SideNavigationItem } from "./SideNavigationItem.js";
10
10
  import { useNavigationCollapsibleState } from "./useNavigationCollapsibleState.js";
11
- import { checkHasActiveItem, isPathItem } from "./util.js";
11
+ import { checkHasActiveItem } from "./util.js";
12
12
 
13
13
  export const SideNavigationCategory = ({
14
14
  category,
@@ -59,9 +59,9 @@ export const SideNavigationCategory = ({
59
59
  <Collapsible.Content className="CollapsibleContent -mx-[--padding-nav-item]">
60
60
  {/* margin on Collapsible.Content will lead jumpiness when animating because it's not added to the calculated height */}
61
61
  <ul className="space-y-0.5 mt-1.5 mb-4 ms-3">
62
- {category.children.map((item) => (
62
+ {category.children.map((item, i) => (
63
63
  <SideNavigationItem
64
- key={isPathItem(item) ? item.path + item.label : item.href}
64
+ key={i}
65
65
  category={category}
66
66
  item={item}
67
67
  activeAnchor={activeAnchor}
@@ -73,7 +73,14 @@ type Metadata = Partial<{
73
73
  }>;
74
74
  type Page = Partial<{
75
75
  pageTitle?: string;
76
- logo?: string;
76
+ logo?: {
77
+ src: {
78
+ light: string;
79
+ dark: string;
80
+ };
81
+ width?: string;
82
+ alt?: string;
83
+ };
77
84
  }>;
78
85
  export type ZudokuContextOptions = {
79
86
  metadata?: Metadata;
@@ -36,11 +36,15 @@ type OperationLike = {
36
36
  method: string;
37
37
  };
38
38
  export const slugifyOperation = (operation: OperationLike, tag?: string) => {
39
+ const summary =
40
+ operation.summary +
41
+ (operation.operationId
42
+ ? "-" + operation.operationId.slice(0, operation.summary ? 4 : 12)
43
+ : "");
44
+
39
45
  return slugify(
40
46
  (tag ? tag + "-" : "") +
41
- (operation.summary ??
42
- operation.operationId ??
43
- `${operation.method}-${operation.path}`),
47
+ (summary || `${operation.method}-${operation.path}`),
44
48
  { lower: true, trim: true },
45
49
  );
46
50
  };
@@ -0,0 +1,29 @@
1
+ import { Outlet } from "react-router-dom";
2
+ import { useAuth } from "../../authentication/hook.js";
3
+ import { DeveloperHint } from "../../components/DeveloperHint.js";
4
+ import { Button } from "../../ui/Button.js";
5
+
6
+ export const ProtectedRoute = () => {
7
+ const auth = useAuth();
8
+
9
+ // TODO: should we suspend here somehow?
10
+ if (auth.isAuthEnabled && auth.isPending) {
11
+ return null;
12
+ }
13
+
14
+ return auth.isAuthenticated ? (
15
+ <Outlet />
16
+ ) : !auth.isAuthEnabled ? (
17
+ <div className="flex flex-col justify-center gap-2 items-center h-1/2">
18
+ <DeveloperHint className="max-w-[600px]">
19
+ Authentication needs to be enabled for API keys to work. Enable it in
20
+ your Zudoku configuration under <code>authentication</code>.
21
+ </DeveloperHint>
22
+ </div>
23
+ ) : (
24
+ <div className="flex flex-col justify-center gap-2 items-center h-1/2">
25
+ Please login first to view this page
26
+ <Button onClick={() => auth.login()}>Login</Button>
27
+ </div>
28
+ );
29
+ };
@@ -1,14 +1,13 @@
1
- import { Outlet, type RouteObject } from "react-router-dom";
1
+ import { type RouteObject } from "react-router-dom";
2
2
  import invariant from "tiny-invariant";
3
- import { useAuth } from "../../authentication/hook.js";
4
3
  import { DevPortalContext } from "../../core/DevPortalContext.js";
5
4
  import {
6
5
  type ApiIdentityPlugin,
7
6
  type DevPortalPlugin,
8
7
  } from "../../core/plugins.js";
9
8
  import { RouterError } from "../../errors/RouterError.js";
10
- import { Button } from "../../ui/Button.js";
11
9
  import { CreateApiKey } from "./CreateApiKey.js";
10
+ import { ProtectedRoute } from "./ProtectedRoute.js";
12
11
  import { SettingsApiKeys } from "./SettingsApiKeys.js";
13
12
 
14
13
  const DEFAULT_API_KEY_ENDPOINT =
@@ -81,24 +80,6 @@ const createDefaultHandler = (endpoint: string): ApiKeyService => {
81
80
  };
82
81
  };
83
82
 
84
- const ProtectedRoute = () => {
85
- const auth = useAuth();
86
-
87
- // TODO: should we suspend here somehow?
88
- if (auth.isPending) {
89
- return null;
90
- }
91
-
92
- return auth.isAuthenticated ? (
93
- <Outlet />
94
- ) : (
95
- <div className="flex flex-col justify-center gap-2 items-center h-1/2 my-12">
96
- Please login first to view this page
97
- <Button onClick={() => auth.login()}>Login</Button>
98
- </div>
99
- );
100
- };
101
-
102
83
  export const apiKeyPlugin = (
103
84
  options: ApiKeyPluginOptions,
104
85
  ): DevPortalPlugin & ApiIdentityPlugin => {