zudoku 0.35.5 → 0.35.6

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 (45) hide show
  1. package/dist/lib/authentication/providers/openid.js +11 -7
  2. package/dist/lib/authentication/providers/openid.js.map +1 -1
  3. package/dist/lib/components/AnchorLink.js +3 -2
  4. package/dist/lib/components/AnchorLink.js.map +1 -1
  5. package/dist/lib/components/navigation/SidebarItem.js +3 -2
  6. package/dist/lib/components/navigation/SidebarItem.js.map +1 -1
  7. package/dist/lib/oas/graphql/index.d.ts +4 -3
  8. package/dist/lib/oas/graphql/index.js +9 -13
  9. package/dist/lib/oas/graphql/index.js.map +1 -1
  10. package/dist/lib/plugins/openapi/OperationList.js +1 -1
  11. package/dist/lib/plugins/openapi/OperationList.js.map +1 -1
  12. package/dist/lib/plugins/openapi/graphql/graphql.d.ts +1 -1
  13. package/dist/lib/plugins/openapi/graphql/graphql.js +1 -1
  14. package/dist/lib/plugins/openapi/graphql/graphql.js.map +1 -1
  15. package/lib/{Markdown-hBN9vkm5.js → Markdown-C0eXdzGn.js} +306 -306
  16. package/lib/{Markdown-hBN9vkm5.js.map → Markdown-C0eXdzGn.js.map} +1 -1
  17. package/lib/{MdxPage-UCWwxhzC.js → MdxPage-BKkG1cm1.js} +2 -2
  18. package/lib/{MdxPage-UCWwxhzC.js.map → MdxPage-BKkG1cm1.js.map} +1 -1
  19. package/lib/{OasProvider-CJ8KOnsH.js → OasProvider-CwhKwrwl.js} +2 -2
  20. package/lib/{OasProvider-CJ8KOnsH.js.map → OasProvider-CwhKwrwl.js.map} +1 -1
  21. package/lib/{OperationList-C4rpJdcE.js → OperationList-DGYoFitT.js} +4 -4
  22. package/lib/{OperationList-C4rpJdcE.js.map → OperationList-DGYoFitT.js.map} +1 -1
  23. package/lib/{SlotletProvider-D-XPr1Wg.js → SlotletProvider-BJC58V32.js} +2 -2
  24. package/lib/{SlotletProvider-D-XPr1Wg.js.map → SlotletProvider-BJC58V32.js.map} +1 -1
  25. package/lib/{createServer-BEFAOb-x.js → createServer-CbL1Uh2Q.js} +4108 -4066
  26. package/lib/createServer-CbL1Uh2Q.js.map +1 -0
  27. package/lib/{index-Dowg8c_k.js → index-Dm1QJHVl.js} +118 -116
  28. package/lib/index-Dm1QJHVl.js.map +1 -0
  29. package/lib/zudoku.auth-openid.js +282 -281
  30. package/lib/zudoku.auth-openid.js.map +1 -1
  31. package/lib/zudoku.components.js +2 -2
  32. package/lib/zudoku.plugin-api-catalog.js +1 -1
  33. package/lib/zudoku.plugin-api-keys.js +1 -1
  34. package/lib/zudoku.plugin-custom-pages.js +1 -1
  35. package/lib/zudoku.plugin-markdown.js +1 -1
  36. package/lib/zudoku.plugin-openapi.js +1 -1
  37. package/package.json +5 -5
  38. package/src/lib/authentication/providers/openid.tsx +12 -9
  39. package/src/lib/components/AnchorLink.tsx +4 -2
  40. package/src/lib/components/navigation/SidebarItem.tsx +3 -2
  41. package/src/lib/oas/graphql/index.ts +27 -27
  42. package/src/lib/plugins/openapi/OperationList.tsx +1 -1
  43. package/src/lib/plugins/openapi/graphql/graphql.ts +5 -4
  44. package/lib/createServer-BEFAOb-x.js.map +0 -1
  45. package/lib/index-Dowg8c_k.js.map +0 -1
@@ -22,7 +22,7 @@ import { S as Be, i as Ke, j as kt, n as P, m as be, l as je, o as A, p as Dt, q
22
22
  import { D as It, a as Qt, c as Rt, b as Ft, d as zt } from "./Dialog-sbgekbjb.js";
23
23
  import { Z as Ue } from "./invariant-Caa8-XvF.js";
24
24
  import { u as Ht, o as Lt } from "./objectEntries-BS7aAgOm.js";
25
- import { E as Ze, S as k, a as Bt, R as Kt } from "./SlotletProvider-D-XPr1Wg.js";
25
+ import { E as Ze, S as k, a as Bt, R as Kt } from "./SlotletProvider-BJC58V32.js";
26
26
  import { Button as $t } from "./ui/Button.js";
27
27
  import { Callout as Ut } from "./ui/Callout.js";
28
28
  import { M as Zt } from "./mutation-B81DztCT.js";
@@ -30,7 +30,7 @@ import * as q from "react";
30
30
  import Yt, { createContext as fe, StrictMode as Ye, useRef as se, useEffect as F, useState as $, useCallback as Vt, Suspense as me, memo as Ve, Component as Xt, createElement as ke, useMemo as re, useContext as _t } from "react";
31
31
  import * as Gt from "react-dom";
32
32
  import { C as ge } from "./ClientOnly-E7hGysn1.js";
33
- import { s as Wt, S as De, u as Jt, a as es, H as ts, P as ss, b as rs, V as ns, M as as } from "./Markdown-hBN9vkm5.js";
33
+ import { s as Wt, S as De, u as Jt, a as es, H as ts, P as ss, b as rs, V as ns, M as as } from "./Markdown-C0eXdzGn.js";
34
34
  import { B as oe, S as Xe } from "./Spinner-C6n4eOvh.js";
35
35
  import { c as E } from "./cn-qaFjX9_3.js";
36
36
  import { isSearchPlugin as is, isProfileMenuPlugin as os, isNavigationPlugin as ls, isEventConsumerPlugin as cs, needsInitialization as us, isApiIdentityPlugin as ds, isMdxProviderPlugin as hs, hasHead as fs } from "./zudoku.plugins.js";
@@ -5,7 +5,7 @@ import { j as d } from "./joinUrl-10po2Jdj.js";
5
5
  import { u as j, b as y } from "./hook-CfCFKZ-2.js";
6
6
  import { H as v } from "./index.esm-CltAN0Tf.js";
7
7
  import { Link as N } from "./zudoku.components.js";
8
- import { H as S, M as w } from "./Markdown-hBN9vkm5.js";
8
+ import { H as S, M as w } from "./Markdown-C0eXdzGn.js";
9
9
  const H = ({
10
10
  items: s,
11
11
  filterCatalogItems: l = (n) => n,
@@ -1,6 +1,6 @@
1
1
  import { j as e } from "./jsx-runtime-CYK1ROHF.js";
2
2
  import { RotateCwIcon as j, TrashIcon as v, EyeOffIcon as w, EyeIcon as K, CheckIcon as b, CopyIcon as k, FileKey2Icon as N } from "lucide-react";
3
- import { D as I, S as x, R as S } from "./SlotletProvider-D-XPr1Wg.js";
3
+ import { D as I, S as x, R as S } from "./SlotletProvider-BJC58V32.js";
4
4
  import { i as c } from "./invariant-Caa8-XvF.js";
5
5
  import { u as h } from "./useQuery-CQUwWR9i.js";
6
6
  import { u as d, S as A, a as C, b as E, c as P, d as D, e as p } from "./Select-FAYHOYTy.js";
@@ -1,6 +1,6 @@
1
1
  import { j as o } from "./jsx-runtime-CYK1ROHF.js";
2
2
  import a from "react";
3
- import { P as n } from "./Markdown-hBN9vkm5.js";
3
+ import { P as n } from "./Markdown-C0eXdzGn.js";
4
4
  import { c } from "./cn-qaFjX9_3.js";
5
5
  import { u as p } from "./useExposedProps-BslIn-FE.js";
6
6
  const u = ({
@@ -53,7 +53,7 @@ const P = (e) => ({
53
53
  const u = {
54
54
  path: r,
55
55
  lazy: async () => {
56
- const { MdxPage: p } = await import("./MdxPage-UCWwxhzC.js"), { default: f, ...l } = await i();
56
+ const { MdxPage: p } = await import("./MdxPage-BKkG1cm1.js"), { default: f, ...l } = await i();
57
57
  return {
58
58
  element: /* @__PURE__ */ d.jsx(
59
59
  p,
@@ -5,7 +5,7 @@ import "./chunk-HA7DTUK3-ZGg2W6yV.js";
5
5
  import "./hook-CfCFKZ-2.js";
6
6
  import "./ui/Button.js";
7
7
  import "./joinUrl-10po2Jdj.js";
8
- import { U as n, o as s } from "./index-Dowg8c_k.js";
8
+ import { U as n, o as s } from "./index-Dm1QJHVl.js";
9
9
  export {
10
10
  n as UNTAGGED_PATH,
11
11
  s as openApiPlugin
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zudoku",
3
- "version": "0.35.5",
3
+ "version": "0.35.6",
4
4
  "type": "module",
5
5
  "homepage": "https://zudoku.dev",
6
6
  "repository": {
@@ -127,7 +127,7 @@
127
127
  }
128
128
  },
129
129
  "dependencies": {
130
- "@apidevtools/json-schema-ref-parser": "11.9.1",
130
+ "@apidevtools/json-schema-ref-parser": "11.9.3",
131
131
  "@envelop/core": "5.0.3",
132
132
  "@graphql-typed-document-node/core": "3.2.0",
133
133
  "@hookform/resolvers": "4.1.3",
@@ -157,7 +157,7 @@
157
157
  "@radix-ui/react-toggle-group": "1.1.2",
158
158
  "@radix-ui/react-tooltip": "1.1.8",
159
159
  "@radix-ui/react-visually-hidden": "1.1.2",
160
- "@scalar/openapi-parser": "0.10.6",
160
+ "@scalar/openapi-parser": "0.10.12",
161
161
  "@sentry/node": "9.1.0",
162
162
  "@sindresorhus/slugify": "2.2.1",
163
163
  "@stefanprobst/rehype-extract-toc": "2.2.1",
@@ -181,7 +181,7 @@
181
181
  "glob": "11.0.1",
182
182
  "graphql": "16.10.0",
183
183
  "graphql-type-json": "0.3.2",
184
- "graphql-yoga": "5.12.0",
184
+ "graphql-yoga": "5.13.2",
185
185
  "gray-matter": "4.0.3",
186
186
  "hast-util-to-jsx-runtime": "^2.3.6",
187
187
  "hast-util-to-string": "3.0.1",
@@ -240,7 +240,7 @@
240
240
  },
241
241
  "devDependencies": {
242
242
  "@graphql-codegen/cli": "5.0.5",
243
- "@graphql-codegen/client-preset": "4.6.2",
243
+ "@graphql-codegen/client-preset": "4.7.0",
244
244
  "@testing-library/react": "16.2.0",
245
245
  "@types/estree": "1.0.6",
246
246
  "@types/express": "5.0.0",
@@ -13,6 +13,7 @@ import { AuthorizationError, OAuthAuthorizationError } from "../errors.js";
13
13
  import { useAuthState, type UserProfile } from "../state.js";
14
14
 
15
15
  const CODE_VERIFIER_KEY = "code-verifier";
16
+ const STATE_KEY = "oauth-state";
16
17
 
17
18
  export interface OpenIdProviderData {
18
19
  accessToken: string;
@@ -201,16 +202,12 @@ export class OpenIDAuthenticationProvider implements AuthenticationProvider {
201
202
  });
202
203
 
203
204
  /**
204
- * We cannot be sure the AS supports PKCE so we're going to use state too. Use of PKCE is
205
- * backwards compatible even if the AS doesn't support it which is why we're using it regardless.
205
+ * The state parameter is used to prevent CSRF attacks and should be used in all authorization requests.
206
+ * It is independent of PKCE and should be used regardless of PKCE support.
206
207
  */
207
- if (
208
- authorizationServer.code_challenge_methods_supported?.includes("S256") !==
209
- true
210
- ) {
211
- const state = oauth.generateRandomState();
212
- authorizationUrl.searchParams.set("state", state);
213
- }
208
+ const state = oauth.generateRandomState();
209
+ sessionStorage.setItem(STATE_KEY, state);
210
+ authorizationUrl.searchParams.set("state", state);
214
211
 
215
212
  // now redirect the user to authorizationUrl.href
216
213
  location.href = authorizationUrl.href;
@@ -295,6 +292,12 @@ export class OpenIDAuthenticationProvider implements AuthenticationProvider {
295
292
  handleCallback = async () => {
296
293
  const url = new URL(window.location.href);
297
294
  const state = url.searchParams.get("state");
295
+ const storedState = sessionStorage.getItem(STATE_KEY);
296
+ sessionStorage.removeItem(STATE_KEY);
297
+
298
+ if (state !== storedState) {
299
+ throw new AuthorizationError("Invalid state parameter");
300
+ }
298
301
 
299
302
  // one eternity later, the user lands back on the redirect_uri
300
303
  // Authorization Code Grant Request & Response
@@ -8,11 +8,13 @@ import { useScrollToHash } from "../util/useScrollToAnchor.js";
8
8
  export const AnchorLink = (props: NavLinkProps) => {
9
9
  const location = useLocation();
10
10
  const scrollToHash = useScrollToHash();
11
- const hash = useHref(props.to).split("#")[1];
11
+ const href = useHref(props.to);
12
+ const [pathname, hash] = href.split("#");
12
13
 
13
14
  const handleClick = (event: MouseEvent<HTMLAnchorElement>) => {
14
15
  props.onClick?.(event);
15
- if (hash !== location.hash.slice(1)) return;
16
+ if (hash !== location.hash.slice(1) || pathname !== location.pathname)
17
+ return;
16
18
 
17
19
  event.preventDefault();
18
20
  scrollToHash(hash);
@@ -1,6 +1,6 @@
1
1
  import { cva } from "class-variance-authority";
2
2
  import { ExternalLinkIcon } from "lucide-react";
3
- import { NavLink, useSearchParams } from "react-router";
3
+ import { NavLink, useLocation, useSearchParams } from "react-router";
4
4
 
5
5
  import type { SidebarItem as SidebarItemType } from "../../../config/validators/SidebarSchema.js";
6
6
  import { joinPath } from "../../util/joinPath.js";
@@ -37,6 +37,7 @@ export const SidebarItem = ({
37
37
  item: SidebarItemType;
38
38
  onRequestClose?: () => void;
39
39
  }) => {
40
+ const location = useLocation();
40
41
  const { activeAnchor } = useViewportAnchor();
41
42
  const [searchParams] = useSearchParams();
42
43
 
@@ -76,7 +77,7 @@ export const SidebarItem = ({
76
77
  }}
77
78
  {...{ [DATA_ANCHOR_ATTR]: item.href.split("#")[1] }}
78
79
  className={navigationListItem({
79
- isActive: item.href.split("#")[1] === activeAnchor,
80
+ isActive: item.href === [location.pathname, activeAnchor].join("#"),
80
81
  className: item.badge?.placement !== "start" && "justify-between",
81
82
  })}
82
83
  onClick={onRequestClose}
@@ -42,21 +42,27 @@ type OperationLike = {
42
42
  export const createOperationSlug = (
43
43
  slugify: CountableSlugify,
44
44
  operation: OperationLike,
45
- tag?: string,
46
45
  ) => {
47
46
  const summary =
48
47
  operation.summary ||
49
48
  operation.operationId ||
50
49
  `${operation.method}-${operation.path}`;
51
- const prefix = tag ? `${tag}-` : "";
52
50
 
53
- return slugify(prefix + summary);
51
+ return slugify(summary);
54
52
  };
55
53
 
56
- export type SchemaImports = Record<
57
- string,
58
- () => Promise<{ schema: OpenAPIDocument }>
59
- >;
54
+ type SchemaImport = () => Promise<{ schema: OpenAPIDocument }>;
55
+
56
+ export type SchemaImports = Record<string, SchemaImport>;
57
+
58
+ type Context = {
59
+ schema: OpenAPIDocument;
60
+ operations: GraphQLOperationObject[];
61
+ tags: TagObject[];
62
+ schemaImports?: SchemaImports;
63
+ slugify: CountableSlugify;
64
+ slugs: Record<string, string>;
65
+ };
60
66
 
61
67
  const builder = new SchemaBuilder<{
62
68
  DefaultFieldNullability: false;
@@ -65,14 +71,7 @@ const builder = new SchemaBuilder<{
65
71
  JSONObject: any;
66
72
  JSONSchema: any;
67
73
  };
68
- Context: {
69
- schema: OpenAPIDocument;
70
- operations: GraphQLOperationObject[];
71
- tags: TagObject[];
72
- schemaImports?: SchemaImports;
73
- currentTag?: string;
74
- slugify: CountableSlugify;
75
- };
74
+ Context: Context;
76
75
  }>({
77
76
  defaultFieldNullability: false,
78
77
  });
@@ -116,6 +115,17 @@ export const getAllTags = (schema: OpenAPIDocument): TagObject[] => {
116
115
  ];
117
116
  };
118
117
 
118
+ const getAllSlugs = (operations: GraphQLOperationObject[]) =>
119
+ Object.fromEntries(
120
+ operations.map((op) => [
121
+ getSlugName(op),
122
+ createOperationSlug(slugifyWithCounter(), op),
123
+ ]),
124
+ );
125
+
126
+ const getSlugName = (op: GraphQLOperationObject) =>
127
+ `${op.path}-${op.method}-${op.operationId}-${op.summary}`;
128
+
119
129
  export const getAllOperations = (
120
130
  paths?: PathsObject,
121
131
  ): GraphQLOperationObject[] => {
@@ -340,19 +350,8 @@ const OperationItem = builder
340
350
  fields: (t) => ({
341
351
  slug: t.field({
342
352
  type: "String",
343
- resolve: (parent, _, ctx) => {
344
- const slugData = {
345
- summary: parent.summary,
346
- operationId: parent.operationId,
347
- path: parent.path,
348
- method: parent.method,
349
- };
350
-
351
- //TODO: fix parent tag parent.tags
352
- return createOperationSlug(ctx.slugify, slugData, parent.parentTag);
353
- },
353
+ resolve: (parent, _, ctx) => ctx.slugs[getSlugName(parent)]!,
354
354
  }),
355
-
356
355
  path: t.exposeString("path"),
357
356
  method: t.exposeString("method"),
358
357
  operationId: t.exposeString("operationId", { nullable: true }),
@@ -531,6 +530,7 @@ builder.queryType({
531
530
  ctx.operations = getAllOperations(schema.paths);
532
531
  ctx.slugify = slugifyWithCounter();
533
532
  ctx.tags = getAllTags(schema);
533
+ ctx.slugs = getAllSlugs(ctx.operations);
534
534
 
535
535
  return schema;
536
536
  },
@@ -194,7 +194,7 @@ export const OperationList = ({
194
194
  registerSidebarAnchor
195
195
  className="mb-0"
196
196
  >
197
- {tag}
197
+ {tag ?? "Other endpoints"}
198
198
  {showVersions && (
199
199
  <span className="text-xl text-muted-foreground ml-1.5">
200
200
  {" "}
@@ -360,12 +360,13 @@ export class TypedDocumentString<TResult, TVariables>
360
360
  implements DocumentTypeDecoration<TResult, TVariables>
361
361
  {
362
362
  __apiType?: DocumentTypeDecoration<TResult, TVariables>["__apiType"];
363
+ private value: string;
364
+ public __meta__?: Record<string, any> | undefined;
363
365
 
364
- constructor(
365
- private value: string,
366
- public __meta__?: Record<string, any> | undefined,
367
- ) {
366
+ constructor(value: string, __meta__?: Record<string, any> | undefined) {
368
367
  super(value);
368
+ this.value = value;
369
+ this.__meta__ = __meta__;
369
370
  }
370
371
 
371
372
  toString(): string & DocumentTypeDecoration<TResult, TVariables> {