zudoku 0.35.5 → 0.36.0

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 (131) hide show
  1. package/dist/app/entry.server.js +5 -1
  2. package/dist/app/entry.server.js.map +1 -1
  3. package/dist/config/validators/common.d.ts +176 -176
  4. package/dist/config/validators/common.js +8 -6
  5. package/dist/config/validators/common.js.map +1 -1
  6. package/dist/config/validators/validate.d.ts +63 -63
  7. package/dist/lib/authentication/providers/openid.js +11 -7
  8. package/dist/lib/authentication/providers/openid.js.map +1 -1
  9. package/dist/lib/components/AnchorLink.js +3 -2
  10. package/dist/lib/components/AnchorLink.js.map +1 -1
  11. package/dist/lib/components/Layout.js +3 -14
  12. package/dist/lib/components/Layout.js.map +1 -1
  13. package/dist/lib/components/Zudoku.js +3 -1
  14. package/dist/lib/components/Zudoku.js.map +1 -1
  15. package/dist/lib/components/cache.d.ts +7 -0
  16. package/dist/lib/components/cache.js +7 -0
  17. package/dist/lib/components/cache.js.map +1 -1
  18. package/dist/lib/components/context/ViewportAnchorContext.js +3 -6
  19. package/dist/lib/components/context/ViewportAnchorContext.js.map +1 -1
  20. package/dist/lib/components/context/ZudokuContext.d.ts +1 -1
  21. package/dist/lib/components/context/ZudokuContext.js +4 -3
  22. package/dist/lib/components/context/ZudokuContext.js.map +1 -1
  23. package/dist/lib/components/navigation/SidebarItem.js +3 -2
  24. package/dist/lib/components/navigation/SidebarItem.js.map +1 -1
  25. package/dist/lib/core/ZudokuContext.d.ts +8 -6
  26. package/dist/lib/core/ZudokuContext.js +4 -2
  27. package/dist/lib/core/ZudokuContext.js.map +1 -1
  28. package/dist/lib/core/plugins.d.ts +3 -3
  29. package/dist/lib/hooks/useEvent.test.js +1 -1
  30. package/dist/lib/hooks/useEvent.test.js.map +1 -1
  31. package/dist/lib/oas/graphql/index.d.ts +16 -4
  32. package/dist/lib/oas/graphql/index.js +59 -43
  33. package/dist/lib/oas/graphql/index.js.map +1 -1
  34. package/dist/lib/plugins/openapi/OperationList.js +19 -5
  35. package/dist/lib/plugins/openapi/OperationList.js.map +1 -1
  36. package/dist/lib/plugins/openapi/OperationListItem.js +1 -1
  37. package/dist/lib/plugins/openapi/OperationListItem.js.map +1 -1
  38. package/dist/lib/plugins/openapi/Sidecar.js +2 -2
  39. package/dist/lib/plugins/openapi/Sidecar.js.map +1 -1
  40. package/dist/lib/plugins/openapi/client/useCreateQuery.d.ts +1 -1
  41. package/dist/lib/plugins/openapi/client/useCreateQuery.js +2 -1
  42. package/dist/lib/plugins/openapi/client/useCreateQuery.js.map +1 -1
  43. package/dist/lib/plugins/openapi/graphql/gql.d.ts +4 -4
  44. package/dist/lib/plugins/openapi/graphql/gql.js +3 -3
  45. package/dist/lib/plugins/openapi/graphql/gql.js.map +1 -1
  46. package/dist/lib/plugins/openapi/graphql/graphql.d.ts +34 -45
  47. package/dist/lib/plugins/openapi/graphql/graphql.js +20 -30
  48. package/dist/lib/plugins/openapi/graphql/graphql.js.map +1 -1
  49. package/dist/lib/plugins/openapi/index.d.ts +5 -10
  50. package/dist/lib/plugins/openapi/index.js +29 -60
  51. package/dist/lib/plugins/openapi/index.js.map +1 -1
  52. package/dist/lib/plugins/openapi/interfaces.d.ts +3 -1
  53. package/dist/lib/plugins/openapi/util/createSidebarCategory.js +5 -7
  54. package/dist/lib/plugins/openapi/util/createSidebarCategory.js.map +1 -1
  55. package/dist/lib/util/traverse.js +2 -2
  56. package/dist/lib/util/traverse.js.map +1 -1
  57. package/dist/lib/util/useScrollToAnchor.js +2 -0
  58. package/dist/lib/util/useScrollToAnchor.js.map +1 -1
  59. package/dist/vite/api/schema-codegen.js +19 -4
  60. package/dist/vite/api/schema-codegen.js.map +1 -1
  61. package/dist/vite/api/schema-codegen.test.js +61 -0
  62. package/dist/vite/api/schema-codegen.test.js.map +1 -1
  63. package/dist/vite/plugin-api.js +3 -11
  64. package/dist/vite/plugin-api.js.map +1 -1
  65. package/lib/{AuthenticationPlugin-4ip08maU.js → AuthenticationPlugin-Cr6xjOJD.js} +2 -2
  66. package/lib/{AuthenticationPlugin-4ip08maU.js.map → AuthenticationPlugin-Cr6xjOJD.js.map} +1 -1
  67. package/lib/{Markdown-hBN9vkm5.js → Markdown-BlioIqkZ.js} +313 -311
  68. package/lib/Markdown-BlioIqkZ.js.map +1 -0
  69. package/lib/{MdxPage-UCWwxhzC.js → MdxPage-7XnN9J9R.js} +3 -3
  70. package/lib/{MdxPage-UCWwxhzC.js.map → MdxPage-7XnN9J9R.js.map} +1 -1
  71. package/lib/{OasProvider-CJ8KOnsH.js → OasProvider-BaRRMSsD.js} +3 -3
  72. package/lib/{OasProvider-CJ8KOnsH.js.map → OasProvider-BaRRMSsD.js.map} +1 -1
  73. package/lib/{OperationList-C4rpJdcE.js → OperationList-BjL1hzSx.js} +988 -961
  74. package/lib/OperationList-BjL1hzSx.js.map +1 -0
  75. package/lib/{SlotletProvider-D-XPr1Wg.js → SlotletProvider-CXb3wQiR.js} +2 -2
  76. package/lib/{SlotletProvider-D-XPr1Wg.js.map → SlotletProvider-CXb3wQiR.js.map} +1 -1
  77. package/lib/{circular-v7K6lDDh.js → circular-ByJI6Mci.js} +4887 -4419
  78. package/lib/circular-ByJI6Mci.js.map +1 -0
  79. package/lib/{createServer-BEFAOb-x.js → createServer-DjgKDpGV.js} +3887 -4291
  80. package/lib/createServer-DjgKDpGV.js.map +1 -0
  81. package/lib/{hook-CfCFKZ-2.js → hook-Bo80UX00.js} +75 -74
  82. package/lib/hook-Bo80UX00.js.map +1 -0
  83. package/lib/{index-Dowg8c_k.js → index-D5m8_oyY.js} +612 -650
  84. package/lib/index-D5m8_oyY.js.map +1 -0
  85. package/lib/post-processors/traverse.js +2 -2
  86. package/lib/post-processors/traverse.js.map +1 -1
  87. package/lib/zudoku.auth-auth0.js +1 -1
  88. package/lib/zudoku.auth-clerk.js +2 -2
  89. package/lib/zudoku.auth-openid.js +283 -282
  90. package/lib/zudoku.auth-openid.js.map +1 -1
  91. package/lib/zudoku.components.js +395 -397
  92. package/lib/zudoku.components.js.map +1 -1
  93. package/lib/zudoku.hooks.js +1 -1
  94. package/lib/zudoku.plugin-api-catalog.js +2 -2
  95. package/lib/zudoku.plugin-api-keys.js +2 -2
  96. package/lib/zudoku.plugin-custom-pages.js +1 -1
  97. package/lib/zudoku.plugin-markdown.js +1 -1
  98. package/lib/zudoku.plugin-openapi.js +4 -5
  99. package/lib/zudoku.plugin-openapi.js.map +1 -1
  100. package/lib/zudoku.plugins.js.map +1 -1
  101. package/package.json +5 -5
  102. package/src/app/entry.server.tsx +7 -1
  103. package/src/lib/authentication/providers/openid.tsx +12 -9
  104. package/src/lib/components/AnchorLink.tsx +4 -2
  105. package/src/lib/components/Layout.tsx +3 -16
  106. package/src/lib/components/Zudoku.tsx +5 -1
  107. package/src/lib/components/cache.ts +8 -0
  108. package/src/lib/components/context/ViewportAnchorContext.tsx +3 -6
  109. package/src/lib/components/context/ZudokuContext.ts +5 -4
  110. package/src/lib/components/navigation/SidebarItem.tsx +3 -2
  111. package/src/lib/core/ZudokuContext.ts +11 -8
  112. package/src/lib/core/plugins.ts +4 -4
  113. package/src/lib/hooks/useEvent.test.tsx +1 -1
  114. package/src/lib/oas/graphql/index.ts +116 -76
  115. package/src/lib/plugins/openapi/OperationList.tsx +31 -37
  116. package/src/lib/plugins/openapi/OperationListItem.tsx +1 -1
  117. package/src/lib/plugins/openapi/Sidecar.tsx +2 -2
  118. package/src/lib/plugins/openapi/client/useCreateQuery.ts +2 -1
  119. package/src/lib/plugins/openapi/graphql/gql.ts +17 -17
  120. package/src/lib/plugins/openapi/graphql/graphql.ts +62 -79
  121. package/src/lib/plugins/openapi/index.tsx +40 -84
  122. package/src/lib/plugins/openapi/interfaces.ts +4 -1
  123. package/src/lib/plugins/openapi/util/createSidebarCategory.tsx +5 -7
  124. package/src/lib/util/traverse.ts +2 -2
  125. package/src/lib/util/useScrollToAnchor.ts +2 -0
  126. package/lib/Markdown-hBN9vkm5.js.map +0 -1
  127. package/lib/OperationList-C4rpJdcE.js.map +0 -1
  128. package/lib/circular-v7K6lDDh.js.map +0 -1
  129. package/lib/createServer-BEFAOb-x.js.map +0 -1
  130. package/lib/hook-CfCFKZ-2.js.map +0 -1
  131. package/lib/index-Dowg8c_k.js.map +0 -1
@@ -42,21 +42,29 @@ 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
+ export type SchemaImport = () => Promise<{
55
+ schema: OpenAPIDocument;
56
+ slugs: ReturnType<typeof getAllSlugs>;
57
+ }>;
58
+
59
+ export type SchemaImports = Record<string, SchemaImport>;
60
+
61
+ type Context = {
62
+ schema: OpenAPIDocument;
63
+ operations: GraphQLOperationObject[];
64
+ schemaImports?: SchemaImports;
65
+ tags: ReturnType<typeof getAllTags>;
66
+ slugs: ReturnType<typeof getAllSlugs>;
67
+ };
60
68
 
61
69
  const builder = new SchemaBuilder<{
62
70
  DefaultFieldNullability: false;
@@ -65,14 +73,7 @@ const builder = new SchemaBuilder<{
65
73
  JSONObject: any;
66
74
  JSONSchema: any;
67
75
  };
68
- Context: {
69
- schema: OpenAPIDocument;
70
- operations: GraphQLOperationObject[];
71
- tags: TagObject[];
72
- schemaImports?: SchemaImports;
73
- currentTag?: string;
74
- slugify: CountableSlugify;
75
- };
76
+ Context: Context;
76
77
  }>({
77
78
  defaultFieldNullability: false,
78
79
  });
@@ -88,17 +89,15 @@ const JSONScalar = builder.addScalarType("JSON", GraphQLJSON);
88
89
  const JSONObjectScalar = builder.addScalarType("JSONObject", GraphQLJSONObject);
89
90
  const JSONSchemaScalar = builder.addScalarType("JSONSchema", GraphQLJSONSchema);
90
91
 
91
- const resolveExtensions = (obj: Record<string, any>) => {
92
- const extensions: Record<string, any> = {};
93
- for (const [key, value] of Object.entries(obj)) {
94
- if (key.startsWith("x-")) {
95
- extensions[key] = value;
96
- }
97
- }
98
- return extensions;
99
- };
92
+ const resolveExtensions = (obj: Record<string, any>) =>
93
+ Object.fromEntries(
94
+ Object.entries(obj).filter(([key]) => key.startsWith("x-")),
95
+ );
100
96
 
101
- export const getAllTags = (schema: OpenAPIDocument): TagObject[] => {
97
+ export const getAllTags = (
98
+ schema: OpenAPIDocument,
99
+ slugs: ReturnType<typeof getAllSlugs>["tags"],
100
+ ): Array<TagObject & { slug?: string }> => {
102
101
  const rootTags = schema.tags ?? [];
103
102
  const operationTags = new Set(
104
103
  Object.values(schema.paths ?? {})
@@ -108,14 +107,43 @@ export const getAllTags = (schema: OpenAPIDocument): TagObject[] => {
108
107
 
109
108
  return [
110
109
  // Keep root tags that are actually used in operations
111
- ...rootTags.filter((tag) => operationTags.has(tag.name)),
110
+ ...rootTags
111
+ .filter((tag) => operationTags.has(tag.name))
112
+ .map((tag) => ({ ...tag, slug: slugs[tag.name] })),
112
113
  // Add tags found in operations but not defined in root tags
113
114
  ...[...operationTags]
114
115
  .filter((tag) => !rootTags.some((rt) => rt.name === tag))
115
- .map((tag) => ({ name: tag })),
116
+ .map((tag) => ({ name: tag, slug: slugs[tag] })),
116
117
  ];
117
118
  };
118
119
 
120
+ export const getAllSlugs = (
121
+ ops: GraphQLOperationObject[],
122
+ schemaTags: TagObject[] = [],
123
+ ) => {
124
+ const slugify = slugifyWithCounter();
125
+
126
+ const tags = Array.from(
127
+ new Set([
128
+ ...ops.flatMap((op) => op.tags ?? []),
129
+ ...schemaTags.map((tag) => tag.name),
130
+ ]),
131
+ );
132
+
133
+ return {
134
+ operations: Object.fromEntries(
135
+ ops.map((op) => [
136
+ getOperationSlugKey(op),
137
+ createOperationSlug(slugify, op),
138
+ ]),
139
+ ),
140
+ tags: Object.fromEntries(tags.map((tag) => [tag, slugify(tag)])),
141
+ };
142
+ };
143
+
144
+ const getOperationSlugKey = (op: GraphQLOperationObject) =>
145
+ [op.path, op.method, op.operationId, op.summary].filter(Boolean).join("-");
146
+
119
147
  export const getAllOperations = (
120
148
  paths?: PathsObject,
121
149
  ): GraphQLOperationObject[] => {
@@ -153,30 +181,38 @@ export const getAllOperations = (
153
181
  return operations;
154
182
  };
155
183
 
156
- const SchemaTag = builder.objectRef<TagObject>("SchemaTag").implement({
157
- fields: (t) => ({
158
- name: t.exposeString("name"),
159
- description: t.exposeString("description", { nullable: true }),
160
- operations: t.field({
161
- type: [OperationItem],
162
- resolve: (parent, _args, ctx) => {
163
- const rootTags = ctx.tags.map((tag) => tag.name);
164
- return ctx.operations
165
- .filter((item) =>
166
- parent.name
167
- ? item.tags?.includes(parent.name)
168
- : item.tags?.length === 0 ||
169
- // If none of the tags are present in the root tags, then show them here
170
- item.tags?.every((tag) => !rootTags.includes(tag)),
171
- )
172
- .map((item) => ({
173
- ...item,
174
- parentTag: parent.name,
175
- }));
176
- },
184
+ const SchemaTag = builder
185
+ .objectRef<
186
+ Omit<TagObject, "name"> & { name?: string; slug?: string }
187
+ >("SchemaTag")
188
+ .implement({
189
+ fields: (t) => ({
190
+ name: t.exposeString("name", { nullable: true }),
191
+ slug: t.exposeString("slug", { nullable: true }),
192
+ description: t.exposeString("description", { nullable: true }),
193
+ operations: t.field({
194
+ type: [OperationItem],
195
+ resolve: (parent, _args, ctx) => {
196
+ const rootTags = ctx.tags.map((tag) => tag.name);
197
+
198
+ return ctx.operations
199
+ .filter((item) =>
200
+ parent.name
201
+ ? item.tags?.includes(parent.name)
202
+ : item.tags?.length === 0 ||
203
+ // If none of the tags are present in the root tags, then show them here
204
+ item.tags?.every((tag) => !rootTags.includes(tag)),
205
+ )
206
+ .map((item) => ({ ...item, parentTag: parent.name }));
207
+ },
208
+ }),
209
+ extensions: t.field({
210
+ type: JSONObjectScalar,
211
+ resolve: (parent) => resolveExtensions(parent),
212
+ nullable: true,
213
+ }),
177
214
  }),
178
- }),
179
- });
215
+ });
180
216
 
181
217
  const ServerItem = builder.objectRef<ServerObject>("Server").implement({
182
218
  fields: (t) => ({
@@ -341,18 +377,16 @@ const OperationItem = builder
341
377
  slug: t.field({
342
378
  type: "String",
343
379
  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);
380
+ const slug = ctx.slugs.operations[getOperationSlugKey(parent)];
381
+
382
+ if (!slug) {
383
+ throw new Error(
384
+ `No slug found for operation: ${getOperationSlugKey(parent)}`,
385
+ );
386
+ }
387
+ return slug;
353
388
  },
354
389
  }),
355
-
356
390
  path: t.exposeString("path"),
357
391
  method: t.exposeString("method"),
358
392
  operationId: t.exposeString("operationId", { nullable: true }),
@@ -466,10 +500,17 @@ const Schema = builder.objectRef<OpenAPIDocument>("Schema").implement({
466
500
  name: t.arg.string(),
467
501
  },
468
502
  type: [SchemaTag],
469
- resolve: (root, args, ctx) => {
470
- return args.name
471
- ? ctx.tags.filter((tag) => tag.name === args.name)
472
- : ctx.tags;
503
+ resolve: (_root, args, ctx) => {
504
+ if (args.name) {
505
+ return ctx.tags.filter((tag) => tag.name === args.name);
506
+ }
507
+
508
+ // Append empty tag which will be used to display untagged operations
509
+ if (ctx.operations.some((op) => !op.tags?.length)) {
510
+ return [...ctx.tags, { name: undefined, slug: undefined }];
511
+ }
512
+
513
+ return ctx.tags;
473
514
  },
474
515
  }),
475
516
  operations: t.field({
@@ -513,26 +554,25 @@ builder.queryType({
513
554
  input: t.arg({ type: JSONScalar, required: true }),
514
555
  },
515
556
  resolve: async (_, args, ctx) => {
516
- let schema: OpenAPIDocument;
517
-
518
557
  if (args.type === "file" && typeof args.input === "string") {
519
558
  const loadSchema = ctx.schemaImports?.[args.input];
520
559
 
521
560
  if (!loadSchema) {
522
561
  throw new Error(`No schema loader found for path: ${args.input}`);
523
562
  }
524
- const module = await loadSchema();
525
- schema = module.schema;
563
+ const { schema, slugs } = await loadSchema();
564
+ ctx.schema = schema;
565
+ ctx.operations = getAllOperations(schema.paths);
566
+ ctx.slugs = slugs;
567
+ ctx.tags = getAllTags(schema, ctx.slugs.tags);
526
568
  } else {
527
- schema = await validate(args.input as string);
569
+ ctx.schema = await validate(args.input as string);
570
+ ctx.operations = getAllOperations(ctx.schema.paths);
571
+ ctx.slugs = getAllSlugs(ctx.operations);
572
+ ctx.tags = getAllTags(ctx.schema, ctx.slugs.tags);
528
573
  }
529
574
 
530
- ctx.schema = schema;
531
- ctx.operations = getAllOperations(schema.paths);
532
- ctx.slugify = slugifyWithCounter();
533
- ctx.tags = getAllTags(schema);
534
-
535
- return schema;
575
+ return ctx.schema;
536
576
  },
537
577
  }),
538
578
  }),
@@ -542,4 +582,4 @@ export const schema = builder.toSchema();
542
582
 
543
583
  export const createGraphQLServer = (
544
584
  options?: Omit<YogaServerOptions<any, any>, "schema">,
545
- ) => createYoga({ schema, ...options });
585
+ ) => createYoga({ schema, batching: true, ...options });
@@ -1,5 +1,5 @@
1
1
  import { type ResultOf } from "@graphql-typed-document-node/core";
2
- import { useSuspenseQuery } from "@tanstack/react-query";
2
+ import { useQuery, useSuspenseQuery } from "@tanstack/react-query";
3
3
  import { Helmet } from "@zudoku/react-helmet-async";
4
4
  import { ChevronsDownUpIcon, ChevronsUpDownIcon } from "lucide-react";
5
5
  import { useNavigate } from "react-router";
@@ -97,8 +97,16 @@ export const OperationsFragment = graphql(/* GraphQL */ `
97
97
 
98
98
  export type OperationListItemResult = ResultOf<typeof OperationsFragment>;
99
99
 
100
- const AllOperationsQuery = graphql(/* GraphQL */ `
101
- query AllOperations(
100
+ const SchemaWarmupQuery = graphql(/* GraphQL */ `
101
+ query SchemaWarmup($input: JSON!, $type: SchemaType!) {
102
+ schema(input: $input, type: $type) {
103
+ openapi
104
+ }
105
+ }
106
+ `);
107
+
108
+ const OperationsForTagQuery = graphql(/* GraphQL */ `
109
+ query OperationsForTag(
102
110
  $input: JSON!
103
111
  $type: SchemaType!
104
112
  $tag: String
@@ -133,7 +141,7 @@ export const OperationList = ({
133
141
  untagged?: boolean;
134
142
  }) => {
135
143
  const { input, type, versions, version, options } = useOasConfig();
136
- const query = useCreateQuery(AllOperationsQuery, {
144
+ const query = useCreateQuery(OperationsForTagQuery, {
137
145
  input,
138
146
  type,
139
147
  tag,
@@ -151,6 +159,14 @@ export const OperationList = ({
151
159
  const operations = schema.operations;
152
160
  const tagDescription = schema.tags.find((t) => t.name === tag)?.description;
153
161
 
162
+ // This is to warmup (i.e. load the schema in the background) the schema on the client, if the page has been rendered on the server
163
+ const warmupQuery = useCreateQuery(SchemaWarmupQuery, { input, type });
164
+ useQuery({
165
+ ...warmupQuery,
166
+ enabled: typeof window !== "undefined",
167
+ notifyOnChangeProps: [],
168
+ });
169
+
154
170
  // Prefetch for Playground
155
171
  useApiIdentities();
156
172
 
@@ -194,7 +210,7 @@ export const OperationList = ({
194
210
  registerSidebarAnchor
195
211
  className="mb-0"
196
212
  >
197
- {tag}
213
+ {tag ?? "Other endpoints"}
198
214
  {showVersions && (
199
215
  <span className="text-xl text-muted-foreground ml-1.5">
200
216
  {" "}
@@ -269,38 +285,16 @@ export const OperationList = ({
269
285
  <div className="my-4 flex items-center justify-end gap-4">
270
286
  <Endpoint />
271
287
  </div>
272
- {operations.map((fragment) => (
273
- <OperationListItem
274
- serverUrl={selectedServer}
275
- key={fragment.slug}
276
- operationFragment={fragment}
277
- />
278
- ))}
279
- {/* {schema.tags
280
- .filter((tag) => tag.operations.length > 0)
281
- .map((tag) => (
282
- // px, -mx is so that `content-visibility` doesn't cut off overflown heading anchor links '#'
283
- <div key={tag.name} className="px-6 -mx-6 [content-visibility:auto]">
284
- {tag.name && <CategoryHeading>{tag.name}</CategoryHeading>}
285
- {tag.description && (
286
- <Markdown
287
- className={`${ProseClasses} max-w-full prose-img:max-w-prose w-full mt-2 mb-12`}
288
- content={tag.description}
289
- />
290
- )}
291
- <div className="operation mb-12">
292
- <StaggeredRender>
293
- {tag.operations.map((fragment) => (
294
- <OperationListItem
295
- serverUrl={selectedServer ?? schema.url}
296
- key={fragment.slug}
297
- operationFragment={fragment}
298
- />
299
- ))}
300
- </StaggeredRender>
301
- </div>
302
- </div>
303
- ))} */}
288
+ {/* px, -mx is so that `content-visibility` doesn't cut off overflown heading anchor links '#' */}
289
+ <div className="px-6 -mx-6 [content-visibility:auto]">
290
+ {operations.map((fragment) => (
291
+ <OperationListItem
292
+ serverUrl={selectedServer}
293
+ key={fragment.slug}
294
+ operationFragment={fragment}
295
+ />
296
+ ))}
297
+ </div>
304
298
  </div>
305
299
  );
306
300
  };
@@ -63,7 +63,7 @@ export const OperationListItem = ({
63
63
  <SelectOnClick className="max-w-full truncate flex cursor-pointer">
64
64
  {serverUrl && (
65
65
  <div className="text-neutral-400 dark:text-neutral-500 truncate">
66
- {serverUrl}
66
+ {serverUrl.replace(/\/$/, "")}
67
67
  </div>
68
68
  )}
69
69
  <div className="text-neutral-900 dark:text-neutral-200">
@@ -173,9 +173,9 @@ export const Sidecar = ({
173
173
  const showPlayground =
174
174
  isOnScreen &&
175
175
  (operation.extensions["x-explorer-enabled"] === true ||
176
- operation.extensions["x-playground-enabled"] === true ||
176
+ operation.extensions["x-zudoku-playground-enabled"] === true ||
177
177
  (operation.extensions["x-explorer-enabled"] === undefined &&
178
- operation.extensions["x-playground-enabled"] === undefined &&
178
+ operation.extensions["x-zudoku-playground-enabled"] === undefined &&
179
179
  !options?.disablePlayground));
180
180
 
181
181
  return (
@@ -1,3 +1,4 @@
1
+ import { stripIgnoredCharacters } from "graphql";
1
2
  import { useContext } from "react";
2
3
  import type { TypedDocumentString } from "../graphql/graphql.js";
3
4
  import { GraphQLContext } from "./GraphQLContext.js";
@@ -13,6 +14,6 @@ export const useCreateQuery = <TResult, TVariables>(
13
14
 
14
15
  return {
15
16
  queryFn: () => graphQLClient.fetch(query, ...variables),
16
- queryKey: [query, variables[0]],
17
+ queryKey: [stripIgnoredCharacters(query.toString()), variables[0]],
17
18
  } as const;
18
19
  };
@@ -15,24 +15,24 @@ import * as types from "./graphql.js";
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
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
- "\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;
18
+ "\n query SchemaWarmup($input: JSON!, $type: SchemaType!) {\n schema(input: $input, type: $type) {\n openapi\n }\n }\n": typeof types.SchemaWarmupDocument;
19
+ "\n query OperationsForTag(\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.OperationsForTagDocument;
19
20
  "\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
- "\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;
21
- "\n query GetOperations($input: JSON!, $type: SchemaType!, $tag: String) {\n schema(input: $input, type: $type) {\n operations(tag: $tag) {\n slug\n deprecated\n method\n summary\n operationId\n path\n tags {\n name\n }\n }\n untagged: operations(untagged: true) {\n slug\n deprecated\n method\n summary\n operationId\n path\n }\n }\n }\n": typeof types.GetOperationsDocument;
21
+ "\n query GetSidebarOperations($input: JSON!, $type: SchemaType!) {\n schema(input: $input, type: $type) {\n tags {\n slug\n name\n extensions\n operations {\n summary\n slug\n method\n operationId\n path\n }\n }\n }\n }\n": typeof types.GetSidebarOperationsDocument;
22
22
  };
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
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
- "\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
- types.AllOperationsDocument,
28
+ "\n query SchemaWarmup($input: JSON!, $type: SchemaType!) {\n schema(input: $input, type: $type) {\n openapi\n }\n }\n":
29
+ types.SchemaWarmupDocument,
30
+ "\n query OperationsForTag(\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":
31
+ types.OperationsForTagDocument,
30
32
  "\n query getServerQuery($input: JSON!, $type: SchemaType!) {\n schema(input: $input, type: $type) {\n url\n servers {\n url\n }\n }\n }\n":
31
33
  types.GetServerQueryDocument,
32
- "\n query GetCategories($input: JSON!, $type: SchemaType!) {\n schema(input: $input, type: $type) {\n url\n tags {\n name\n }\n }\n }\n":
33
- types.GetCategoriesDocument,
34
- "\n query GetOperations($input: JSON!, $type: SchemaType!, $tag: String) {\n schema(input: $input, type: $type) {\n operations(tag: $tag) {\n slug\n deprecated\n method\n summary\n operationId\n path\n tags {\n name\n }\n }\n untagged: operations(untagged: true) {\n slug\n deprecated\n method\n summary\n operationId\n path\n }\n }\n }\n":
35
- types.GetOperationsDocument,
34
+ "\n query GetSidebarOperations($input: JSON!, $type: SchemaType!) {\n schema(input: $input, type: $type) {\n tags {\n slug\n name\n extensions\n operations {\n summary\n slug\n method\n operationId\n path\n }\n }\n }\n }\n":
35
+ types.GetSidebarOperationsDocument,
36
36
  };
37
37
 
38
38
  /**
@@ -51,26 +51,26 @@ export function graphql(
51
51
  * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
52
52
  */
53
53
  export function graphql(
54
- source: "\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",
55
- ): typeof import("./graphql.js").AllOperationsDocument;
54
+ source: "\n query SchemaWarmup($input: JSON!, $type: SchemaType!) {\n schema(input: $input, type: $type) {\n openapi\n }\n }\n",
55
+ ): typeof import("./graphql.js").SchemaWarmupDocument;
56
56
  /**
57
57
  * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
58
58
  */
59
59
  export function graphql(
60
- source: "\n query getServerQuery($input: JSON!, $type: SchemaType!) {\n schema(input: $input, type: $type) {\n url\n servers {\n url\n }\n }\n }\n",
61
- ): typeof import("./graphql.js").GetServerQueryDocument;
60
+ source: "\n query OperationsForTag(\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",
61
+ ): typeof import("./graphql.js").OperationsForTagDocument;
62
62
  /**
63
63
  * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
64
64
  */
65
65
  export function graphql(
66
- source: "\n query GetCategories($input: JSON!, $type: SchemaType!) {\n schema(input: $input, type: $type) {\n url\n tags {\n name\n }\n }\n }\n",
67
- ): typeof import("./graphql.js").GetCategoriesDocument;
66
+ source: "\n query getServerQuery($input: JSON!, $type: SchemaType!) {\n schema(input: $input, type: $type) {\n url\n servers {\n url\n }\n }\n }\n",
67
+ ): typeof import("./graphql.js").GetServerQueryDocument;
68
68
  /**
69
69
  * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
70
70
  */
71
71
  export function graphql(
72
- source: "\n query GetOperations($input: JSON!, $type: SchemaType!, $tag: String) {\n schema(input: $input, type: $type) {\n operations(tag: $tag) {\n slug\n deprecated\n method\n summary\n operationId\n path\n tags {\n name\n }\n }\n untagged: operations(untagged: true) {\n slug\n deprecated\n method\n summary\n operationId\n path\n }\n }\n }\n",
73
- ): typeof import("./graphql.js").GetOperationsDocument;
72
+ source: "\n query GetSidebarOperations($input: JSON!, $type: SchemaType!) {\n schema(input: $input, type: $type) {\n tags {\n slug\n name\n extensions\n operations {\n summary\n slug\n method\n operationId\n path\n }\n }\n }\n }\n",
73
+ ): typeof import("./graphql.js").GetSidebarOperationsDocument;
74
74
 
75
75
  export function graphql(source: string) {
76
76
  return (documents as any)[source] ?? {};