zudoku 0.3.0-dev.68 → 0.3.0-dev.69

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 (85) hide show
  1. package/dist/app/main.js +1 -0
  2. package/dist/app/main.js.map +1 -1
  3. package/dist/config/validators/validate.d.ts +3 -0
  4. package/dist/config/validators/validate.js +1 -0
  5. package/dist/config/validators/validate.js.map +1 -1
  6. package/dist/lib/components/DevPortal.d.ts +1 -0
  7. package/dist/lib/components/DevPortal.js +3 -1
  8. package/dist/lib/components/DevPortal.js.map +1 -1
  9. package/dist/lib/components/Layout.js +2 -1
  10. package/dist/lib/components/Layout.js.map +1 -1
  11. package/dist/lib/components/SlotletProvider.d.ts +9 -0
  12. package/dist/lib/components/SlotletProvider.js +11 -0
  13. package/dist/lib/components/SlotletProvider.js.map +1 -0
  14. package/dist/lib/components/context/ViewportAnchorContext.js +1 -2
  15. package/dist/lib/components/context/ViewportAnchorContext.js.map +1 -1
  16. package/dist/lib/components/navigation/SideNavigation.js +3 -2
  17. package/dist/lib/components/navigation/SideNavigation.js.map +1 -1
  18. package/dist/lib/core/DevPortalContext.d.ts +2 -0
  19. package/dist/lib/core/DevPortalContext.js.map +1 -1
  20. package/dist/lib/plugins/api-keys/SettingsApiKeys.js +2 -1
  21. package/dist/lib/plugins/api-keys/SettingsApiKeys.js.map +1 -1
  22. package/dist/lib/plugins/api-keys/index.js +1 -1
  23. package/dist/lib/plugins/api-keys/index.js.map +1 -1
  24. package/dist/lib/plugins/markdown/Toc.js +1 -2
  25. package/dist/lib/plugins/markdown/Toc.js.map +1 -1
  26. package/dist/lib/plugins/openapi/StaggeredRender.js +2 -3
  27. package/dist/lib/plugins/openapi/StaggeredRender.js.map +1 -1
  28. package/dist/lib/util/invariant.d.ts +6 -0
  29. package/dist/lib/util/invariant.js +21 -0
  30. package/dist/lib/util/invariant.js.map +1 -0
  31. package/dist/lib/util/requestIdleCallbackPolyfill.d.ts +1 -0
  32. package/dist/lib/util/requestIdleCallbackPolyfill.js +7 -0
  33. package/dist/lib/util/requestIdleCallbackPolyfill.js.map +1 -0
  34. package/dist/lib/util/useScrollToAnchor.js +2 -3
  35. package/dist/lib/util/useScrollToAnchor.js.map +1 -1
  36. package/lib/{AnchorLink-61IZfWrS.js → AnchorLink-C_pYhuZi.js} +2 -2
  37. package/lib/{AnchorLink-61IZfWrS.js.map → AnchorLink-C_pYhuZi.js.map} +1 -1
  38. package/lib/{CategoryHeading-aW8CL0KA.js → CategoryHeading-D5Q-X6lE.js} +2 -2
  39. package/lib/{CategoryHeading-aW8CL0KA.js.map → CategoryHeading-D5Q-X6lE.js.map} +1 -1
  40. package/lib/{Combination-BbWKjDLe.js → Combination-Cq0UkOXq.js} +2 -2
  41. package/lib/{Combination-BbWKjDLe.js.map → Combination-Cq0UkOXq.js.map} +1 -1
  42. package/lib/{Input-BY0B_0qy.js → Input-DdAxw3vC.js} +3 -3
  43. package/lib/{Input-BY0B_0qy.js.map → Input-DdAxw3vC.js.map} +1 -1
  44. package/lib/{Markdown-BO5EsS-C.js → Markdown-DsCvZnhw.js} +746 -748
  45. package/lib/Markdown-DsCvZnhw.js.map +1 -0
  46. package/lib/{MdxPage-DEfyHwSx.js → MdxPage-B_7x36CA.js} +28 -28
  47. package/lib/MdxPage-B_7x36CA.js.map +1 -0
  48. package/lib/{OperationList-VK1_1rzp.js → OperationList-i6FGZUu4.js} +7 -7
  49. package/lib/{OperationList-VK1_1rzp.js.map → OperationList-i6FGZUu4.js.map} +1 -1
  50. package/lib/{hook-gOGk1OUF.js → SlotletProvider-CpNYmq6S.js} +42 -33
  51. package/lib/SlotletProvider-CpNYmq6S.js.map +1 -0
  52. package/lib/{Spinner-6NfpF1CA.js → Spinner-BBPlEab_.js} +48 -48
  53. package/lib/Spinner-BBPlEab_.js.map +1 -0
  54. package/lib/{index-7W7DUZbY.js → index-DT-cf5tv.js} +4 -4
  55. package/lib/{index-7W7DUZbY.js.map → index-DT-cf5tv.js.map} +1 -1
  56. package/lib/zudoku.components.js +544 -534
  57. package/lib/zudoku.components.js.map +1 -1
  58. package/lib/zudoku.plugin-api-keys.js +49 -46
  59. package/lib/zudoku.plugin-api-keys.js.map +1 -1
  60. package/lib/zudoku.plugin-custom-page.js +1 -1
  61. package/lib/zudoku.plugin-markdown.js +1 -1
  62. package/lib/zudoku.plugin-openapi.js +2 -2
  63. package/package.json +1 -2
  64. package/src/app/main.tsx +1 -0
  65. package/src/lib/components/DevPortal.tsx +5 -1
  66. package/src/lib/components/Layout.tsx +3 -0
  67. package/src/lib/components/SlotletProvider.tsx +25 -0
  68. package/src/lib/components/context/ViewportAnchorContext.tsx +1 -2
  69. package/src/lib/components/navigation/SideNavigation.tsx +3 -0
  70. package/src/lib/core/DevPortalContext.ts +2 -0
  71. package/src/lib/plugins/api-keys/SettingsApiKeys.tsx +3 -0
  72. package/src/lib/plugins/api-keys/index.tsx +1 -1
  73. package/src/lib/plugins/markdown/Toc.tsx +1 -2
  74. package/src/lib/plugins/openapi/StaggeredRender.tsx +2 -3
  75. package/src/lib/util/invariant.ts +26 -0
  76. package/src/lib/util/requestIdleCallbackPolyfill.ts +6 -0
  77. package/src/lib/util/useScrollToAnchor.ts +2 -3
  78. package/dist/lib/util/requestIdle.d.ts +0 -2
  79. package/dist/lib/util/requestIdle.js +0 -3
  80. package/dist/lib/util/requestIdle.js.map +0 -1
  81. package/lib/Markdown-BO5EsS-C.js.map +0 -1
  82. package/lib/MdxPage-DEfyHwSx.js.map +0 -1
  83. package/lib/Spinner-6NfpF1CA.js.map +0 -1
  84. package/lib/hook-gOGk1OUF.js.map +0 -1
  85. package/src/lib/util/requestIdle.ts +0 -4
@@ -1,9 +1,9 @@
1
- import { b as f, j as e, O as j } from "./jsx-runtime-BIr0WBt_.js";
2
- import { u as g, R as v } from "./hook-gOGk1OUF.js";
3
- import { u as w, a as p, I as b, S as k, b as K, c as N, d as E, e as A, f as h } from "./Input-BY0B_0qy.js";
4
- import { c as l, L as x, a as P } from "./Markdown-BO5EsS-C.js";
5
- import { u as m, x as S, y as I } from "./DevPortalProvider-BBhQ8kgI.js";
6
- import { B as c, p as C } from "./Combination-BbWKjDLe.js";
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
7
  import { useState as D } from "react";
8
8
  /**
9
9
  * @license lucide-react v0.378.0 - ISC
@@ -57,27 +57,29 @@ const z = l("Trash", [
57
57
  ["path", { d: "M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6", key: "4alrt4" }],
58
58
  ["path", { d: "M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2", key: "v07s0e" }]
59
59
  ]);
60
- var M = process.env.NODE_ENV === "production", d = "Invariant failed";
61
- function u(t, n) {
62
- if (!t) {
63
- if (M)
64
- throw new Error(d);
65
- var r = typeof n == "function" ? n() : n, a = r ? "".concat(d, ": ").concat(r) : d;
66
- throw new Error(a);
60
+ function d(t, n) {
61
+ if (t)
62
+ return;
63
+ const r = typeof n == "function" ? n() : n;
64
+ throw new M(r ?? "Invariant failed");
65
+ }
66
+ class M extends Error {
67
+ constructor(n) {
68
+ super(n), this.name = "ZudokuError";
67
69
  }
68
70
  }
69
71
  const L = ({ service: t }) => {
70
- const n = m(), r = f(), a = w({
72
+ const n = p(), r = y(), a = w({
71
73
  defaultValues: {
72
74
  expiresOn: "30"
73
75
  }
74
- }), i = p({
75
- mutationFn: ({ description: s, expiresOn: o }) => {
76
+ }), i = h({
77
+ mutationFn: ({ description: s, expiresOn: c }) => {
76
78
  if (!t.createKey)
77
79
  throw new Error("deleteKey not implemented");
78
- const y = o !== "never" ? T(Number(o)) : void 0;
80
+ const m = c !== "never" ? T(Number(c)) : void 0;
79
81
  return t.createKey(
80
- { description: s, expiresOn: y },
82
+ { description: s, expiresOn: m },
81
83
  n
82
84
  );
83
85
  },
@@ -91,28 +93,28 @@ const L = ({ service: t }) => {
91
93
  onSubmit: a.handleSubmit((s) => i.mutate(s)),
92
94
  children: /* @__PURE__ */ e.jsxs("div", { className: "flex gap-2 flex-col", children: [
93
95
  "Note",
94
- /* @__PURE__ */ e.jsx(b, { ...a.register("description") }),
96
+ /* @__PURE__ */ e.jsx(k, { ...a.register("description") }),
95
97
  "Expiration",
96
98
  /* @__PURE__ */ e.jsxs(
97
- k,
99
+ b,
98
100
  {
99
101
  onValueChange: (s) => a.setValue("expiresOn", s),
100
102
  defaultValue: a.getValues("expiresOn"),
101
103
  children: [
102
104
  /* @__PURE__ */ e.jsx(K, { children: /* @__PURE__ */ e.jsx(N, {}) }),
103
- /* @__PURE__ */ e.jsx(E, { children: /* @__PURE__ */ e.jsxs(A, { children: [
104
- [7, 30, 60, 90].map((s) => /* @__PURE__ */ e.jsxs(h, { value: String(s), children: [
105
+ /* @__PURE__ */ e.jsx(A, { children: /* @__PURE__ */ e.jsxs(E, { children: [
106
+ [7, 30, 60, 90].map((s) => /* @__PURE__ */ e.jsxs(x, { value: String(s), children: [
105
107
  s,
106
108
  " days"
107
109
  ] }, s)),
108
- /* @__PURE__ */ e.jsx(h, { value: "never", children: "Never" })
110
+ /* @__PURE__ */ e.jsx(x, { value: "never", children: "Never" })
109
111
  ] }) })
110
112
  ]
111
113
  }
112
114
  ),
113
115
  /* @__PURE__ */ e.jsxs("div", { className: "flex gap-2", children: [
114
- /* @__PURE__ */ e.jsx(c, { children: "Generate Key" }),
115
- /* @__PURE__ */ e.jsx(c, { variant: "outline", asChild: !0, children: /* @__PURE__ */ e.jsx(x, { to: "/settings/api-keys/", children: "Cancel" }) })
116
+ /* @__PURE__ */ e.jsx(o, { children: "Generate Key" }),
117
+ /* @__PURE__ */ e.jsx(o, { variant: "outline", asChild: !0, children: /* @__PURE__ */ e.jsx(u, { to: "/settings/api-keys/", children: "Cancel" }) })
116
118
  ] })
117
119
  ] })
118
120
  }
@@ -121,22 +123,22 @@ const L = ({ service: t }) => {
121
123
  }, T = (t) => {
122
124
  const n = /* @__PURE__ */ new Date();
123
125
  return n.setDate(n.getDate() + t), n.toISOString();
124
- }, V = () => {
125
- const t = g();
126
- return t.isAuthEnabled && t.isPending ? null : t.isAuthenticated ? /* @__PURE__ */ e.jsx(j, {}) : t.isAuthEnabled ? /* @__PURE__ */ e.jsxs("div", { className: "flex flex-col justify-center gap-2 items-center h-1/2", children: [
126
+ }, F = () => {
127
+ const t = j();
128
+ 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: [
127
129
  "Please login first to view this page",
128
- /* @__PURE__ */ e.jsx(c, { onClick: () => t.login(), children: "Login" })
130
+ /* @__PURE__ */ e.jsx(o, { onClick: () => t.login(), children: "Login" })
129
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: [
130
132
  "Authentication needs to be enabled for API keys to work. Enable it in your Zudoku configuration under ",
131
133
  /* @__PURE__ */ e.jsx("code", { children: "authentication" }),
132
134
  "."
133
135
  ] }) });
134
- }, F = ({ service: t }) => {
135
- const n = m(), r = S(), { data: a } = I({
136
+ }, V = ({ service: t }) => {
137
+ const n = p(), r = I(), { data: a } = P({
136
138
  queryFn: () => t.getKeys(n),
137
139
  queryKey: ["api-keys"],
138
140
  retry: !1
139
- }), i = p({
141
+ }), i = h({
140
142
  mutationFn: (s) => {
141
143
  if (!t.deleteKey)
142
144
  throw new Error("deleteKey not implemented");
@@ -149,19 +151,20 @@ const L = ({ service: t }) => {
149
151
  return /* @__PURE__ */ e.jsxs("div", { className: "max-w-screen-lg h-full pt-[--padding-content-top] pb-[--padding-content-bottom]", children: [
150
152
  /* @__PURE__ */ e.jsxs("div", { className: "flex justify-between mb-4 border-b pb-3", children: [
151
153
  /* @__PURE__ */ e.jsx("h1", { className: "font-medium text-2xl", children: "API Keys" }),
152
- t.createKey && /* @__PURE__ */ e.jsx(c, { asChild: !0, children: /* @__PURE__ */ e.jsx(x, { to: "/settings/api-keys/new", children: "Create API Key" }) })
154
+ t.createKey && /* @__PURE__ */ e.jsx(o, { asChild: !0, children: /* @__PURE__ */ e.jsx(u, { to: "/settings/api-keys/new", children: "Create API Key" }) })
153
155
  ] }),
156
+ /* @__PURE__ */ e.jsx(g, { name: "api-keys-list-page-before-keys" }),
154
157
  a.length === 0 ? /* @__PURE__ */ e.jsxs("div", { className: "flex flex-col justify-center gap-4 items-center h-1/2 my-8", children: [
155
158
  /* @__PURE__ */ e.jsxs("div", { className: "text-center", children: [
156
159
  "No API keys created yet.",
157
160
  /* @__PURE__ */ e.jsx("br", {}),
158
161
  "Get started and create the first one now"
159
162
  ] }),
160
- t.createKey && /* @__PURE__ */ e.jsx(c, { asChild: !0, children: /* @__PURE__ */ e.jsx(x, { to: "/settings/api-keys/new", children: "Create API Key" }) })
163
+ t.createKey && /* @__PURE__ */ e.jsx(o, { asChild: !0, children: /* @__PURE__ */ e.jsx(u, { to: "/settings/api-keys/new", children: "Create API Key" }) })
161
164
  ] }) : /* @__PURE__ */ e.jsx(
162
165
  "ul",
163
166
  {
164
- className: P(
167
+ className: S(
165
168
  "grid grid-cols-1 rounded border",
166
169
  "lg:grid-cols-[minmax(250px,min-content)_1fr_min-content]"
167
170
  ),
@@ -185,9 +188,9 @@ const L = ({ service: t }) => {
185
188
  ] }),
186
189
  /* @__PURE__ */ e.jsx("div", { className: "items-center flex lg:justify-center", children: /* @__PURE__ */ e.jsx(_, { apiKey: s.key }) }),
187
190
  /* @__PURE__ */ e.jsxs("div", { className: "flex gap-2", children: [
188
- t.rollKey && /* @__PURE__ */ e.jsx(c, { size: "icon", children: /* @__PURE__ */ e.jsx(q, { size: 16 }) }),
191
+ t.rollKey && /* @__PURE__ */ e.jsx(o, { size: "icon", children: /* @__PURE__ */ e.jsx(q, { size: 16 }) }),
189
192
  t.deleteKey && /* @__PURE__ */ e.jsx(
190
- c,
193
+ o,
191
194
  {
192
195
  variant: "ghost",
193
196
  size: "icon",
@@ -217,7 +220,7 @@ const L = ({ service: t }) => {
217
220
  }
218
221
  ),
219
222
  /* @__PURE__ */ e.jsx(
220
- c,
223
+ o,
221
224
  {
222
225
  variant: "outline",
223
226
  onClick: () => r((a) => !a),
@@ -226,14 +229,14 @@ const L = ({ service: t }) => {
226
229
  }
227
230
  )
228
231
  ] });
229
- }, B = "https://zudoku-rewiringamerica-main-ef9c9c0.d2.zuplo.dev", G = (t) => ({
232
+ }, Z = "https://zudoku-rewiringamerica-main-ef9c9c0.d2.zuplo.dev", B = (t) => ({
230
233
  deleteKey: async (n, r) => {
231
234
  const a = new Request(t + `/v1/developer/api-keys/${n}`, {
232
235
  method: "DELETE"
233
236
  });
234
237
  await r.signRequest(a);
235
238
  const i = await fetch(a);
236
- u(i.ok, "Failed to delete API key");
239
+ d(i.ok, "Failed to delete API key");
237
240
  },
238
241
  createKey: async (n, r) => {
239
242
  const a = new Request(t + "/v1/developer/api-keys", {
@@ -245,16 +248,16 @@ const L = ({ service: t }) => {
245
248
  });
246
249
  await r.signRequest(a);
247
250
  const i = await fetch(a);
248
- u(i.ok, "Failed to create API key");
251
+ d(i.ok, "Failed to create API key");
249
252
  },
250
253
  getKeys: async (n) => {
251
254
  const r = new Request(t + "/v1/developer/api-keys");
252
255
  await n.signRequest(r);
253
256
  const a = await fetch(r);
254
- return u(a.ok, "Failed to fetch API keys"), await a.json();
257
+ return d(a.ok, "Failed to fetch API keys"), await a.json();
255
258
  }
256
259
  }), W = (t) => {
257
- const n = "endpoint" in t ? t.endpoint : B, r = "getKeys" in t ? t : G(n);
260
+ const n = "endpoint" in t ? t.endpoint : Z, r = "getKeys" in t ? t : B(n);
258
261
  return {
259
262
  getProfileMenuItems: () => [
260
263
  {
@@ -265,7 +268,7 @@ const L = ({ service: t }) => {
265
268
  getIdentities: async (a) => {
266
269
  try {
267
270
  return (await r.getKeys(a)).map((s) => ({
268
- authorizeRequest: (o) => (o.headers.set("Authorization", `Bearer ${s.key}`), o),
271
+ authorizeRequest: (c) => (c.headers.set("Authorization", `Bearer ${s.key}`), c),
269
272
  id: s.id,
270
273
  label: s.description ?? s.id
271
274
  }));
@@ -275,12 +278,12 @@ const L = ({ service: t }) => {
275
278
  },
276
279
  getRoutes: () => [
277
280
  {
278
- element: /* @__PURE__ */ e.jsx(V, {}),
281
+ element: /* @__PURE__ */ e.jsx(F, {}),
279
282
  errorElement: /* @__PURE__ */ e.jsx(v, {}),
280
283
  children: [
281
284
  {
282
285
  path: "/settings/api-keys",
283
- element: /* @__PURE__ */ e.jsx(F, { service: r })
286
+ element: /* @__PURE__ */ e.jsx(V, { service: r })
284
287
  },
285
288
  {
286
289
  path: "/settings/api-keys/new",
@@ -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/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 { 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 { 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 {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 invariant from \"tiny-invariant\";\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 { 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","isProduction","prefix","invariant","condition","message","provided","value","CreateApiKey","service","context","useDevPortal","navigate","useNavigate","form","useForm","createKeyMutation","useMutation","description","expiresOn","expiresOnDate","addDaysToDate","jsxs","jsx","data","Input","Select","SelectTrigger","SelectValue","SelectContent","SelectGroup","option","SelectItem","Button","Link","days","date","ProtectedRoute","auth","useAuth","Outlet","DeveloperHint","SettingsApiKeys","queryClient","useQueryClient","useSuspenseQuery","deleteKeyMutation","id","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,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","../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
1
  import { j as m } from "./jsx-runtime-BIr0WBt_.js";
2
- import { P as o } from "./Markdown-BO5EsS-C.js";
2
+ import { P as o } from "./Markdown-DsCvZnhw.js";
3
3
  const l = (s) => ({
4
4
  getRoutes: () => s.map(({ path: e, element: t }) => ({
5
5
  path: e,
@@ -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-DEfyHwSx.js"), { default: c, ...l } = await m();
12
+ const { MdxPage: u } = await import("./MdxPage-B_7x36CA.js"), { default: c, ...l } = await m();
13
13
  return {
14
14
  element: /* @__PURE__ */ o.jsx(
15
15
  u,
@@ -1,8 +1,8 @@
1
1
  import "./jsx-runtime-BIr0WBt_.js";
2
- import { o as n } from "./index-7W7DUZbY.js";
2
+ import { o as n } from "./index-DT-cf5tv.js";
3
3
  import "./urql-DMlBWUKL.js";
4
4
  import "zudoku/openapi-worker";
5
- import "./Markdown-BO5EsS-C.js";
5
+ import "./Markdown-DsCvZnhw.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.68",
3
+ "version": "0.3.0-dev.69",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist",
@@ -135,7 +135,6 @@
135
135
  "strip-ansi": "7.1.0",
136
136
  "tailwind-merge": "2.3.0",
137
137
  "tailwindcss": "3.4.4",
138
- "tiny-invariant": "1.3.3",
139
138
  "ulidx": "^2.3.0",
140
139
  "unist-util-visit": "5.0.0",
141
140
  "urql": "4.1.0",
package/src/app/main.tsx CHANGED
@@ -29,6 +29,7 @@ export const convertZudokuConfigToOptions = (
29
29
  },
30
30
  },
31
31
  },
32
+ slotlets: config.slotlets,
32
33
  metadata: {
33
34
  favicon: "https://cdn.zudoku.dev/logos/icon.svg",
34
35
  title: "%s | Developer Portal",
@@ -21,6 +21,7 @@ import { hasHead } from "../core/plugins.js";
21
21
  import { TopLevelError } from "../errors/TopLevelError.js";
22
22
  import { StaggeredRenderContext } from "../plugins/openapi/StaggeredRender.js";
23
23
  import { MdxComponents } from "../util/MdxComponents.js";
24
+ import "../util/requestIdleCallbackPolyfill.js";
24
25
  import {
25
26
  ComponentsProvider,
26
27
  DEFAULT_COMPONENTS,
@@ -28,6 +29,7 @@ import {
28
29
  import { DevPortalProvider } from "./context/DevPortalProvider.js";
29
30
  import { ThemeProvider } from "./context/ThemeContext.js";
30
31
  import { ViewportAnchorProvider } from "./context/ViewportAnchorContext.js";
32
+ import { SlotletProvider } from "./SlotletProvider.js";
31
33
 
32
34
  export const DevPortalSystemPaths = {
33
35
  Settings: "/settings",
@@ -84,7 +86,9 @@ const DevPortalInner = ({
84
86
  <MDXProvider components={mdxComponents}>
85
87
  <ThemeProvider>
86
88
  <ComponentsProvider value={components}>
87
- <ViewportAnchorProvider>{children}</ViewportAnchorProvider>
89
+ <SlotletProvider slotlets={props.slotlets}>
90
+ <ViewportAnchorProvider>{children}</ViewportAnchorProvider>
91
+ </SlotletProvider>
88
92
  </ComponentsProvider>
89
93
  </ThemeProvider>
90
94
  </MDXProvider>
@@ -8,6 +8,7 @@ import { useDevPortal } from "./context/DevPortalProvider.js";
8
8
  import { useViewportAnchor } from "./context/ViewportAnchorContext.js";
9
9
  import { Header } from "./Header.js";
10
10
  import { SideNavigation } from "./navigation/SideNavigation.js";
11
+ import { Slotlet } from "./SlotletProvider.js";
11
12
  import { Spinner } from "./Spinner.js";
12
13
 
13
14
  export const Layout = ({ children }: { children?: ReactNode }) => {
@@ -55,7 +56,9 @@ export const Layout = ({ children }: { children?: ReactNode }) => {
55
56
  "lg:peer-data-[navigation=true]:translate-x-[--side-nav-width] lg:peer-data-[navigation=true]:pl-12",
56
57
  )}
57
58
  >
59
+ <Slotlet name="zudoku-before-content" />
58
60
  {children ?? <Outlet />}
61
+ <Slotlet name="zudoku-after-content" />
59
62
  </main>
60
63
  </Suspense>
61
64
  </div>
@@ -0,0 +1,25 @@
1
+ import React, { ReactNode, useContext } from "react";
2
+
3
+ export type Slotlets = Record<string, ReactNode>;
4
+
5
+ const SlotletContext = React.createContext<Slotlets | undefined>({});
6
+
7
+ export const SlotletProvider = ({
8
+ slotlets,
9
+ children,
10
+ }: {
11
+ children: ReactNode;
12
+ slotlets?: Slotlets;
13
+ }) => {
14
+ return (
15
+ <SlotletContext.Provider value={slotlets}>
16
+ {children}
17
+ </SlotletContext.Provider>
18
+ );
19
+ };
20
+
21
+ export const Slotlet = ({ name }: { name: string }) => {
22
+ const x = useContext(SlotletContext);
23
+
24
+ return x?.[name];
25
+ };
@@ -8,7 +8,6 @@ import {
8
8
  useRef,
9
9
  useState,
10
10
  } from "react";
11
- import { requestIdle } from "../../util/requestIdle.js";
12
11
 
13
12
  type AnchorContextType = {
14
13
  activeAnchor?: string;
@@ -96,7 +95,7 @@ export const ViewportAnchorProvider = ({
96
95
  // reset the active anchor when we reach the top
97
96
  setActiveAnchor("");
98
97
  } else if (hasReachedBottom) {
99
- requestIdle(() => {
98
+ requestIdleCallback(() => {
100
99
  // set the last anchor when we reach the bottom
101
100
  const lastItem = Array.from(elements).pop();
102
101
  setActiveAnchor(lastItem?.id ?? "");
@@ -1,6 +1,7 @@
1
1
  import { useRef } from "react";
2
2
 
3
3
  import { useNavigation } from "../context/DevPortalProvider.js";
4
+ import { Slotlet } from "../SlotletProvider.js";
4
5
  import { SideNavigationCategory } from "./SideNavigationCategory.js";
5
6
  import { SideNavigationWrapper } from "./SideNavigationWrapper.js";
6
7
 
@@ -13,9 +14,11 @@ export const SideNavigation = () => {
13
14
  ref={navRef}
14
15
  pushMainContent={navigation.data.items.length > 0}
15
16
  >
17
+ <Slotlet name="zudoku-before-navigation" />
16
18
  {navigation.data.items.map((category) => (
17
19
  <SideNavigationCategory key={category.label} category={category} />
18
20
  ))}
21
+ <Slotlet name="zudoku-after-navigation" />
19
22
  </SideNavigationWrapper>
20
23
  );
21
24
  };
@@ -3,6 +3,7 @@ import { type ReactNode } from "react";
3
3
  import { type AuthenticationProvider } from "../authentication/authentication.js";
4
4
  import type { ComponentsContextType } from "../components/context/ComponentsContext.js";
5
5
  import { type DevPortalPath } from "../components/DevPortal.js";
6
+ import { Slotlets } from "../components/SlotletProvider.js";
6
7
  import type { MdxComponentsType } from "../util/MdxComponents.js";
7
8
  import {
8
9
  type DevPortalPlugin,
@@ -90,6 +91,7 @@ export type ZudokuContextOptions = {
90
91
  authentication?: AuthenticationProvider;
91
92
  navigation: NavigationItem[];
92
93
  plugins?: DevPortalPlugin[];
94
+ slotlets?: Slotlets;
93
95
  mdx?: {
94
96
  components?: MdxComponentsType;
95
97
  };
@@ -7,6 +7,7 @@ import { EyeIcon, EyeOffIcon, RotateCwIcon, TrashIcon } from "lucide-react";
7
7
  import { useState } from "react";
8
8
  import { Link } from "react-router-dom";
9
9
  import { useDevPortal } from "../../components/context/DevPortalProvider.js";
10
+ import { Slotlet } from "../../components/SlotletProvider.js";
10
11
  import { Button } from "../../ui/Button.js";
11
12
  import { cn } from "../../util/cn.js";
12
13
  import { ApiKeyService } from "./index.js";
@@ -44,6 +45,8 @@ export const SettingsApiKeys = ({ service }: { service: ApiKeyService }) => {
44
45
  )}
45
46
  </div>
46
47
 
48
+ <Slotlet name="api-keys-list-page-before-keys" />
49
+
47
50
  {data.length === 0 ? (
48
51
  <div className="flex flex-col justify-center gap-4 items-center h-1/2 my-8">
49
52
  <div className="text-center">
@@ -1,5 +1,4 @@
1
1
  import { type RouteObject } from "react-router-dom";
2
- import invariant from "tiny-invariant";
3
2
  import { DevPortalContext } from "../../core/DevPortalContext.js";
4
3
  import {
5
4
  type ApiIdentityPlugin,
@@ -7,6 +6,7 @@ import {
7
6
  ProfileMenuPlugin,
8
7
  } from "../../core/plugins.js";
9
8
  import { RouterError } from "../../errors/RouterError.js";
9
+ import invariant from "../../util/invariant.js";
10
10
  import { CreateApiKey } from "./CreateApiKey.js";
11
11
  import { ProtectedRoute } from "./ProtectedRoute.js";
12
12
  import { SettingsApiKeys } from "./SettingsApiKeys.js";
@@ -10,7 +10,6 @@ import {
10
10
  import { AnchorLink } from "../../components/AnchorLink.js";
11
11
  import { useViewportAnchor } from "../../components/context/ViewportAnchorContext.js";
12
12
  import { cn } from "../../util/cn.js";
13
- import { requestIdle } from "../../util/requestIdle.js";
14
13
 
15
14
  const DATA_ANCHOR_ATTR = "data-active";
16
15
 
@@ -84,7 +83,7 @@ export const Toc = ({ entries }: { entries: TocEntry[] }) => {
84
83
  if (paintedOnce.current) return;
85
84
 
86
85
  // after all is painted, the indicator should animate
87
- requestIdle(() => {
86
+ requestIdleCallback(() => {
88
87
  paintedOnce.current = true;
89
88
  });
90
89
  }, [activeAnchor]);
@@ -6,7 +6,6 @@ import {
6
6
  useEffect,
7
7
  useState,
8
8
  } from "react";
9
- import { cancelIdle, requestIdle } from "../../util/requestIdle.js";
10
9
 
11
10
  export const StaggeredRenderContext = createContext({ stagger: false });
12
11
 
@@ -19,11 +18,11 @@ const StaggeredRender = ({ children }: { children: ReactNode[] }) => {
19
18
  return;
20
19
  }
21
20
 
22
- const idle = requestIdle(() => {
21
+ const idle = requestIdleCallback(() => {
23
22
  setRenderAll(true);
24
23
  });
25
24
 
26
- return () => cancelIdle(idle);
25
+ return () => cancelIdleCallback(idle);
27
26
  }, [renderAll]);
28
27
 
29
28
  return !renderAll ? Children.toArray(children).slice(0, 3) : children;