zudoku 0.3.0-dev.70 → 0.3.0-dev.72

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 (78) hide show
  1. package/dist/app/main.js +6 -2
  2. package/dist/app/main.js.map +1 -1
  3. package/dist/lib/authentication/authentication.d.ts +6 -2
  4. package/dist/lib/authentication/components/SignIn.js +6 -2
  5. package/dist/lib/authentication/components/SignIn.js.map +1 -1
  6. package/dist/lib/authentication/components/SignOut.js +4 -2
  7. package/dist/lib/authentication/components/SignOut.js.map +1 -1
  8. package/dist/lib/authentication/providers/auth0.js +2 -2
  9. package/dist/lib/authentication/providers/auth0.js.map +1 -1
  10. package/dist/lib/authentication/providers/openid.d.ts +14 -8
  11. package/dist/lib/authentication/providers/openid.js +40 -39
  12. package/dist/lib/authentication/providers/openid.js.map +1 -1
  13. package/dist/lib/authentication/state.js +1 -1
  14. package/dist/lib/authentication/state.js.map +1 -1
  15. package/dist/lib/components/DevPortal.js +3 -6
  16. package/dist/lib/components/DevPortal.js.map +1 -1
  17. package/dist/lib/components/Header.js +7 -3
  18. package/dist/lib/components/Header.js.map +1 -1
  19. package/dist/lib/core/DevPortalContext.js +1 -0
  20. package/dist/lib/core/DevPortalContext.js.map +1 -1
  21. package/lib/{AnchorLink-C_pYhuZi.js → AnchorLink-DwUyvkrL.js} +3 -3
  22. package/lib/{AnchorLink-C_pYhuZi.js.map → AnchorLink-DwUyvkrL.js.map} +1 -1
  23. package/lib/AuthenticationPlugin-BuCQtecV.js +55 -0
  24. package/lib/AuthenticationPlugin-BuCQtecV.js.map +1 -0
  25. package/lib/{CategoryHeading-D5Q-X6lE.js → CategoryHeading-8saHYD9L.js} +3 -3
  26. package/lib/{CategoryHeading-D5Q-X6lE.js.map → CategoryHeading-8saHYD9L.js.map} +1 -1
  27. package/lib/{Combination-Cq0UkOXq.js → Combination-BMJg4xHo.js} +4 -4
  28. package/lib/{Combination-Cq0UkOXq.js.map → Combination-BMJg4xHo.js.map} +1 -1
  29. package/lib/{DevPortalProvider-BBhQ8kgI.js → DevPortalProvider-DMrk4yw1.js} +2 -2
  30. package/lib/{DevPortalProvider-BBhQ8kgI.js.map → DevPortalProvider-DMrk4yw1.js.map} +1 -1
  31. package/lib/{Input-DdAxw3vC.js → Input-98JuH9ox.js} +5 -5
  32. package/lib/{Input-DdAxw3vC.js.map → Input-98JuH9ox.js.map} +1 -1
  33. package/lib/{Markdown-DsCvZnhw.js → Markdown-CSdXDuYx.js} +2914 -3825
  34. package/lib/Markdown-CSdXDuYx.js.map +1 -0
  35. package/lib/{MdxPage-B_7x36CA.js → MdxPage-7CszsIct.js} +13 -12
  36. package/lib/{MdxPage-B_7x36CA.js.map → MdxPage-7CszsIct.js.map} +1 -1
  37. package/lib/{OperationList-i6FGZUu4.js → OperationList-CzXPfUMy.js} +29 -28
  38. package/lib/{OperationList-i6FGZUu4.js.map → OperationList-CzXPfUMy.js.map} +1 -1
  39. package/lib/{Route-Bsrd0acQ.js → Route-CueiECQ0.js} +2 -2
  40. package/lib/{Route-Bsrd0acQ.js.map → Route-CueiECQ0.js.map} +1 -1
  41. package/lib/{SlotletProvider-CpNYmq6S.js → SlotletProvider-ibdqvOie.js} +22 -21
  42. package/lib/{SlotletProvider-CpNYmq6S.js.map → SlotletProvider-ibdqvOie.js.map} +1 -1
  43. package/lib/{Spinner-BBPlEab_.js → Spinner-D0EmkS4m.js} +4 -4
  44. package/lib/{Spinner-BBPlEab_.js.map → Spinner-D0EmkS4m.js.map} +1 -1
  45. package/lib/index-CjHZiWvQ.js +916 -0
  46. package/lib/index-CjHZiWvQ.js.map +1 -0
  47. package/lib/{index-DT-cf5tv.js → index-D_ZoO3pi.js} +18 -17
  48. package/lib/{index-DT-cf5tv.js.map → index-D_ZoO3pi.js.map} +1 -1
  49. package/lib/{jsx-runtime-BIr0WBt_.js → jsx-runtime-D0NHp7nI.js} +3 -3
  50. package/lib/{jsx-runtime-BIr0WBt_.js.map → jsx-runtime-D0NHp7nI.js.map} +1 -1
  51. package/lib/{state-DKdaQzvh.js → state-DsXXkBLH.js} +2 -2
  52. package/lib/{state-DKdaQzvh.js.map → state-DsXXkBLH.js.map} +1 -1
  53. package/lib/zudoku.auth-auth0.js +26 -20
  54. package/lib/zudoku.auth-auth0.js.map +1 -1
  55. package/lib/zudoku.auth-clerk.js +2 -2
  56. package/lib/zudoku.auth-openid.js +211 -200
  57. package/lib/zudoku.auth-openid.js.map +1 -1
  58. package/lib/zudoku.components.js +473 -467
  59. package/lib/zudoku.components.js.map +1 -1
  60. package/lib/zudoku.plugin-api-keys.js +17 -16
  61. package/lib/zudoku.plugin-api-keys.js.map +1 -1
  62. package/lib/zudoku.plugin-custom-page.js +2 -2
  63. package/lib/zudoku.plugin-markdown.js +3 -3
  64. package/lib/zudoku.plugin-openapi.js +3 -3
  65. package/package.json +1 -1
  66. package/src/app/main.tsx +6 -8
  67. package/src/lib/authentication/authentication.ts +2 -2
  68. package/src/lib/authentication/components/SignIn.tsx +6 -2
  69. package/src/lib/authentication/components/SignOut.tsx +4 -2
  70. package/src/lib/authentication/providers/auth0.tsx +2 -2
  71. package/src/lib/authentication/providers/openid.tsx +53 -43
  72. package/src/lib/authentication/state.ts +1 -1
  73. package/src/lib/components/DevPortal.tsx +5 -7
  74. package/src/lib/components/Header.tsx +11 -3
  75. package/src/lib/core/DevPortalContext.ts +2 -0
  76. package/lib/AuthenticationPlugin-RvXALgvS.js +0 -52
  77. package/lib/AuthenticationPlugin-RvXALgvS.js.map +0 -1
  78. package/lib/Markdown-DsCvZnhw.js.map +0 -1
@@ -1,10 +1,11 @@
1
- import { b as y, j as e, O as f } from "./jsx-runtime-BIr0WBt_.js";
2
- import { u as j, a as g, R as v } from "./SlotletProvider-CpNYmq6S.js";
3
- import { u as w, a as h, I as k, S as b, b as K, c as N, d as A, e as E, f as x } from "./Input-DdAxw3vC.js";
4
- import { c as l, L as u, a as S } from "./Markdown-DsCvZnhw.js";
5
- import { u as p, x as I, y as P } from "./DevPortalProvider-BBhQ8kgI.js";
6
- import { B as o, p as C } from "./Combination-Cq0UkOXq.js";
7
- import { useState as D } from "react";
1
+ import { b as y, j as e, O as f } from "./jsx-runtime-D0NHp7nI.js";
2
+ import { u as j, a as g, R as v } from "./SlotletProvider-ibdqvOie.js";
3
+ import { u as w, a as p, I as k, S as b, b as K, c as N, d as A, e as E, f as x } from "./Input-98JuH9ox.js";
4
+ import { L as u } from "./index-CjHZiWvQ.js";
5
+ import { u as h, x as S, y as I } from "./DevPortalProvider-DMrk4yw1.js";
6
+ import { B as o, p as P } from "./Combination-BMJg4xHo.js";
7
+ import { useState as C } from "react";
8
+ import { c as l, a as D } from "./Markdown-CSdXDuYx.js";
8
9
  /**
9
10
  * @license lucide-react v0.378.0 - ISC
10
11
  *
@@ -69,11 +70,11 @@ class M extends Error {
69
70
  }
70
71
  }
71
72
  const L = ({ service: t }) => {
72
- const n = p(), r = y(), a = w({
73
+ const n = h(), r = y(), a = w({
73
74
  defaultValues: {
74
75
  expiresOn: "30"
75
76
  }
76
- }), i = h({
77
+ }), i = p({
77
78
  mutationFn: ({ description: s, expiresOn: c }) => {
78
79
  if (!t.createKey)
79
80
  throw new Error("deleteKey not implemented");
@@ -128,17 +129,17 @@ const L = ({ service: t }) => {
128
129
  return t.isAuthEnabled && t.isPending ? null : t.isAuthenticated ? /* @__PURE__ */ e.jsx(f, {}) : t.isAuthEnabled ? /* @__PURE__ */ e.jsxs("div", { className: "flex flex-col justify-center gap-2 items-center h-1/2", children: [
129
130
  "Please login first to view this page",
130
131
  /* @__PURE__ */ e.jsx(o, { onClick: () => t.login(), children: "Login" })
131
- ] }) : /* @__PURE__ */ e.jsx("div", { className: "flex flex-col justify-center gap-2 items-center h-1/2", children: /* @__PURE__ */ e.jsxs(C, { className: "max-w-[600px]", children: [
132
+ ] }) : /* @__PURE__ */ e.jsx("div", { className: "flex flex-col justify-center gap-2 items-center h-1/2", children: /* @__PURE__ */ e.jsxs(P, { className: "max-w-[600px]", children: [
132
133
  "Authentication needs to be enabled for API keys to work. Enable it in your Zudoku configuration under ",
133
134
  /* @__PURE__ */ e.jsx("code", { children: "authentication" }),
134
135
  "."
135
136
  ] }) });
136
137
  }, V = ({ service: t }) => {
137
- const n = p(), r = I(), { data: a } = P({
138
+ const n = h(), r = S(), { data: a } = I({
138
139
  queryFn: () => t.getKeys(n),
139
140
  queryKey: ["api-keys"],
140
141
  retry: !1
141
- }), i = h({
142
+ }), i = p({
142
143
  mutationFn: (s) => {
143
144
  if (!t.deleteKey)
144
145
  throw new Error("deleteKey not implemented");
@@ -164,7 +165,7 @@ const L = ({ service: t }) => {
164
165
  ] }) : /* @__PURE__ */ e.jsx(
165
166
  "ul",
166
167
  {
167
- className: S(
168
+ className: D(
168
169
  "grid grid-cols-1 rounded border",
169
170
  "lg:grid-cols-[minmax(250px,min-content)_1fr_min-content]"
170
171
  ),
@@ -210,7 +211,7 @@ const L = ({ service: t }) => {
210
211
  )
211
212
  ] });
212
213
  }, _ = ({ apiKey: t }) => {
213
- const [n, r] = D(!1);
214
+ const [n, r] = C(!1);
214
215
  return /* @__PURE__ */ e.jsxs("div", { className: "flex gap-2 items-center text-sm w-full", children: [
215
216
  /* @__PURE__ */ e.jsx(
216
217
  "input",
@@ -256,7 +257,7 @@ const L = ({ service: t }) => {
256
257
  const a = await fetch(r);
257
258
  return d(a.ok, "Failed to fetch API keys"), await a.json();
258
259
  }
259
- }), W = (t) => {
260
+ }), X = (t) => {
260
261
  const n = "endpoint" in t ? t.endpoint : Z, r = "getKeys" in t ? t : B(n);
261
262
  return {
262
263
  getProfileMenuItems: () => [
@@ -295,6 +296,6 @@ const L = ({ service: t }) => {
295
296
  };
296
297
  };
297
298
  export {
298
- W as apiKeyPlugin
299
+ X as apiKeyPlugin
299
300
  };
300
301
  //# sourceMappingURL=zudoku.plugin-api-keys.js.map
@@ -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","../src/lib/util/invariant.ts","../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","export default function invariant(\n condition: any,\n // Not providing an inline default argument for message as the result is smaller\n /**\n * Can provide a string, or a function that returns a string for cases where\n * the message takes a fair amount of effort to compute\n */\n message?: string | (() => string),\n): asserts condition {\n if (condition) {\n return;\n }\n // Condition not passed\n\n const provided: string | undefined =\n typeof message === \"function\" ? message() : message;\n\n throw new ZudokuError(provided ?? \"Invariant failed\");\n}\n\nclass ZudokuError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"ZudokuError\";\n }\n}\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 {\n Select,\n SelectContent,\n SelectGroup,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from \"../../components/Select.js\";\nimport { Button } from \"../../ui/Button.js\";\nimport { Input } from \"../../ui/Input.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 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 { Slotlet } from \"../../components/SlotletProvider.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 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 <Slotlet name=\"api-keys-list-page-before-keys\" />\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\",\n \"lg:grid-cols-[minmax(250px,min-content)_1fr_min-content]\",\n )}\n >\n {data.map((key) => (\n <li\n className=\"border-b 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 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 { DevPortalContext } from \"../../core/DevPortalContext.js\";\nimport {\n type ApiIdentityPlugin,\n type DevPortalPlugin,\n ProfileMenuPlugin,\n} from \"../../core/plugins.js\";\nimport { RouterError } from \"../../errors/RouterError.js\";\nimport invariant from \"../../util/invariant.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 & ProfileMenuPlugin => {\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 getProfileMenuItems: () => [\n {\n label: \"API Keys\",\n path: \"/settings/api-keys\",\n },\n ],\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","invariant","condition","message","provided","ZudokuError","CreateApiKey","service","context","useDevPortal","navigate","useNavigate","form","useForm","createKeyMutation","useMutation","description","expiresOn","expiresOnDate","addDaysToDate","jsxs","jsx","data","Input","Select","value","SelectTrigger","SelectValue","SelectContent","SelectGroup","option","SelectItem","Button","Link","days","date","ProtectedRoute","auth","useAuth","Outlet","DeveloperHint","SettingsApiKeys","queryClient","useQueryClient","useSuspenseQuery","deleteKeyMutation","id","Slotlet","cn","key","RevealApiKey","RotateCwIcon","TrashIcon","apiKey","revealed","setRevealed","useState","prev","EyeOffIcon","EyeIcon","DEFAULT_API_KEY_ENDPOINT","createDefaultHandler","endpoint","request","response","keys","apiKeyPlugin","options","RouterError"],"mappings":";;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AASA,MAAMA,IAASC,EAAiB,UAAU;AAAA,EACxC,CAAC,QAAQ,EAAE,GAAG,kCAAkC,KAAK,SAAQ,CAAE;AAAA,EAC/D;AAAA,IACE;AAAA,IACA;AAAA,MACE,GAAG;AAAA,MACH,KAAK;AAAA,IACN;AAAA,EACF;AAAA,EACD;AAAA,IACE;AAAA,IACA,EAAE,GAAG,0EAA0E,KAAK,SAAU;AAAA,EAC/F;AAAA,EACD,CAAC,QAAQ,EAAE,IAAI,KAAK,IAAI,MAAM,IAAI,KAAK,IAAI,MAAM,KAAK,SAAQ,CAAE;AAClE,CAAC;ACvBD;AAAA;AAAA;AAAA;AAAA;AAAA;AASA,MAAMC,IAAMD,EAAiB,OAAO;AAAA,EAClC,CAAC,QAAQ,EAAE,GAAG,gDAAgD,KAAK,SAAQ,CAAE;AAAA,EAC7E,CAAC,UAAU,EAAE,IAAI,MAAM,IAAI,MAAM,GAAG,KAAK,KAAK,UAAU;AAC1D,CAAC;ACZD;AAAA;AAAA;AAAA;AAAA;AAAA;AASA,MAAME,IAAWF,EAAiB,YAAY;AAAA,EAC5C,CAAC,QAAQ,EAAE,GAAG,qDAAqD,KAAK,SAAQ,CAAE;AAAA,EAClF,CAAC,QAAQ,EAAE,GAAG,cAAc,KAAK,SAAQ,CAAE;AAC7C,CAAC;ACZD;AAAA;AAAA;AAAA;AAAA;AAAA;AASA,MAAMG,IAAQH,EAAiB,SAAS;AAAA,EACtC,CAAC,QAAQ,EAAE,GAAG,WAAW,KAAK,SAAQ,CAAE;AAAA,EACxC,CAAC,QAAQ,EAAE,GAAG,yCAAyC,KAAK,SAAQ,CAAE;AAAA,EACtE,CAAC,QAAQ,EAAE,GAAG,sCAAsC,KAAK,SAAQ,CAAE;AACrE,CAAC;ACbuB,SAAAI,EACtBC,GAMAC,GACmB;AACnB,MAAID;AACF;AAIF,QAAME,IACJ,OAAOD,KAAY,aAAaA,MAAYA;AAExC,QAAA,IAAIE,EAAYD,KAAY,kBAAkB;AACtD;AAEA,MAAMC,UAAoB,MAAM;AAAA,EAC9B,YAAYF,GAAiB;AAC3B,UAAMA,CAAO,GACb,KAAK,OAAO;AAAA,EACd;AACF;ACPO,MAAMG,IAAe,CAAC,EAAE,SAAAC,QAA0C;AACvE,QAAMC,IAAUC,KACVC,IAAWC,KACXC,IAAOC,EAAsB;AAAA,IACjC,eAAe;AAAA,MACb,WAAW;AAAA,IACb;AAAA,EAAA,CACD,GACKC,IAAoBC,EAAY;AAAA,IACpC,YAAY,CAAC,EAAE,aAAAC,GAAa,WAAAC,QAA8B;AACpD,UAAA,CAACV,EAAQ;AACL,cAAA,IAAI,MAAM,2BAA2B;AAG7C,YAAMW,IACJD,MAAc,UAAUE,EAAc,OAAOF,CAAS,CAAC,IAAI;AAE7D,aAAOV,EAAQ;AAAA,QACb,EAAE,aAAAS,GAA0B,WAAWE,EAAc;AAAA,QACrDV;AAAA,MAAA;AAAA,IAEJ;AAAA,IACA,WAAW,MAAME,EAAS,qBAAqB;AAAA,EAAA,CAChD;AAEG,SAACH,EAAQ,YAKXa,gBAAAA,EAAA,KAAC,OAAI,EAAA,WAAU,4EACb,UAAA;AAAA,IAACC,gBAAAA,EAAAA,IAAA,OAAA,EAAI,WAAU,2CACb,UAAAA,gBAAAA,EAAA,IAAC,QAAG,WAAU,wBAAuB,yBAAW,EAClD,CAAA;AAAA,IACAA,gBAAAA,EAAA;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,UAAUT,EAAK,aAAa,CAACU,MAASR,EAAkB,OAAOQ,CAAI,CAAC;AAAA,QAEpE,UAAAF,gBAAAA,EAAA,KAAC,OAAI,EAAA,WAAU,uBAAsB,UAAA;AAAA,UAAA;AAAA,gCAElCG,GAAO,EAAA,GAAGX,EAAK,SAAS,aAAa,GAAG;AAAA,UAAE;AAAA,UAE3CQ,gBAAAA,EAAA;AAAA,YAACI;AAAA,YAAA;AAAA,cACC,eAAe,CAACC,MAAUb,EAAK,SAAS,aAAaa,CAAK;AAAA,cAC1D,cAAcb,EAAK,UAAU,WAAW;AAAA,cAExC,UAAA;AAAA,gBAACS,gBAAAA,EAAA,IAAAK,GAAA,EACC,UAACL,gBAAAA,EAAA,IAAAM,GAAA,CAAY,CAAA,GACf;AAAA,gBACAN,gBAAAA,EAAA,IAACO,GACC,EAAA,UAAAR,gBAAAA,EAAAA,KAACS,GACE,EAAA,UAAA;AAAA,kBAAA,CAAC,GAAG,IAAI,IAAI,EAAE,EAAE,IAAI,CAACC,MACnBV,gBAAAA,EAAAA,KAAAW,GAAA,EAAW,OAAO,OAAOD,CAAM,GAC7B,UAAA;AAAA,oBAAAA;AAAA,oBAAO;AAAA,kBAAA,EAAA,GAD8BA,CAExC,CACD;AAAA,kBACAT,gBAAAA,EAAA,IAAAU,GAAA,EAAW,OAAM,SAAQ,UAAK,SAAA;AAAA,gBAAA,EAAA,CACjC,EACF,CAAA;AAAA,cAAA;AAAA,YAAA;AAAA,UACF;AAAA,UACAX,gBAAAA,EAAAA,KAAC,OAAI,EAAA,WAAU,cACb,UAAA;AAAA,YAAAC,gBAAAA,EAAAA,IAACW,KAAO,UAAY,eAAA,CAAA;AAAA,YACpBX,gBAAAA,EAAA,IAACW,GAAO,EAAA,SAAQ,WAAU,SAAO,IAC/B,UAAAX,gBAAAA,EAAA,IAACY,GAAK,EAAA,IAAG,uBAAsB,UAAA,SAAM,CAAA,GACvC;AAAA,UAAA,GACF;AAAA,QAAA,GACF;AAAA,MAAA;AAAA,IACF;AAAA,EACF,EAAA,CAAA,IAzCO;AA2CX,GAEMd,IAAgB,CAACe,MAAyB;AACxC,QAAAC,wBAAW;AACjB,SAAAA,EAAK,QAAQA,EAAK,QAAQ,IAAID,CAAI,GAC3BC,EAAK;AACd,GCxFaC,IAAiB,MAAM;AAClC,QAAMC,IAAOC;AAGT,SAAAD,EAAK,iBAAiBA,EAAK,YACtB,OAGFA,EAAK,kBACThB,gBAAAA,MAAAkB,GAAA,CAAA,CAAO,IACLF,EAAK,gBAQPjB,gBAAAA,EAAA,KAAA,OAAA,EAAI,WAAU,yDAAwD,UAAA;AAAA,IAAA;AAAA,0BAEpEY,GAAO,EAAA,SAAS,MAAMK,EAAK,SAAS,UAAK,SAAA;AAAA,EAC5C,EAAA,CAAA,IAVAhB,gBAAAA,EAAA,IAAC,SAAI,WAAU,yDACb,UAACD,gBAAAA,EAAAA,KAAAoB,GAAA,EAAc,WAAU,iBAAgB,UAAA;AAAA,IAAA;AAAA,IAEPnB,gBAAAA,EAAAA,IAAC,UAAK,UAAc,iBAAA,CAAA;AAAA,IAAO;AAAA,EAAA,EAC7D,CAAA,EACF,CAAA;AAOJ,GCdaoB,IAAkB,CAAC,EAAE,SAAAlC,QAA0C;AAC1E,QAAMC,IAAUC,KACViC,IAAcC,KACd,EAAE,MAAArB,EAAK,IAAIsB,EAAiB;AAAA,IAChC,SAAS,MAAMrC,EAAQ,QAAQC,CAAO;AAAA,IACtC,UAAU,CAAC,UAAU;AAAA,IACrB,OAAO;AAAA,EAAA,CACR,GAEKqC,IAAoB9B,EAAY;AAAA,IACpC,YAAY,CAAC+B,MAAe;AACtB,UAAA,CAACvC,EAAQ;AACL,cAAA,IAAI,MAAM,2BAA2B;AAGtC,aAAAA,EAAQ,UAAUuC,GAAItC,CAAO;AAAA,IACtC;AAAA,IACA,WAAW,MAAM;AACf,MAAKkC,EAAY,kBAAkB,EAAE,UAAU,CAAC,UAAU,GAAG;AAAA,IAC/D;AAAA,EAAA,CACD;AAGC,SAAAtB,gBAAAA,EAAA,KAAC,OAAI,EAAA,WAAU,mFACb,UAAA;AAAA,IAACA,gBAAAA,EAAAA,KAAA,OAAA,EAAI,WAAU,2CACb,UAAA;AAAA,MAACC,gBAAAA,EAAA,IAAA,MAAA,EAAG,WAAU,wBAAuB,UAAQ,YAAA;AAAA,MAC5Cd,EAAQ,aACPc,gBAAAA,EAAA,IAACW,GAAO,EAAA,SAAO,IACb,UAAAX,gBAAAA,EAAA,IAACY,GAAK,EAAA,IAAG,0BAAyB,UAAA,iBAAc,CAAA,GAClD;AAAA,IAAA,GAEJ;AAAA,IAEAZ,gBAAAA,EAAAA,IAAC0B,GAAQ,EAAA,MAAK,iCAAiC,CAAA;AAAA,IAE9CzB,EAAK,WAAW,IACdF,gBAAAA,EAAA,KAAA,OAAA,EAAI,WAAU,8DACb,UAAA;AAAA,MAACA,gBAAAA,EAAAA,KAAA,OAAA,EAAI,WAAU,eAAc,UAAA;AAAA,QAAA;AAAA,8BAE1B,MAAG,EAAA;AAAA,QAAE;AAAA,MAAA,GAER;AAAA,MACCb,EAAQ,aACPc,gBAAAA,EAAA,IAACW,GAAO,EAAA,SAAO,IACb,UAAAX,gBAAAA,EAAA,IAACY,GAAK,EAAA,IAAG,0BAAyB,UAAA,iBAAc,CAAA,GAClD;AAAA,IAAA,EAAA,CAEJ,IAEAZ,gBAAAA,EAAA;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,WAAW2B;AAAA,UACT;AAAA,UACA;AAAA,QACF;AAAA,QAEC,UAAA1B,EAAK,IAAI,CAAC2B,MACT7B,gBAAAA,EAAA;AAAA,UAAC;AAAA,UAAA;AAAA,YACC,WAAU;AAAA,YAGV,UAAA;AAAA,cAACA,gBAAAA,EAAAA,KAAA,OAAA,EAAI,WAAU,+BACZ,UAAA;AAAA,gBAAA6B,EAAI,eAAeA,EAAI;AAAA,gBACxB7B,gBAAAA,EAAAA,KAAC,OAAI,EAAA,WAAU,iCACZ,UAAA;AAAA,kBAAI6B,EAAA,oCACF,OAAI,EAAA,UAAA;AAAA,oBAAA;AAAA,oBACS,IAAI,KAAKA,EAAI,SAAS,EAAE,mBAAmB;AAAA,kBAAA,GACzD;AAAA,kBAEDA,EAAI,aACH7B,gBAAAA,EAAAA,KAAC,OAAI,EAAA,UAAA;AAAA,oBAAA;AAAA,oBACS,IAAI,KAAK6B,EAAI,SAAS,EAAE,mBAAmB;AAAA,kBAAA,GACzD;AAAA,gBAAA,GAEJ;AAAA,cAAA,GACF;AAAA,cACA5B,gBAAAA,EAAAA,IAAC,SAAI,WAAU,uCACb,gCAAC6B,GAAa,EAAA,QAAQD,EAAI,IAAA,CAAK,EACjC,CAAA;AAAA,cACA7B,gBAAAA,EAAAA,KAAC,OAAI,EAAA,WAAU,cACZ,UAAA;AAAA,gBAAQb,EAAA,iCACNyB,GAAO,EAAA,MAAK,QACX,UAACX,gBAAAA,EAAAA,IAAA8B,GAAA,EAAa,MAAM,GAAA,CAAI,EAC1B,CAAA;AAAA,gBAED5C,EAAQ,aACPc,gBAAAA,EAAA;AAAA,kBAACW;AAAA,kBAAA;AAAA,oBACC,SAAQ;AAAA,oBACR,MAAK;AAAA,oBACL,SAAS,MAAM;AACT,sBAAC,QAAQ,iCAAiC,KAI5Ba,EAAA,OAAOI,EAAI,EAAE;AAAA,oBACjC;AAAA,oBACA,UAAUJ,EAAkB;AAAA,oBAE5B,UAAAxB,gBAAAA,EAAAA,IAAC+B,GAAU,EAAA,MAAM,GAAI,CAAA;AAAA,kBAAA;AAAA,gBACvB;AAAA,cAAA,GAEJ;AAAA,YAAA;AAAA,UAAA;AAAA,UA1CKH,EAAI;AAAA,QAAA,CA4CZ;AAAA,MAAA;AAAA,IACH;AAAA,EAEJ,EAAA,CAAA;AAEJ,GAEMC,IAAe,CAAC,EAAE,QAAAG,QAAiC;AACvD,QAAM,CAACC,GAAUC,CAAW,IAAIC,EAAS,EAAK;AAG5C,SAAApC,gBAAAA,EAAA,KAAC,OAAI,EAAA,WAAU,0CACb,UAAA;AAAA,IAAAC,gBAAAA,EAAA;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,WAAU;AAAA,QACV,OAAOiC,IAAWD,IAAS,IAAI,OAAOA,EAAO,MAAM;AAAA,MAAA;AAAA,IACrD;AAAA,IACAhC,gBAAAA,EAAA;AAAA,MAACW;AAAA,MAAA;AAAA,QACC,SAAQ;AAAA,QACR,SAAS,MAAMuB,EAAY,CAACE,MAAS,CAACA,CAAI;AAAA,QAC1C,MAAK;AAAA,QAEJ,UAAAH,0BAAYI,GAAW,EAAA,MAAM,IAAI,IAAKrC,gBAAAA,EAAA,IAACsC,GAAQ,EAAA,MAAM,GAAI,CAAA;AAAA,MAAA;AAAA,IAC5D;AAAA,EACF,EAAA,CAAA;AAEJ,GChIMC,IACJ,4DA8BIC,IAAuB,CAACC,OACrB;AAAA,EACL,WAAW,OAAOhB,GAAItC,MAAY;AAChC,UAAMuD,IAAU,IAAI,QAAQD,IAAW,0BAA0BhB,CAAE,IAAI;AAAA,MACrE,QAAQ;AAAA,IAAA,CACT;AAEK,UAAAtC,EAAQ,YAAYuD,CAAO;AAE3B,UAAAC,IAAW,MAAM,MAAMD,CAAO;AAC1B,IAAA9D,EAAA+D,EAAS,IAAI,0BAA0B;AAAA,EACnD;AAAA,EACA,WAAW,OAAOX,GAAQ7C,MAAY;AACpC,UAAMuD,IAAU,IAAI,QAAQD,IAAW,0BAA0B;AAAA,MAC/D,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,gBAAgB;AAAA,MAClB;AAAA,MACA,MAAM,KAAK,UAAUT,CAAM;AAAA,IAAA,CAC5B;AAEK,UAAA7C,EAAQ,YAAYuD,CAAO;AAE3B,UAAAC,IAAW,MAAM,MAAMD,CAAO;AAC1B,IAAA9D,EAAA+D,EAAS,IAAI,0BAA0B;AAAA,EACnD;AAAA,EACA,SAAS,OAAOxD,MAAY;AAC1B,UAAMuD,IAAU,IAAI,QAAQD,IAAW,wBAAwB;AAEzD,UAAAtD,EAAQ,YAAYuD,CAAO;AAE3B,UAAAE,IAAO,MAAM,MAAMF,CAAO;AACtB,WAAA9D,EAAAgE,EAAK,IAAI,0BAA0B,GAEtC,MAAMA,EAAK;EACpB;AAAA,IAISC,IAAe,CAC1BC,MAC4D;AAC5D,QAAML,IACJ,cAAcK,IAAUA,EAAQ,WAAWP,GAEvCrD,IACJ,aAAa4D,IAAUA,IAAUN,EAAqBC,CAAQ;AAEzD,SAAA;AAAA,IACL,qBAAqB,MAAM;AAAA,MACzB;AAAA,QACE,OAAO;AAAA,QACP,MAAM;AAAA,MACR;AAAA,IACF;AAAA,IACA,eAAe,OAAOtD,MAAY;AAC5B,UAAA;AAGK,gBAFM,MAAMD,EAAQ,QAAQC,CAAO,GAE9B,IAAI,CAACyC,OAAS;AAAA,UACxB,kBAAkB,CAACc,OACjBA,EAAQ,QAAQ,IAAI,iBAAiB,UAAUd,EAAI,GAAG,EAAE,GACjDc;AAAA,UAET,IAAId,EAAI;AAAA,UACR,OAAOA,EAAI,eAAeA,EAAI;AAAA,QAC9B,EAAA;AAAA,MAAA,QACI;AACN,eAAO;MACT;AAAA,IACF;AAAA,IACA,WAAW,MAEF;AAAA,MACL;AAAA,QACE,+BAAUb,GAAe,EAAA;AAAA,QACzB,oCAAegC,GAAY,EAAA;AAAA,QAC3B,UAAU;AAAA,UACR;AAAA,YACE,MAAM;AAAA,YACN,SAAU/C,gBAAAA,EAAA,IAAAoB,GAAA,EAAgB,SAAAlC,EAAkB,CAAA;AAAA,UAC9C;AAAA,UACA;AAAA,YACE,MAAM;AAAA,YACN,SAAUc,gBAAAA,EAAA,IAAAf,GAAA,EAAa,SAAAC,EAAkB,CAAA;AAAA,UAC3C;AAAA,QACF;AAAA,MACF;AAAA,IAAA;AAAA,EAEJ;AAEJ;","x_google_ignoreList":[0,1,2,3]}
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","../src/lib/util/invariant.ts","../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","export default function invariant(\n condition: any,\n // Not providing an inline default argument for message as the result is smaller\n /**\n * Can provide a string, or a function that returns a string for cases where\n * the message takes a fair amount of effort to compute\n */\n message?: string | (() => string),\n): asserts condition {\n if (condition) {\n return;\n }\n // Condition not passed\n\n const provided: string | undefined =\n typeof message === \"function\" ? message() : message;\n\n throw new ZudokuError(provided ?? \"Invariant failed\");\n}\n\nclass ZudokuError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"ZudokuError\";\n }\n}\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 {\n Select,\n SelectContent,\n SelectGroup,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from \"../../components/Select.js\";\nimport { Button } from \"../../ui/Button.js\";\nimport { Input } from \"../../ui/Input.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 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 { Slotlet } from \"../../components/SlotletProvider.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 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 <Slotlet name=\"api-keys-list-page-before-keys\" />\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\",\n \"lg:grid-cols-[minmax(250px,min-content)_1fr_min-content]\",\n )}\n >\n {data.map((key) => (\n <li\n className=\"border-b 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 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 { DevPortalContext } from \"../../core/DevPortalContext.js\";\nimport {\n type ApiIdentityPlugin,\n type DevPortalPlugin,\n ProfileMenuPlugin,\n} from \"../../core/plugins.js\";\nimport { RouterError } from \"../../errors/RouterError.js\";\nimport invariant from \"../../util/invariant.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 & ProfileMenuPlugin => {\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 getProfileMenuItems: () => [\n {\n label: \"API Keys\",\n path: \"/settings/api-keys\",\n },\n ],\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","invariant","condition","message","provided","ZudokuError","CreateApiKey","service","context","useDevPortal","navigate","useNavigate","form","useForm","createKeyMutation","useMutation","description","expiresOn","expiresOnDate","addDaysToDate","jsxs","jsx","data","Input","Select","value","SelectTrigger","SelectValue","SelectContent","SelectGroup","option","SelectItem","Button","Link","days","date","ProtectedRoute","auth","useAuth","Outlet","DeveloperHint","SettingsApiKeys","queryClient","useQueryClient","useSuspenseQuery","deleteKeyMutation","id","Slotlet","cn","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]}
@@ -1,5 +1,5 @@
1
- import { j as m } from "./jsx-runtime-BIr0WBt_.js";
2
- import { P as o } from "./Markdown-DsCvZnhw.js";
1
+ import { j as m } from "./jsx-runtime-D0NHp7nI.js";
2
+ import { P as o } from "./Markdown-CSdXDuYx.js";
3
3
  const l = (s) => ({
4
4
  getRoutes: () => s.map(({ path: e, element: t }) => ({
5
5
  path: e,
@@ -1,5 +1,5 @@
1
- import { j as o, N as x } from "./jsx-runtime-BIr0WBt_.js";
2
- import { v as d, z as g, l as h } from "./DevPortalProvider-BBhQ8kgI.js";
1
+ import { j as o, N as x } from "./jsx-runtime-D0NHp7nI.js";
2
+ import { v as d, z as g, l as h } from "./DevPortalProvider-DMrk4yw1.js";
3
3
  const f = (t, e) => {
4
4
  const a = Object.entries(t).flatMap(
5
5
  ([n, m]) => {
@@ -9,7 +9,7 @@ const f = (t, e) => {
9
9
  return {
10
10
  path: i.at(-1) === "index" ? i.slice(0, -1).join("/") : s,
11
11
  lazy: async () => {
12
- const { MdxPage: u } = await import("./MdxPage-B_7x36CA.js"), { default: c, ...l } = await m();
12
+ const { MdxPage: u } = await import("./MdxPage-7CszsIct.js"), { default: c, ...l } = await m();
13
13
  return {
14
14
  element: /* @__PURE__ */ o.jsx(
15
15
  u,
@@ -1,8 +1,8 @@
1
- import "./jsx-runtime-BIr0WBt_.js";
2
- import { o as n } from "./index-DT-cf5tv.js";
1
+ import "./jsx-runtime-D0NHp7nI.js";
2
+ import { o as n } from "./index-D_ZoO3pi.js";
3
3
  import "./urql-DMlBWUKL.js";
4
4
  import "zudoku/openapi-worker";
5
- import "./Markdown-DsCvZnhw.js";
5
+ import "./Markdown-CSdXDuYx.js";
6
6
  import "./router-BiRCp01d.js";
7
7
  export {
8
8
  n as openApiPlugin
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zudoku",
3
- "version": "0.3.0-dev.70",
3
+ "version": "0.3.0-dev.72",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist",
package/src/app/main.tsx CHANGED
@@ -77,14 +77,12 @@ export const getRoutesByConfig = (config: ZudokuConfig): RouteObject[] => {
77
77
  <Layout />
78
78
  </DevPortal>
79
79
  ),
80
- errorElement: (
81
- <DevPortal {...options}>
82
- <Layout>
83
- <RouterError />
84
- </Layout>
85
- </DevPortal>
86
- ),
87
- children: routes,
80
+ children: [
81
+ {
82
+ errorElement: <RouterError />,
83
+ children: routes,
84
+ },
85
+ ],
88
86
  },
89
87
  ];
90
88
  };
@@ -1,8 +1,8 @@
1
1
  import { DevPortalPlugin } from "../core/plugins.js";
2
2
 
3
3
  export interface AuthenticationProvider {
4
- signUp(): Promise<void>;
5
- signIn(): Promise<void>;
4
+ signUp(options?: { redirectTo?: string }): Promise<void>;
5
+ signIn(options?: { redirectTo?: string }): Promise<void>;
6
6
  signOut(): Promise<void>;
7
7
  getAccessToken(): Promise<string>;
8
8
  getAuthenticationPlugin?(): DevPortalPlugin;
@@ -1,11 +1,15 @@
1
1
  import { useEffect } from "react";
2
+ import { useSearchParams } from "react-router-dom";
2
3
  import { useDevPortal } from "../../components/context/DevPortalProvider.js";
3
4
 
4
5
  export const SignIn = () => {
5
6
  const context = useDevPortal();
7
+ const [search] = useSearchParams();
6
8
  useEffect(() => {
7
- void context.authentication?.signIn();
8
- }, [context.authentication]);
9
+ void context.authentication?.signIn({
10
+ redirectTo: search.get("redirect") ?? undefined,
11
+ });
12
+ }, [context.authentication, search]);
9
13
 
10
14
  return null;
11
15
  };
@@ -1,11 +1,13 @@
1
1
  import { useEffect } from "react";
2
+ import { useNavigate } from "react-router-dom";
2
3
  import { useDevPortal } from "../../components/context/DevPortalProvider.js";
3
4
 
4
5
  export const SignOut = () => {
5
6
  const context = useDevPortal();
7
+ const navigate = useNavigate();
6
8
  useEffect(() => {
7
- void context.authentication?.signOut();
8
- }, [context.authentication]);
9
+ void context.authentication?.signOut().then(() => navigate("/"));
10
+ }, [navigate, context.authentication]);
9
11
 
10
12
  return null;
11
13
  };
@@ -4,7 +4,7 @@ import { useAuthState } from "../state.js";
4
4
  import { OpenIDAuthenticationProvider } from "./openid.js";
5
5
 
6
6
  class Auth0AuthenticationProvider extends OpenIDAuthenticationProvider {
7
- override async signOut(): Promise<void> {
7
+ signOut = async (): Promise<void> => {
8
8
  useAuthState.setState({
9
9
  isAuthenticated: false,
10
10
  isPending: false,
@@ -39,7 +39,7 @@ class Auth0AuthenticationProvider extends OpenIDAuthenticationProvider {
39
39
  } else {
40
40
  logoutUrl = new URL(`${this.issuer}oidc/logout`);
41
41
  }
42
- }
42
+ };
43
43
  }
44
44
 
45
45
  const auth0Auth: AuthenticationProviderInitializer<
@@ -23,6 +23,7 @@ class OpenIdAuthPlugin extends AuthenticationPlugin {
23
23
  constructor(
24
24
  private callbackUrlPath: string,
25
25
  private handleCallback: () => Promise<string>,
26
+ public initialize?: () => Promise<void>,
26
27
  ) {
27
28
  super();
28
29
  }
@@ -48,12 +49,14 @@ export class OpenIDAuthenticationProvider implements AuthenticationProvider {
48
49
 
49
50
  protected callbackUrlPath = "/oauth/callback";
50
51
  protected logoutRedirectUrlPath = "/";
51
- private redirectToAfterSignUp: string;
52
- private redirectToAfterSignIn: string;
53
- private redirectToAfterSignOut: string;
52
+ private readonly redirectToAfterSignUp: string;
53
+ private readonly redirectToAfterSignIn: string;
54
+ private readonly redirectToAfterSignOut: string;
55
+ private readonly audience?: string;
54
56
 
55
57
  constructor({
56
58
  issuer,
59
+ audience,
57
60
  authorizationEndpoint,
58
61
  tokenEndpoint,
59
62
  clientId,
@@ -65,6 +68,7 @@ export class OpenIDAuthenticationProvider implements AuthenticationProvider {
65
68
  client_id: clientId,
66
69
  token_endpoint_auth_method: "none",
67
70
  };
71
+ this.audience = audience;
68
72
  this.issuer = issuer;
69
73
  this.authorizationEndpoint = authorizationEndpoint;
70
74
  this.tokenEndpoint = tokenEndpoint;
@@ -116,24 +120,28 @@ export class OpenIDAuthenticationProvider implements AuthenticationProvider {
116
120
  expiresOn: new Date(Date.now() + response.expires_in * 1000),
117
121
  tokenType: response.token_type,
118
122
  };
123
+ sessionStorage.setItem("openid-token", JSON.stringify(this.tokens));
119
124
  }
120
125
 
121
- async signUp() {
122
- return this.authorize(true);
126
+ async signUp({ redirectTo }: { redirectTo?: string } = {}) {
127
+ return this.authorize({
128
+ redirectTo: redirectTo ?? this.redirectToAfterSignUp,
129
+ });
123
130
  }
124
131
 
125
- async signIn() {
126
- return this.authorize();
132
+ async signIn({ redirectTo }: { redirectTo?: string } = {}) {
133
+ return this.authorize({
134
+ redirectTo: redirectTo ?? this.redirectToAfterSignIn,
135
+ });
127
136
  }
128
137
 
129
- private async authorize(signUp = false): Promise<void> {
138
+ private async authorize({
139
+ redirectTo,
140
+ }: {
141
+ redirectTo: string;
142
+ }): Promise<void> {
130
143
  const code_challenge_method = "S256";
131
144
  const authorizationServer = await this.getAuthServer();
132
- if (signUp) {
133
- localStorage.setItem("sign-up", "true");
134
- } else {
135
- localStorage.removeItem("sign-up");
136
- }
137
145
 
138
146
  if (!authorizationServer.authorization_endpoint) {
139
147
  throw new AuthorizationError("No authorization endpoint");
@@ -147,22 +155,16 @@ export class OpenIDAuthenticationProvider implements AuthenticationProvider {
147
155
  const codeVerifier = oauth.generateRandomCodeVerifier();
148
156
  const codeChallenge = await oauth.calculatePKCECodeChallenge(codeVerifier);
149
157
 
150
- localStorage.setItem(CODE_VERIFIER_KEY, codeVerifier);
158
+ sessionStorage.setItem(CODE_VERIFIER_KEY, codeVerifier);
151
159
 
152
160
  // redirect user to as.authorization_endpoint
153
161
  const authorizationUrl = new URL(
154
- signUp
155
- ? authorizationServer.registration_endpoint ??
156
- authorizationServer.authorization_endpoint
157
- : authorizationServer.authorization_endpoint,
162
+ authorizationServer.authorization_endpoint,
158
163
  );
159
164
 
160
- const redirectUrl = new URL(
161
- (signUp
162
- ? window.location.origin + this.redirectToAfterSignUp
163
- : window.location.origin + this.redirectToAfterSignIn) ??
164
- window.location.href,
165
- );
165
+ sessionStorage.setItem("redirect-to", redirectTo);
166
+
167
+ const redirectUrl = new URL(window.location.origin);
166
168
  redirectUrl.pathname = this.callbackUrlPath;
167
169
  redirectUrl.search = "";
168
170
 
@@ -175,6 +177,9 @@ export class OpenIDAuthenticationProvider implements AuthenticationProvider {
175
177
  "code_challenge_method",
176
178
  code_challenge_method,
177
179
  );
180
+ if (this.audience) {
181
+ authorizationUrl.searchParams.set("audience", this.audience);
182
+ }
178
183
 
179
184
  /**
180
185
  * We cannot be sure the AS supports PKCE so we're going to use state too. Use of PKCE is
@@ -222,12 +227,13 @@ export class OpenIDAuthenticationProvider implements AuthenticationProvider {
222
227
  return this.tokens.accessToken;
223
228
  }
224
229
 
225
- async signOut(): Promise<void> {
230
+ signOut = async () => {
226
231
  useAuthState.setState({
227
232
  isAuthenticated: false,
228
233
  isPending: false,
229
234
  profile: undefined,
230
235
  });
236
+ localStorage.removeItem("auto-login");
231
237
 
232
238
  const as = await this.getAuthServer();
233
239
 
@@ -253,16 +259,16 @@ export class OpenIDAuthenticationProvider implements AuthenticationProvider {
253
259
  } else {
254
260
  logoutUrl = redirectUrl;
255
261
  }
256
- }
262
+ };
257
263
 
258
- handleCallback = async (): Promise<string> => {
264
+ handleCallback = async () => {
259
265
  const url = new URL(window.location.href);
260
266
  const state = url.searchParams.get("state");
261
267
 
262
268
  // one eternity later, the user lands back on the redirect_uri
263
269
  // Authorization Code Grant Request & Response
264
- const codeVerifier = localStorage.getItem(CODE_VERIFIER_KEY);
265
- // localStorage.removeItem(CODE_VERIFIER_KEY);
270
+ const codeVerifier = sessionStorage.getItem(CODE_VERIFIER_KEY);
271
+ sessionStorage.removeItem(CODE_VERIFIER_KEY);
266
272
 
267
273
  if (!codeVerifier) {
268
274
  throw new AuthorizationError(
@@ -287,7 +293,7 @@ export class OpenIDAuthenticationProvider implements AuthenticationProvider {
287
293
  }
288
294
 
289
295
  const redirectUrl = new URL(url);
290
- redirectUrl.pathname = this.redirectToAfterSignIn ?? this.callbackUrlPath;
296
+ redirectUrl.pathname = this.redirectToAfterSignIn;
291
297
  redirectUrl.search = "";
292
298
 
293
299
  const response = await oauth.authorizationCodeGrantRequest(
@@ -337,23 +343,27 @@ export class OpenIDAuthenticationProvider implements AuthenticationProvider {
337
343
  profile,
338
344
  });
339
345
 
340
- if (localStorage.getItem("sign-up")) {
341
- return this.redirectToAfterSignUp;
342
- } else {
343
- return this.redirectToAfterSignIn;
344
- }
346
+ localStorage.setItem("auto-login", "1");
345
347
 
346
- // // Remove the query strings so react query doesn't keep retrying
347
- // // to make the token request
348
- // history.replaceState({}, "", window.location.pathname);
349
-
350
- // Returning true because we are using react query
351
- // return true;
348
+ return sessionStorage.getItem("redirect-to") ?? "/";
352
349
  };
353
350
 
354
351
  getAuthenticationPlugin() {
355
- return new OpenIdAuthPlugin(this.callbackUrlPath, () =>
356
- this.handleCallback(),
352
+ return new OpenIdAuthPlugin(
353
+ this.callbackUrlPath,
354
+ async () => {
355
+ return this.handleCallback();
356
+ },
357
+ async () => {
358
+ if (
359
+ typeof localStorage !== "undefined" &&
360
+ localStorage.getItem("auto-login")
361
+ ) {
362
+ localStorage.removeItem("auto-login");
363
+
364
+ await this.authorize({ redirectTo: window.location.pathname });
365
+ }
366
+ },
357
367
  );
358
368
  }
359
369
  }
@@ -1,7 +1,7 @@
1
1
  import { create } from "zustand";
2
2
 
3
3
  export const useAuthState = create<AuthState>(() => ({
4
- isPending: true,
4
+ isPending: false,
5
5
  isAuthenticated: false,
6
6
  }));
7
7
 
@@ -11,7 +11,7 @@ import {
11
11
  useState,
12
12
  } from "react";
13
13
  import { ErrorBoundary } from "react-error-boundary";
14
- import { useNavigation } from "react-router-dom";
14
+ import { Outlet, useNavigation } from "react-router-dom";
15
15
  import {
16
16
  DevPortalContext,
17
17
  queryClient,
@@ -67,11 +67,7 @@ const DevPortalInner = ({
67
67
  setDidNavigate(true);
68
68
  }, [didNavigate, navigation.location]);
69
69
 
70
- const devPortalContext = useMemo(() => new DevPortalContext(props), [props]);
71
-
72
- useEffect(() => {
73
- void devPortalContext.initialize();
74
- }, [devPortalContext]);
70
+ const [devPortalContext] = useState(() => new DevPortalContext(props));
75
71
 
76
72
  const heads = props.plugins
77
73
  ?.filter(hasHead)
@@ -87,7 +83,9 @@ const DevPortalInner = ({
87
83
  <ThemeProvider>
88
84
  <ComponentsProvider value={components}>
89
85
  <SlotletProvider slotlets={props.slotlets}>
90
- <ViewportAnchorProvider>{children}</ViewportAnchorProvider>
86
+ <ViewportAnchorProvider>
87
+ {children ?? <Outlet />}
88
+ </ViewportAnchorProvider>
91
89
  </SlotletProvider>
92
90
  </ComponentsProvider>
93
91
  </ThemeProvider>
@@ -1,7 +1,7 @@
1
1
  import { MoonStarIcon, SunIcon } from "lucide-react";
2
2
  import { memo } from "react";
3
3
 
4
- import { Link } from "react-router-dom";
4
+ import { Link, useLocation } from "react-router-dom";
5
5
  import { useAuth } from "../authentication/hook.js";
6
6
  import { isProfileMenuPlugin, NavigationItem } from "../core/plugins.js";
7
7
  import { Button } from "../ui/Button.js";
@@ -44,7 +44,8 @@ const RecursiveMenu = ({ item }: { item: NavigationItem }) => {
44
44
 
45
45
  export const Header = memo(function HeaderInner() {
46
46
  const [isDark, toggleTheme] = useTheme();
47
- const { isAuthenticated, profile, isAuthEnabled, login, logout } = useAuth();
47
+ const { isAuthenticated, profile, isAuthEnabled } = useAuth();
48
+ const { pathname } = useLocation();
48
49
  const context = useDevPortal();
49
50
  const { page, plugins } = context;
50
51
 
@@ -97,7 +98,14 @@ export const Header = memo(function HeaderInner() {
97
98
  <div className="items-center justify-self-end text-sm hidden lg:flex gap-2">
98
99
  {isAuthEnabled && !isAuthenticated ? (
99
100
  <Button variant="ghost" asChild>
100
- <Link to="/signin">Login</Link>
101
+ <Link
102
+ to={{
103
+ pathname: "/signin",
104
+ search: `?redirect=${encodeURIComponent(pathname)}`,
105
+ }}
106
+ >
107
+ Login
108
+ </Link>
101
109
  </Button>
102
110
  ) : (
103
111
  <DropdownMenu>
@@ -113,6 +113,8 @@ export class DevPortalContext {
113
113
  this.authentication = config.authentication;
114
114
  this.meta = config.metadata;
115
115
  this.page = config.page;
116
+
117
+ void this.initialize();
116
118
  }
117
119
 
118
120
  initialize = async () => {