zudoku 0.35.4 → 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 (60) 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 +2 -1
  11. package/dist/lib/plugins/openapi/OperationList.js.map +1 -1
  12. package/dist/lib/plugins/openapi/ParamInfos.js +1 -1
  13. package/dist/lib/plugins/openapi/ParamInfos.js.map +1 -1
  14. package/dist/lib/plugins/openapi/ParameterListItem.js +5 -3
  15. package/dist/lib/plugins/openapi/ParameterListItem.js.map +1 -1
  16. package/dist/lib/plugins/openapi/graphql/gql.d.ts +1 -1
  17. package/dist/lib/plugins/openapi/graphql/gql.js +1 -1
  18. package/dist/lib/plugins/openapi/graphql/gql.js.map +1 -1
  19. package/dist/lib/plugins/openapi/graphql/graphql.d.ts +2 -1
  20. package/dist/lib/plugins/openapi/graphql/graphql.js +3 -1
  21. package/dist/lib/plugins/openapi/graphql/graphql.js.map +1 -1
  22. package/dist/lib/plugins/openapi/schema/SchemaPropertyItem.js +5 -2
  23. package/dist/lib/plugins/openapi/schema/SchemaPropertyItem.js.map +1 -1
  24. package/lib/{Markdown-hBN9vkm5.js → Markdown-C0eXdzGn.js} +306 -306
  25. package/lib/{Markdown-hBN9vkm5.js.map → Markdown-C0eXdzGn.js.map} +1 -1
  26. package/lib/{MdxPage-UCWwxhzC.js → MdxPage-BKkG1cm1.js} +2 -2
  27. package/lib/{MdxPage-UCWwxhzC.js.map → MdxPage-BKkG1cm1.js.map} +1 -1
  28. package/lib/{OasProvider-BbSqUQka.js → OasProvider-CwhKwrwl.js} +2 -2
  29. package/lib/{OasProvider-BbSqUQka.js.map → OasProvider-CwhKwrwl.js.map} +1 -1
  30. package/lib/{OperationList-CENzwqY8.js → OperationList-DGYoFitT.js} +360 -362
  31. package/lib/OperationList-DGYoFitT.js.map +1 -0
  32. package/lib/{SlotletProvider-D-XPr1Wg.js → SlotletProvider-BJC58V32.js} +2 -2
  33. package/lib/{SlotletProvider-D-XPr1Wg.js.map → SlotletProvider-BJC58V32.js.map} +1 -1
  34. package/lib/{createServer-BEFAOb-x.js → createServer-CbL1Uh2Q.js} +4108 -4066
  35. package/lib/createServer-CbL1Uh2Q.js.map +1 -0
  36. package/lib/{index-BVhQWA89.js → index-Dm1QJHVl.js} +121 -117
  37. package/lib/index-Dm1QJHVl.js.map +1 -0
  38. package/lib/zudoku.auth-openid.js +282 -281
  39. package/lib/zudoku.auth-openid.js.map +1 -1
  40. package/lib/zudoku.components.js +2 -2
  41. package/lib/zudoku.plugin-api-catalog.js +1 -1
  42. package/lib/zudoku.plugin-api-keys.js +1 -1
  43. package/lib/zudoku.plugin-custom-pages.js +1 -1
  44. package/lib/zudoku.plugin-markdown.js +1 -1
  45. package/lib/zudoku.plugin-openapi.js +1 -1
  46. package/package.json +5 -5
  47. package/src/app/main.css +4 -0
  48. package/src/lib/authentication/providers/openid.tsx +12 -9
  49. package/src/lib/components/AnchorLink.tsx +4 -2
  50. package/src/lib/components/navigation/SidebarItem.tsx +3 -2
  51. package/src/lib/oas/graphql/index.ts +27 -27
  52. package/src/lib/plugins/openapi/OperationList.tsx +2 -1
  53. package/src/lib/plugins/openapi/ParamInfos.tsx +1 -1
  54. package/src/lib/plugins/openapi/ParameterListItem.tsx +20 -14
  55. package/src/lib/plugins/openapi/graphql/gql.ts +3 -3
  56. package/src/lib/plugins/openapi/graphql/graphql.ts +8 -4
  57. package/src/lib/plugins/openapi/schema/SchemaPropertyItem.tsx +10 -6
  58. package/lib/OperationList-CENzwqY8.js.map +0 -1
  59. package/lib/createServer-BEFAOb-x.js.map +0 -1
  60. package/lib/index-BVhQWA89.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-BVhQWA89.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.4",
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",
package/src/app/main.css CHANGED
@@ -123,6 +123,10 @@
123
123
  "calt" 1;
124
124
  }
125
125
 
126
+ ::selection {
127
+ @apply bg-primary/100 text-primary-foreground;
128
+ }
129
+
126
130
  .dark {
127
131
  color-scheme: dark;
128
132
  }
@@ -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
  },
@@ -46,6 +46,7 @@ export const OperationsFragment = graphql(/* GraphQL */ `
46
46
  required
47
47
  schema
48
48
  style
49
+ explode
49
50
  examples {
50
51
  name
51
52
  description
@@ -193,7 +194,7 @@ export const OperationList = ({
193
194
  registerSidebarAnchor
194
195
  className="mb-0"
195
196
  >
196
- {tag}
197
+ {tag ?? "Other endpoints"}
197
198
  {showVersions && (
198
199
  <span className="text-xl text-muted-foreground ml-1.5">
199
200
  {" "}
@@ -43,7 +43,7 @@ export const ParamInfos = ({
43
43
  extraItems?: unknown[];
44
44
  className?: string;
45
45
  }) => {
46
- const filteredItems = [...extraItems, ...getSchemaInfos(schema)].flatMap(
46
+ const filteredItems = [...getSchemaInfos(schema), ...extraItems].flatMap(
47
47
  (item) => (typeof item === "string" || isValidElement(item) ? item : []),
48
48
  );
49
49
 
@@ -5,6 +5,7 @@ import type { OperationListItemResult } from "./OperationList.js";
5
5
  import type { ParameterGroup } from "./OperationListItem.js";
6
6
  import { ParamInfos } from "./ParamInfos.js";
7
7
  import { EnumValues } from "./components/EnumValues.js";
8
+ import { SelectOnClick } from "./components/SelectOnClick.js";
8
9
 
9
10
  const getParameterSchema = (
10
11
  parameter: ParameterListItemResult,
@@ -35,23 +36,28 @@ export const ParameterListItem = ({
35
36
  return (
36
37
  <li className="p-4 bg-border/20 text-sm flex flex-col gap-1.5">
37
38
  <div className="flex items-center gap-2">
38
- <code>
39
- {group === "path" ? (
40
- <ColorizedParam
41
- name={parameter.name}
42
- backgroundOpacity="15%"
43
- className="px-2"
44
- slug={`${id}-${parameter.name}`}
45
- />
46
- ) : (
47
- parameter.name
48
- )}
49
- </code>
39
+ <SelectOnClick asChild>
40
+ <code>
41
+ {group === "path" ? (
42
+ <ColorizedParam
43
+ name={parameter.name}
44
+ backgroundOpacity="15%"
45
+ className="px-2"
46
+ slug={`${id}-${parameter.name}`}
47
+ />
48
+ ) : (
49
+ parameter.name
50
+ )}
51
+ </code>
52
+ </SelectOnClick>
50
53
  <ParamInfos
51
54
  schema={paramSchema}
52
55
  extraItems={[
53
- parameter.required && "required",
54
- parameter.style === "form" && "form",
56
+ parameter.required && (
57
+ <span className="text-primary">required</span>
58
+ ),
59
+ parameter.style && `style: ${parameter.style}`,
60
+ parameter.explode && `explode: ${parameter.explode}`,
55
61
  ]}
56
62
  />
57
63
  </div>
@@ -14,7 +14,7 @@ import * as types from "./graphql.js";
14
14
  */
15
15
  type Documents = {
16
16
  "\n query ServersQuery($input: JSON!, $type: SchemaType!) {\n schema(input: $input, type: $type) {\n url\n servers {\n url\n }\n }\n }\n": typeof types.ServersQueryDocument;
17
- "\n fragment OperationsFragment on OperationItem {\n slug\n summary\n method\n description\n operationId\n contentTypes\n path\n deprecated\n extensions\n parameters {\n name\n in\n description\n required\n schema\n style\n examples {\n name\n description\n externalValue\n value\n summary\n }\n }\n requestBody {\n content {\n mediaType\n encoding {\n name\n }\n examples {\n name\n description\n externalValue\n value\n summary\n }\n schema\n }\n description\n required\n }\n responses {\n statusCode\n links\n description\n content {\n examples {\n name\n description\n externalValue\n value\n summary\n }\n mediaType\n encoding {\n name\n }\n schema\n }\n }\n }\n": typeof types.OperationsFragmentFragmentDoc;
17
+ "\n fragment OperationsFragment on OperationItem {\n slug\n summary\n method\n description\n operationId\n contentTypes\n path\n deprecated\n extensions\n parameters {\n name\n in\n description\n required\n schema\n style\n explode\n examples {\n name\n description\n externalValue\n value\n summary\n }\n }\n requestBody {\n content {\n mediaType\n encoding {\n name\n }\n examples {\n name\n description\n externalValue\n value\n summary\n }\n schema\n }\n description\n required\n }\n responses {\n statusCode\n links\n description\n content {\n examples {\n name\n description\n externalValue\n value\n summary\n }\n mediaType\n encoding {\n name\n }\n schema\n }\n }\n }\n": typeof types.OperationsFragmentFragmentDoc;
18
18
  "\n query AllOperations(\n $input: JSON!\n $type: SchemaType!\n $tag: String\n $untagged: Boolean\n ) {\n schema(input: $input, type: $type) {\n servers {\n url\n }\n description\n summary\n title\n url\n version\n tags(name: $tag) {\n name\n description\n }\n operations(tag: $tag, untagged: $untagged) {\n slug\n ...OperationsFragment\n }\n }\n }\n": typeof types.AllOperationsDocument;
19
19
  "\n query getServerQuery($input: JSON!, $type: SchemaType!) {\n schema(input: $input, type: $type) {\n url\n servers {\n url\n }\n }\n }\n": typeof types.GetServerQueryDocument;
20
20
  "\n query GetCategories($input: JSON!, $type: SchemaType!) {\n schema(input: $input, type: $type) {\n url\n tags {\n name\n }\n }\n }\n": typeof types.GetCategoriesDocument;
@@ -23,7 +23,7 @@ type Documents = {
23
23
  const documents: Documents = {
24
24
  "\n query ServersQuery($input: JSON!, $type: SchemaType!) {\n schema(input: $input, type: $type) {\n url\n servers {\n url\n }\n }\n }\n":
25
25
  types.ServersQueryDocument,
26
- "\n fragment OperationsFragment on OperationItem {\n slug\n summary\n method\n description\n operationId\n contentTypes\n path\n deprecated\n extensions\n parameters {\n name\n in\n description\n required\n schema\n style\n examples {\n name\n description\n externalValue\n value\n summary\n }\n }\n requestBody {\n content {\n mediaType\n encoding {\n name\n }\n examples {\n name\n description\n externalValue\n value\n summary\n }\n schema\n }\n description\n required\n }\n responses {\n statusCode\n links\n description\n content {\n examples {\n name\n description\n externalValue\n value\n summary\n }\n mediaType\n encoding {\n name\n }\n schema\n }\n }\n }\n":
26
+ "\n fragment OperationsFragment on OperationItem {\n slug\n summary\n method\n description\n operationId\n contentTypes\n path\n deprecated\n extensions\n parameters {\n name\n in\n description\n required\n schema\n style\n explode\n examples {\n name\n description\n externalValue\n value\n summary\n }\n }\n requestBody {\n content {\n mediaType\n encoding {\n name\n }\n examples {\n name\n description\n externalValue\n value\n summary\n }\n schema\n }\n description\n required\n }\n responses {\n statusCode\n links\n description\n content {\n examples {\n name\n description\n externalValue\n value\n summary\n }\n mediaType\n encoding {\n name\n }\n schema\n }\n }\n }\n":
27
27
  types.OperationsFragmentFragmentDoc,
28
28
  "\n query AllOperations(\n $input: JSON!\n $type: SchemaType!\n $tag: String\n $untagged: Boolean\n ) {\n schema(input: $input, type: $type) {\n servers {\n url\n }\n description\n summary\n title\n url\n version\n tags(name: $tag) {\n name\n description\n }\n operations(tag: $tag, untagged: $untagged) {\n slug\n ...OperationsFragment\n }\n }\n }\n":
29
29
  types.AllOperationsDocument,
@@ -45,7 +45,7 @@ export function graphql(
45
45
  * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
46
46
  */
47
47
  export function graphql(
48
- source: "\n fragment OperationsFragment on OperationItem {\n slug\n summary\n method\n description\n operationId\n contentTypes\n path\n deprecated\n extensions\n parameters {\n name\n in\n description\n required\n schema\n style\n examples {\n name\n description\n externalValue\n value\n summary\n }\n }\n requestBody {\n content {\n mediaType\n encoding {\n name\n }\n examples {\n name\n description\n externalValue\n value\n summary\n }\n schema\n }\n description\n required\n }\n responses {\n statusCode\n links\n description\n content {\n examples {\n name\n description\n externalValue\n value\n summary\n }\n mediaType\n encoding {\n name\n }\n schema\n }\n }\n }\n",
48
+ source: "\n fragment OperationsFragment on OperationItem {\n slug\n summary\n method\n description\n operationId\n contentTypes\n path\n deprecated\n extensions\n parameters {\n name\n in\n description\n required\n schema\n style\n explode\n examples {\n name\n description\n externalValue\n value\n summary\n }\n }\n requestBody {\n content {\n mediaType\n encoding {\n name\n }\n examples {\n name\n description\n externalValue\n value\n summary\n }\n schema\n }\n description\n required\n }\n responses {\n statusCode\n links\n description\n content {\n examples {\n name\n description\n externalValue\n value\n summary\n }\n mediaType\n encoding {\n name\n }\n schema\n }\n }\n }\n",
49
49
  ): typeof import("./graphql.js").OperationsFragmentFragmentDoc;
50
50
  /**
51
51
  * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
@@ -212,6 +212,7 @@ export type OperationsFragmentFragment = {
212
212
  required?: boolean | null;
213
213
  schema?: any | null;
214
214
  style?: string | null;
215
+ explode?: boolean | null;
215
216
  examples?: Array<{
216
217
  __typename?: "ExampleItem";
217
218
  name: string;
@@ -359,12 +360,13 @@ export class TypedDocumentString<TResult, TVariables>
359
360
  implements DocumentTypeDecoration<TResult, TVariables>
360
361
  {
361
362
  __apiType?: DocumentTypeDecoration<TResult, TVariables>["__apiType"];
363
+ private value: string;
364
+ public __meta__?: Record<string, any> | undefined;
362
365
 
363
- constructor(
364
- private value: string,
365
- public __meta__?: Record<string, any> | undefined,
366
- ) {
366
+ constructor(value: string, __meta__?: Record<string, any> | undefined) {
367
367
  super(value);
368
+ this.value = value;
369
+ this.__meta__ = __meta__;
368
370
  }
369
371
 
370
372
  toString(): string & DocumentTypeDecoration<TResult, TVariables> {
@@ -390,6 +392,7 @@ export const OperationsFragmentFragmentDoc = new TypedDocumentString(
390
392
  required
391
393
  schema
392
394
  style
395
+ explode
393
396
  examples {
394
397
  name
395
398
  description
@@ -490,6 +493,7 @@ export const AllOperationsDocument = new TypedDocumentString(`
490
493
  required
491
494
  schema
492
495
  style
496
+ explode
493
497
  examples {
494
498
  name
495
499
  description
@@ -7,6 +7,7 @@ import { Button } from "../../../ui/Button.js";
7
7
  import { cn } from "../../../util/cn.js";
8
8
  import { objectEntries } from "../../../util/objectEntries.js";
9
9
  import { EnumValues } from "../components/EnumValues.js";
10
+ import { SelectOnClick } from "../components/SelectOnClick.js";
10
11
  import { ParamInfos } from "../ParamInfos.js";
11
12
  import { LogicalGroup } from "./LogicalGroup/LogicalGroup.js";
12
13
  import { SchemaView } from "./SchemaView.js";
@@ -72,10 +73,7 @@ export const SchemaPropertyItem = ({
72
73
  <div className="flex flex-col gap-2.5 justify-between text-sm">
73
74
  <div className="flex gap-2 items-center">
74
75
  <code>{name}</code>
75
- <ParamInfos
76
- schema={schema}
77
- extraItems={[group === "optional" && "optional"]}
78
- />
76
+ <ParamInfos schema={schema} />
79
77
  <RecursiveIndicator />
80
78
  </div>
81
79
  </div>
@@ -87,10 +85,16 @@ export const SchemaPropertyItem = ({
87
85
  <li className="p-4 bg-border/20 hover:bg-border/30">
88
86
  <div className="flex flex-col gap-2.5 justify-between text-sm">
89
87
  <div className="flex gap-2 items-center">
90
- <code>{name}</code>
88
+ <SelectOnClick asChild>
89
+ <code>{name}</code>
90
+ </SelectOnClick>
91
91
  <ParamInfos
92
92
  schema={schema}
93
- extraItems={[group === "optional" && "optional"]}
93
+ extraItems={[
94
+ group !== "optional" && (
95
+ <span className="text-primary">required</span>
96
+ ),
97
+ ]}
94
98
  />
95
99
  {schema.type === "array" &&
96
100
  "items" in schema &&