zudoku 0.1.1-dev.10 → 0.1.1-dev.12
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.
- package/dist/app/DevPortal.js +2 -15
- package/dist/app/DevPortal.js.map +1 -1
- package/dist/app/Router.d.ts +4 -0
- package/dist/app/Router.js +20 -0
- package/dist/app/Router.js.map +1 -0
- package/dist/vite/config.d.ts +2 -2
- package/dist/vite/config.js +13 -8
- package/dist/vite/config.js.map +1 -1
- package/dist/vite/plugin-api.js +1 -1
- package/dist/vite/plugin-api.js.map +1 -1
- package/dist/vite/plugin-auth.js +1 -1
- package/dist/vite/plugin-docs.js +1 -1
- package/dist/vite/plugin-docs.js.map +1 -1
- package/package.json +2 -2
- package/src/app/App.tsx +0 -30
- package/src/app/DevPortal.tsx +0 -115
- package/src/app/Heading.tsx +0 -60
- package/src/app/authentication/authentication.ts +0 -18
- package/src/app/authentication/clerk.ts +0 -47
- package/src/app/authentication/openid.ts +0 -192
- package/src/app/components/AnchorLink.tsx +0 -19
- package/src/app/components/CategoryHeading.tsx +0 -16
- package/src/app/components/Dialog.tsx +0 -119
- package/src/app/components/DynamicIcon.tsx +0 -60
- package/src/app/components/Header.tsx +0 -69
- package/src/app/components/Input.tsx +0 -24
- package/src/app/components/Layout.tsx +0 -56
- package/src/app/components/Markdown.tsx +0 -37
- package/src/app/components/SyntaxHighlight.tsx +0 -94
- package/src/app/components/TopNavigation.tsx +0 -32
- package/src/app/components/context/ComponentsContext.tsx +0 -24
- package/src/app/components/context/DevPortalProvider.ts +0 -54
- package/src/app/components/context/PluginSystem.ts +0 -0
- package/src/app/components/context/ThemeContext.tsx +0 -46
- package/src/app/components/context/ViewportAnchorContext.tsx +0 -139
- package/src/app/components/navigation/SideNavigation.tsx +0 -18
- package/src/app/components/navigation/SideNavigationCategory.tsx +0 -74
- package/src/app/components/navigation/SideNavigationItem.tsx +0 -143
- package/src/app/components/navigation/SideNavigationWrapper.tsx +0 -15
- package/src/app/components/navigation/useNavigationCollapsibleState.ts +0 -27
- package/src/app/components/navigation/util.ts +0 -38
- package/src/app/core/DevPortalContext.ts +0 -164
- package/src/app/core/helmet.ts +0 -5
- package/src/app/core/icons.tsx +0 -1
- package/src/app/core/plugins.ts +0 -43
- package/src/app/core/router.tsx +0 -1
- package/src/app/core/types/combine.ts +0 -16
- package/src/app/main.css +0 -137
- package/src/app/main.tsx +0 -9
- package/src/app/oas/graphql/index.ts +0 -422
- package/src/app/oas/graphql/server.ts +0 -10
- package/src/app/oas/parser/dereference/index.ts +0 -59
- package/src/app/oas/parser/dereference/resolveRef.ts +0 -32
- package/src/app/oas/parser/index.ts +0 -94
- package/src/app/oas/parser/schemas/v3.0.json +0 -1489
- package/src/app/oas/parser/schemas/v3.1.json +0 -1298
- package/src/app/oas/parser/upgrade/index.ts +0 -108
- package/src/app/plugins/api-key/SettingsApiKeys.tsx +0 -22
- package/src/app/plugins/api-key/index.tsx +0 -123
- package/src/app/plugins/markdown/MdxPage.tsx +0 -128
- package/src/app/plugins/markdown/Toc.tsx +0 -122
- package/src/app/plugins/markdown/generateRoutes.tsx +0 -72
- package/src/app/plugins/markdown/index.tsx +0 -31
- package/src/app/plugins/openapi/ColorizedParam.tsx +0 -82
- package/src/app/plugins/openapi/MakeRequest.tsx +0 -49
- package/src/app/plugins/openapi/MethodBadge.tsx +0 -36
- package/src/app/plugins/openapi/OperationList.tsx +0 -117
- package/src/app/plugins/openapi/OperationListItem.tsx +0 -55
- package/src/app/plugins/openapi/ParameterList.tsx +0 -32
- package/src/app/plugins/openapi/ParameterListItem.tsx +0 -60
- package/src/app/plugins/openapi/RequestBodySidecarBox.tsx +0 -51
- package/src/app/plugins/openapi/ResponsesSidecarBox.tsx +0 -60
- package/src/app/plugins/openapi/Select.tsx +0 -35
- package/src/app/plugins/openapi/Sidecar.tsx +0 -160
- package/src/app/plugins/openapi/SidecarBox.tsx +0 -36
- package/src/app/plugins/openapi/graphql/fragment-masking.ts +0 -111
- package/src/app/plugins/openapi/graphql/gql.ts +0 -70
- package/src/app/plugins/openapi/graphql/graphql.ts +0 -795
- package/src/app/plugins/openapi/graphql/index.ts +0 -2
- package/src/app/plugins/openapi/index.tsx +0 -142
- package/src/app/plugins/openapi/playground/Playground.tsx +0 -309
- package/src/app/plugins/openapi/queries.graphql +0 -6
- package/src/app/plugins/openapi/util/generateSchemaExample.ts +0 -59
- package/src/app/plugins/openapi/util/urql.ts +0 -8
- package/src/app/plugins/openapi/worker/createSharedWorkerClient.ts +0 -60
- package/src/app/plugins/openapi/worker/worker.ts +0 -30
- package/src/app/plugins/redirect/index.tsx +0 -20
- package/src/app/tailwind.ts +0 -72
- package/src/app/ui/Button.tsx +0 -56
- package/src/app/ui/Callout.tsx +0 -87
- package/src/app/ui/Card.tsx +0 -82
- package/src/app/ui/Note.tsx +0 -58
- package/src/app/ui/Tabs.tsx +0 -52
- package/src/app/util/MdxComponents.tsx +0 -70
- package/src/app/util/cn.ts +0 -6
- package/src/app/util/createVariantComponent.tsx +0 -30
- package/src/app/util/createWaitForNotify.ts +0 -18
- package/src/app/util/groupBy.ts +0 -24
- package/src/app/util/joinPath.tsx +0 -10
- package/src/app/util/pastellize.ts +0 -25
- package/src/app/util/slugify.ts +0 -3
- package/src/app/util/traverseNavigation.ts +0 -55
- package/src/app/util/useScrollToAnchor.ts +0 -38
- package/src/app/util/useScrollToTop.ts +0 -13
|
@@ -1,422 +0,0 @@
|
|
|
1
|
-
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
-
import SchemaBuilder from "@pothos/core";
|
|
3
|
-
import { GraphQLJSON, GraphQLJSONObject } from "graphql-type-json";
|
|
4
|
-
import { createYoga, type YogaServerOptions } from "graphql-yoga";
|
|
5
|
-
import { LRUCache } from "lru-cache";
|
|
6
|
-
import hashit from "object-hash";
|
|
7
|
-
import slugify from "../../util/slugify.js";
|
|
8
|
-
import {
|
|
9
|
-
HttpMethods,
|
|
10
|
-
validate,
|
|
11
|
-
type EncodingObject,
|
|
12
|
-
type ExampleObject,
|
|
13
|
-
type OpenAPIDocument,
|
|
14
|
-
type OperationObject,
|
|
15
|
-
type ParameterObject,
|
|
16
|
-
type PathsObject,
|
|
17
|
-
type SchemaObject,
|
|
18
|
-
type TagObject,
|
|
19
|
-
} from "../parser/index.js";
|
|
20
|
-
|
|
21
|
-
export type {
|
|
22
|
-
EncodingObject,
|
|
23
|
-
ExampleObject,
|
|
24
|
-
OpenAPIDocument,
|
|
25
|
-
OperationObject,
|
|
26
|
-
ParameterObject,
|
|
27
|
-
PathsObject,
|
|
28
|
-
SchemaObject,
|
|
29
|
-
TagObject,
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
type OperationLike = {
|
|
33
|
-
summary?: string | null;
|
|
34
|
-
operationId?: string | null;
|
|
35
|
-
path: string;
|
|
36
|
-
method: string;
|
|
37
|
-
};
|
|
38
|
-
export const slugifyOperation = (operation: OperationLike, tag?: string) => {
|
|
39
|
-
return slugify(
|
|
40
|
-
(tag ? tag + "-" : "") +
|
|
41
|
-
(operation.summary ??
|
|
42
|
-
operation.operationId ??
|
|
43
|
-
`${operation.method}-${operation.path}`),
|
|
44
|
-
{ lower: true, trim: true },
|
|
45
|
-
);
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
const cache = new LRUCache<string, OpenAPIDocument>({
|
|
49
|
-
ttl: 60 * 10 * 1000,
|
|
50
|
-
ttlAutopurge: true,
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
const builder = new SchemaBuilder<{
|
|
54
|
-
Scalars: {
|
|
55
|
-
JSON: any;
|
|
56
|
-
JSONObject: any;
|
|
57
|
-
};
|
|
58
|
-
Context: {
|
|
59
|
-
schema: OpenAPIDocument;
|
|
60
|
-
};
|
|
61
|
-
}>({});
|
|
62
|
-
|
|
63
|
-
const JSONScalar = builder.addScalarType("JSON", GraphQLJSON);
|
|
64
|
-
const JSONObjectScalar = builder.addScalarType("JSONObject", GraphQLJSONObject);
|
|
65
|
-
|
|
66
|
-
const getAllOperations = (paths?: PathsObject, tag?: string) => {
|
|
67
|
-
return Object.entries(paths ?? {}).flatMap(([path, value]) =>
|
|
68
|
-
HttpMethods.flatMap((method) => {
|
|
69
|
-
if (!value?.[method]) return [];
|
|
70
|
-
|
|
71
|
-
const operation = value[method] as OperationObject;
|
|
72
|
-
const pathParameters = value?.parameters ?? [];
|
|
73
|
-
const operationParameters = operation.parameters ?? [];
|
|
74
|
-
|
|
75
|
-
// parameters are inherited from the parent path object,
|
|
76
|
-
// but can be overridden by their `name` and `in` location
|
|
77
|
-
const parameters = [
|
|
78
|
-
...pathParameters.filter(
|
|
79
|
-
// remove path parameters that are already defined in the operation
|
|
80
|
-
(pp) =>
|
|
81
|
-
!operationParameters.some(
|
|
82
|
-
(op) => op.name === pp.name && op.in === pp.in,
|
|
83
|
-
),
|
|
84
|
-
),
|
|
85
|
-
...operationParameters,
|
|
86
|
-
];
|
|
87
|
-
|
|
88
|
-
return {
|
|
89
|
-
...operation,
|
|
90
|
-
method,
|
|
91
|
-
path,
|
|
92
|
-
parameters,
|
|
93
|
-
slug: slugifyOperation(
|
|
94
|
-
{
|
|
95
|
-
summary: operation.summary,
|
|
96
|
-
operationId: operation.operationId,
|
|
97
|
-
path,
|
|
98
|
-
method,
|
|
99
|
-
},
|
|
100
|
-
tag,
|
|
101
|
-
),
|
|
102
|
-
};
|
|
103
|
-
}),
|
|
104
|
-
);
|
|
105
|
-
};
|
|
106
|
-
|
|
107
|
-
const SchemaTag = builder.objectRef<TagObject>("SchemaTag").implement({
|
|
108
|
-
fields: (t) => ({
|
|
109
|
-
name: t.exposeString("name", { nullable: true }),
|
|
110
|
-
description: t.exposeString("description", { nullable: true }),
|
|
111
|
-
operations: t.field({
|
|
112
|
-
type: [OperationItem],
|
|
113
|
-
resolve: (parent, _args, ctx) =>
|
|
114
|
-
getAllOperations(ctx.schema.paths, parent.name).filter((item) =>
|
|
115
|
-
parent.name
|
|
116
|
-
? item.tags?.includes(parent.name)
|
|
117
|
-
: !item.tags || item.tags.length === 0,
|
|
118
|
-
),
|
|
119
|
-
}),
|
|
120
|
-
}),
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
const PathItem = builder
|
|
124
|
-
.objectRef<{
|
|
125
|
-
path: string;
|
|
126
|
-
methods: typeof HttpMethods;
|
|
127
|
-
}>("PathItem")
|
|
128
|
-
.implement({
|
|
129
|
-
fields: (t) => ({
|
|
130
|
-
path: t.exposeString("path"),
|
|
131
|
-
methods: t.exposeStringList("methods"),
|
|
132
|
-
}),
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
const TagItem = builder.objectRef<TagObject>("TagItem").implement({
|
|
136
|
-
fields: (t) => ({
|
|
137
|
-
name: t.exposeString("name"),
|
|
138
|
-
description: t.exposeString("description", { nullable: true }),
|
|
139
|
-
}),
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
const EncodingItem = builder
|
|
143
|
-
.objectRef<EncodingObject & { name: string }>("EncodingItem")
|
|
144
|
-
.implement({
|
|
145
|
-
fields: (t) => ({
|
|
146
|
-
name: t.exposeString("name"),
|
|
147
|
-
contentType: t.exposeString("contentType", { nullable: true }),
|
|
148
|
-
headers: t.expose("headers", { type: JSONObjectScalar, nullable: true }),
|
|
149
|
-
style: t.exposeString("style", { nullable: true }),
|
|
150
|
-
explode: t.exposeBoolean("explode", { nullable: true }),
|
|
151
|
-
allowReserved: t.exposeBoolean("allowReserved", { nullable: true }),
|
|
152
|
-
}),
|
|
153
|
-
});
|
|
154
|
-
|
|
155
|
-
const ExampleItem = builder
|
|
156
|
-
.objectRef<ExampleObject & { name: string }>("ExampleItem")
|
|
157
|
-
.implement({
|
|
158
|
-
fields: (t) => ({
|
|
159
|
-
name: t.exposeString("name"),
|
|
160
|
-
summary: t.exposeString("summary", { nullable: true }),
|
|
161
|
-
description: t.exposeString("description", { nullable: true }),
|
|
162
|
-
value: t.exposeString("value", { nullable: true }),
|
|
163
|
-
externalValue: t.exposeString("externalValue", { nullable: true }),
|
|
164
|
-
}),
|
|
165
|
-
});
|
|
166
|
-
|
|
167
|
-
const ParameterIn = builder.enumType("ParameterIn", {
|
|
168
|
-
values: ["query", "header", "path", "cookie"] as const,
|
|
169
|
-
});
|
|
170
|
-
|
|
171
|
-
const ParameterItem = builder
|
|
172
|
-
.objectRef<ParameterObject>("ParameterItem")
|
|
173
|
-
.implement({
|
|
174
|
-
fields: (t) => ({
|
|
175
|
-
name: t.exposeString("name"),
|
|
176
|
-
in: t.field({
|
|
177
|
-
type: ParameterIn,
|
|
178
|
-
resolve: (parent) => parent.in as typeof ParameterIn.$inferType,
|
|
179
|
-
}),
|
|
180
|
-
description: t.exposeString("description", { nullable: true }),
|
|
181
|
-
required: t.exposeBoolean("required", { nullable: true }),
|
|
182
|
-
deprecated: t.exposeBoolean("deprecated", { nullable: true }),
|
|
183
|
-
allowEmptyValue: t.exposeBoolean("allowEmptyValue", { nullable: true }),
|
|
184
|
-
style: t.exposeString("style", { nullable: true }),
|
|
185
|
-
explode: t.exposeBoolean("explode", { nullable: true }),
|
|
186
|
-
allowReserved: t.exposeBoolean("allowReserved", { nullable: true }),
|
|
187
|
-
examples: t.field({
|
|
188
|
-
type: [ExampleItem],
|
|
189
|
-
resolve: (parent) =>
|
|
190
|
-
Object.entries(parent.examples ?? {}).map(([name, value]) => ({
|
|
191
|
-
name,
|
|
192
|
-
...value,
|
|
193
|
-
})),
|
|
194
|
-
nullable: true,
|
|
195
|
-
}),
|
|
196
|
-
schema: t.expose("schema", { type: JSONScalar, nullable: true }),
|
|
197
|
-
}),
|
|
198
|
-
});
|
|
199
|
-
|
|
200
|
-
const MediaTypeItem = builder
|
|
201
|
-
.objectRef<{
|
|
202
|
-
mediaType: string;
|
|
203
|
-
schema: any;
|
|
204
|
-
examples: Array<ExampleObject & { name: string }>;
|
|
205
|
-
encoding?: Array<EncodingObject & { name: string }>;
|
|
206
|
-
}>("MediaTypeObject")
|
|
207
|
-
.implement({
|
|
208
|
-
fields: (t) => ({
|
|
209
|
-
mediaType: t.exposeString("mediaType"),
|
|
210
|
-
schema: t.expose("schema", { type: JSONScalar }),
|
|
211
|
-
examples: t.expose("examples", { type: [ExampleItem], nullable: true }),
|
|
212
|
-
encoding: t.expose("encoding", { type: [EncodingItem], nullable: true }),
|
|
213
|
-
}),
|
|
214
|
-
});
|
|
215
|
-
|
|
216
|
-
const RequestBodyObject = builder
|
|
217
|
-
.objectRef<{
|
|
218
|
-
description?: string;
|
|
219
|
-
required?: boolean;
|
|
220
|
-
content: Array<{
|
|
221
|
-
mediaType: string;
|
|
222
|
-
schema: any;
|
|
223
|
-
examples: Array<ExampleObject & { name: string }>;
|
|
224
|
-
encoding?: Array<EncodingObject & { name: string }>;
|
|
225
|
-
}>;
|
|
226
|
-
}>("RequestBodyObject")
|
|
227
|
-
.implement({
|
|
228
|
-
fields: (t) => ({
|
|
229
|
-
description: t.exposeString("description", { nullable: true }),
|
|
230
|
-
content: t.expose("content", { type: [MediaTypeItem], nullable: true }),
|
|
231
|
-
required: t.exposeBoolean("required", { nullable: true }),
|
|
232
|
-
}),
|
|
233
|
-
});
|
|
234
|
-
|
|
235
|
-
const ResponseItem = builder
|
|
236
|
-
.objectRef<{
|
|
237
|
-
statusCode: string;
|
|
238
|
-
description: string;
|
|
239
|
-
content: Array<{
|
|
240
|
-
mediaType: string;
|
|
241
|
-
schema: any;
|
|
242
|
-
examples: Array<ExampleObject & { name: string }>;
|
|
243
|
-
}>;
|
|
244
|
-
headers?: any;
|
|
245
|
-
links?: any;
|
|
246
|
-
}>("ResponseItem")
|
|
247
|
-
.implement({
|
|
248
|
-
fields: (t) => ({
|
|
249
|
-
statusCode: t.exposeString("statusCode"),
|
|
250
|
-
description: t.exposeString("description"),
|
|
251
|
-
content: t.expose("content", { type: [MediaTypeItem], nullable: true }),
|
|
252
|
-
headers: t.expose("headers", { type: JSONScalar, nullable: true }),
|
|
253
|
-
links: t.expose("links", { type: JSONScalar, nullable: true }),
|
|
254
|
-
}),
|
|
255
|
-
});
|
|
256
|
-
|
|
257
|
-
const OperationItem = builder
|
|
258
|
-
.objectRef<
|
|
259
|
-
OperationObject & { path: string; method: string; slug: string }
|
|
260
|
-
>("OperationItem")
|
|
261
|
-
.implement({
|
|
262
|
-
fields: (t) => ({
|
|
263
|
-
slug: t.exposeString("slug"),
|
|
264
|
-
path: t.exposeString("path"),
|
|
265
|
-
method: t.exposeString("method"),
|
|
266
|
-
operationId: t.exposeString("operationId", { nullable: true }),
|
|
267
|
-
summary: t.exposeString("summary", { nullable: true }),
|
|
268
|
-
description: t.exposeString("description", { nullable: true }),
|
|
269
|
-
contentTypes: t.stringList({
|
|
270
|
-
resolve: (parent) => Object.keys(parent.requestBody?.content ?? {}),
|
|
271
|
-
}),
|
|
272
|
-
parameters: t.expose("parameters", {
|
|
273
|
-
type: [ParameterItem],
|
|
274
|
-
nullable: true,
|
|
275
|
-
}),
|
|
276
|
-
requestBody: t.field({
|
|
277
|
-
type: RequestBodyObject,
|
|
278
|
-
resolve: (parent) => ({
|
|
279
|
-
description: parent.requestBody?.description,
|
|
280
|
-
required: parent.requestBody?.required,
|
|
281
|
-
content: Object.entries(parent.requestBody?.content ?? {}).map(
|
|
282
|
-
([mediaType, content]) => ({
|
|
283
|
-
mediaType,
|
|
284
|
-
schema: content.schema,
|
|
285
|
-
examples: Object.entries(content.examples ?? {}).map(
|
|
286
|
-
([name, value]) => ({ name, ...value }),
|
|
287
|
-
),
|
|
288
|
-
encoding: Object.entries(content.encoding ?? {}).map(
|
|
289
|
-
([name, value]) => ({ name, ...value }),
|
|
290
|
-
),
|
|
291
|
-
}),
|
|
292
|
-
),
|
|
293
|
-
}),
|
|
294
|
-
nullable: true,
|
|
295
|
-
}),
|
|
296
|
-
responses: t.field({
|
|
297
|
-
type: [ResponseItem],
|
|
298
|
-
resolve: (parent) => {
|
|
299
|
-
return Object.entries(parent.responses ?? {}).map(
|
|
300
|
-
([statusCode, response]) => ({
|
|
301
|
-
statusCode,
|
|
302
|
-
description: response.description,
|
|
303
|
-
content: Object.entries(response.content ?? {}).map(
|
|
304
|
-
([mediaType, mediaTypeObject]) => ({
|
|
305
|
-
mediaType,
|
|
306
|
-
schema: mediaTypeObject.schema,
|
|
307
|
-
examples: Object.entries(mediaTypeObject.examples ?? {}).map(
|
|
308
|
-
([name, value]) => ({ name, ...value }),
|
|
309
|
-
),
|
|
310
|
-
}),
|
|
311
|
-
),
|
|
312
|
-
headers: response.headers,
|
|
313
|
-
links: response.links,
|
|
314
|
-
}),
|
|
315
|
-
);
|
|
316
|
-
},
|
|
317
|
-
}),
|
|
318
|
-
tags: t.field({
|
|
319
|
-
type: [TagItem],
|
|
320
|
-
resolve: (parent, _, ctx) =>
|
|
321
|
-
parent.tags?.map((tag) => ({
|
|
322
|
-
name: tag,
|
|
323
|
-
description: ctx.schema.tags?.find((t) => t.name === tag)
|
|
324
|
-
?.description,
|
|
325
|
-
})),
|
|
326
|
-
nullable: true,
|
|
327
|
-
}),
|
|
328
|
-
deprecated: t.exposeBoolean("deprecated", { nullable: true }),
|
|
329
|
-
}),
|
|
330
|
-
});
|
|
331
|
-
|
|
332
|
-
const Schema = builder.objectRef<OpenAPIDocument>("Schema").implement({
|
|
333
|
-
fields: (t) => ({
|
|
334
|
-
openapi: t.string({ resolve: (root) => root.openapi }),
|
|
335
|
-
url: t.string({ resolve: (root) => root.servers?.at(0)?.url ?? "/" }),
|
|
336
|
-
title: t.string({ resolve: (root) => root.info.title }),
|
|
337
|
-
version: t.string({ resolve: (root) => root.info.version }),
|
|
338
|
-
description: t.string({
|
|
339
|
-
resolve: (root) => root.info.description,
|
|
340
|
-
nullable: true,
|
|
341
|
-
}),
|
|
342
|
-
paths: t.field({
|
|
343
|
-
type: [PathItem],
|
|
344
|
-
resolve: (root) =>
|
|
345
|
-
Object.entries(root.paths ?? {}).map(([path, value]) => ({
|
|
346
|
-
path,
|
|
347
|
-
methods: Object.keys(value!) as typeof HttpMethods,
|
|
348
|
-
})),
|
|
349
|
-
}),
|
|
350
|
-
tags: t.field({
|
|
351
|
-
args: {
|
|
352
|
-
name: t.arg.string(),
|
|
353
|
-
},
|
|
354
|
-
type: [SchemaTag],
|
|
355
|
-
resolve: (root, args) =>
|
|
356
|
-
[...(root.tags ?? []), { name: "" }].filter(
|
|
357
|
-
(tag) => !args.name || args.name === tag.name,
|
|
358
|
-
),
|
|
359
|
-
}),
|
|
360
|
-
operations: t.field({
|
|
361
|
-
type: [OperationItem],
|
|
362
|
-
args: {
|
|
363
|
-
path: t.arg.string(),
|
|
364
|
-
method: t.arg.string(),
|
|
365
|
-
operationId: t.arg.string(),
|
|
366
|
-
tag: t.arg.string(),
|
|
367
|
-
},
|
|
368
|
-
resolve: (parent, args) =>
|
|
369
|
-
getAllOperations(parent.paths).filter(
|
|
370
|
-
(item) =>
|
|
371
|
-
(!args.operationId || item.operationId === args.operationId) &&
|
|
372
|
-
(!args.path || item.path === args.path) &&
|
|
373
|
-
(!args.method || item.method === args.method) &&
|
|
374
|
-
(!args.tag || item.tags?.includes(args.tag)),
|
|
375
|
-
),
|
|
376
|
-
}),
|
|
377
|
-
}),
|
|
378
|
-
});
|
|
379
|
-
|
|
380
|
-
const loadOpenAPISchema = async (input: NonNullable<unknown>) => {
|
|
381
|
-
const hash = hashit(input);
|
|
382
|
-
|
|
383
|
-
if (cache.has(hash)) {
|
|
384
|
-
return cache.get(hash)!;
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
const schema = await validate(input);
|
|
388
|
-
|
|
389
|
-
cache.set(hash, schema);
|
|
390
|
-
|
|
391
|
-
return schema;
|
|
392
|
-
};
|
|
393
|
-
|
|
394
|
-
const SchemaSource = builder.enumType("SchemaType", {
|
|
395
|
-
values: ["url", "json", "yaml"] as const,
|
|
396
|
-
});
|
|
397
|
-
|
|
398
|
-
builder.queryType({
|
|
399
|
-
fields: (t) => ({
|
|
400
|
-
// https://tan-cow-main-bce8a06.d2.zuplo.dev/openapi
|
|
401
|
-
schema: t.field({
|
|
402
|
-
type: Schema,
|
|
403
|
-
args: {
|
|
404
|
-
type: t.arg({ type: SchemaSource, required: true }),
|
|
405
|
-
input: t.arg({ type: JSONScalar, required: true }),
|
|
406
|
-
},
|
|
407
|
-
resolve: async (_, args, ctx) => {
|
|
408
|
-
const schema = await loadOpenAPISchema(args.input!);
|
|
409
|
-
// for easier access of the whole schema in children resolvers
|
|
410
|
-
ctx.schema = schema;
|
|
411
|
-
|
|
412
|
-
return schema;
|
|
413
|
-
},
|
|
414
|
-
}),
|
|
415
|
-
}),
|
|
416
|
-
});
|
|
417
|
-
|
|
418
|
-
export const schema = builder.toSchema();
|
|
419
|
-
|
|
420
|
-
export const createGraphQLServer = (
|
|
421
|
-
options?: Omit<YogaServerOptions<any, any>, "schema">,
|
|
422
|
-
) => createYoga({ schema, ...options });
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { createServer } from "node:http";
|
|
2
|
-
import { createGraphQLServer } from "./index.js";
|
|
3
|
-
|
|
4
|
-
const yoga = createGraphQLServer();
|
|
5
|
-
|
|
6
|
-
const server = createServer(yoga);
|
|
7
|
-
|
|
8
|
-
server.listen(4000, () => {
|
|
9
|
-
console.log(`🚀 Server ready at http://localhost:4000/graphql`);
|
|
10
|
-
});
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import type { JSONSchema4, JSONSchema6 } from "json-schema";
|
|
2
|
-
import { resolveLocalRef } from "./resolveRef.js";
|
|
3
|
-
|
|
4
|
-
export type JSONSchema = JSONSchema4 | JSONSchema6;
|
|
5
|
-
|
|
6
|
-
type CustomResolver = (ref: string) => Promise<JSONSchema | undefined>;
|
|
7
|
-
|
|
8
|
-
const cache = new Map<JSONSchema, JSONSchema>();
|
|
9
|
-
|
|
10
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
11
|
-
const isIndexableObject = (obj: any): obj is Record<string, any> =>
|
|
12
|
-
obj !== null && typeof obj === "object";
|
|
13
|
-
|
|
14
|
-
// Taken and inspired from `dereference-json-schema` package.
|
|
15
|
-
export const dereference = async (
|
|
16
|
-
schema: JSONSchema,
|
|
17
|
-
resolvers: CustomResolver[] = [],
|
|
18
|
-
) => {
|
|
19
|
-
if (cache.has(schema)) {
|
|
20
|
-
return cache.get(schema)!;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
const cloned = structuredClone(schema);
|
|
24
|
-
const visited = new Set();
|
|
25
|
-
|
|
26
|
-
const resolve = async (current: unknown, path: string) => {
|
|
27
|
-
if (isIndexableObject(current)) {
|
|
28
|
-
if (visited.has(current)) {
|
|
29
|
-
return current;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
visited.add(current);
|
|
33
|
-
|
|
34
|
-
if (Array.isArray(current)) {
|
|
35
|
-
for (let index = 0; index < current.length; index++) {
|
|
36
|
-
current[index] = await resolve(current[index], `${path}/${index}`);
|
|
37
|
-
}
|
|
38
|
-
} else {
|
|
39
|
-
if ("$ref" in current && typeof current.$ref === "string") {
|
|
40
|
-
for (const resolver of resolvers) {
|
|
41
|
-
const resolved = await resolver(current.$ref);
|
|
42
|
-
if (resolved) return resolved;
|
|
43
|
-
}
|
|
44
|
-
return await resolveLocalRef(cloned, current.$ref);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
for (const key in current) {
|
|
48
|
-
current[key] = await resolve(current[key], `${path}/${key}`);
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
return current;
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
const result = (await resolve(cloned, "#")) as JSONSchema;
|
|
57
|
-
cache.set(schema, result);
|
|
58
|
-
return result;
|
|
59
|
-
};
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import type { JSONSchema } from "./index.js";
|
|
2
|
-
|
|
3
|
-
const cache = new Map<JSONSchema, Map<string, unknown>>();
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Resolves a $ref pointer in a schema and returns the referenced value.
|
|
7
|
-
*/
|
|
8
|
-
export const resolveLocalRef = (schema: JSONSchema, ref: string): unknown => {
|
|
9
|
-
if (!cache.has(schema)) {
|
|
10
|
-
cache.set(schema, new Map<string, unknown>());
|
|
11
|
-
}
|
|
12
|
-
const schemaCache = cache.get(schema);
|
|
13
|
-
|
|
14
|
-
if (schemaCache!.has(ref)) {
|
|
15
|
-
return schemaCache!.get(ref);
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
const path = ref.split("/").slice(1);
|
|
19
|
-
|
|
20
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
21
|
-
let current: any = schema;
|
|
22
|
-
for (const segment of path) {
|
|
23
|
-
if (!current || typeof current !== "object") {
|
|
24
|
-
// we've reached a dead end
|
|
25
|
-
current = null;
|
|
26
|
-
}
|
|
27
|
-
current = current[segment] ?? null;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
schemaCache!.set(ref, current);
|
|
31
|
-
return current;
|
|
32
|
-
};
|
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
import { OpenAPIV3, type OpenAPIV3_1 } from "openapi-types";
|
|
2
|
-
import { dereference, type JSONSchema } from "./dereference/index.js";
|
|
3
|
-
import { upgradeSchema } from "./upgrade/index.js";
|
|
4
|
-
|
|
5
|
-
type ReferenceObject = OpenAPIV3_1.ReferenceObject;
|
|
6
|
-
type DeepOmitReference<T> = T extends ReferenceObject
|
|
7
|
-
? never
|
|
8
|
-
: T extends object
|
|
9
|
-
? { [K in keyof T]: DeepOmitReference<T[K]> }
|
|
10
|
-
: T;
|
|
11
|
-
|
|
12
|
-
// type Prettify<T> = {
|
|
13
|
-
// [K in keyof T]: T[K];
|
|
14
|
-
// } & {};
|
|
15
|
-
|
|
16
|
-
export type OpenAPIDocument = DeepOmitReference<OpenAPIV3_1.Document>;
|
|
17
|
-
export type ResponseObject = DeepOmitReference<OpenAPIV3_1.ResponseObject>;
|
|
18
|
-
export type OperationObject = DeepOmitReference<OpenAPIV3_1.OperationObject>;
|
|
19
|
-
export type PathsObject = DeepOmitReference<OpenAPIV3_1.PathsObject>;
|
|
20
|
-
export type PathItemObject = DeepOmitReference<OpenAPIV3_1.PathItemObject>;
|
|
21
|
-
export type ParameterObject = DeepOmitReference<OpenAPIV3_1.ParameterObject>;
|
|
22
|
-
export type TagObject = DeepOmitReference<OpenAPIV3_1.TagObject>;
|
|
23
|
-
export type ExampleObject = DeepOmitReference<OpenAPIV3_1.ExampleObject>;
|
|
24
|
-
export type EncodingObject = DeepOmitReference<OpenAPIV3_1.EncodingObject>;
|
|
25
|
-
export type SchemaObject = DeepOmitReference<OpenAPIV3_1.SchemaObject>;
|
|
26
|
-
|
|
27
|
-
export const HttpMethods = Object.values(OpenAPIV3.HttpMethods);
|
|
28
|
-
|
|
29
|
-
// class ValidationError extends Error {
|
|
30
|
-
// constructor(public errors: OutputUnit[]) {
|
|
31
|
-
// super("Validation error");
|
|
32
|
-
// }
|
|
33
|
-
// }
|
|
34
|
-
|
|
35
|
-
// const getValidator = async (openApiVersion: string) => {
|
|
36
|
-
// if (openApiVersion.startsWith("3.0")) {
|
|
37
|
-
// const schema = (await import("./schemas/v3.0.json")) as any;
|
|
38
|
-
// return new Validator(schema, "4");
|
|
39
|
-
// }
|
|
40
|
-
// if (openApiVersion.startsWith("3.1")) {
|
|
41
|
-
// const schema = (await import("./schemas/v3.1.json")) as any;
|
|
42
|
-
// return new Validator(schema as any, "2020-12");
|
|
43
|
-
// }
|
|
44
|
-
|
|
45
|
-
// throw new Error(`Unsupported OpenAPI version: ${openApiVersion}`);
|
|
46
|
-
// };
|
|
47
|
-
|
|
48
|
-
const parseSchemaInput = async (
|
|
49
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
50
|
-
schemaInput: any,
|
|
51
|
-
): Promise<JSONSchema & { openapi?: string }> => {
|
|
52
|
-
if (typeof schemaInput === "string") {
|
|
53
|
-
if (schemaInput.trim().startsWith("{")) {
|
|
54
|
-
return JSON.parse(schemaInput);
|
|
55
|
-
}
|
|
56
|
-
if (schemaInput.includes("://")) {
|
|
57
|
-
const response = await fetch(schemaInput);
|
|
58
|
-
return (await response.json()) as JSONSchema;
|
|
59
|
-
}
|
|
60
|
-
const yaml = await import("yaml");
|
|
61
|
-
return yaml.parse(schemaInput);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
if (typeof schemaInput === "object") return schemaInput;
|
|
65
|
-
|
|
66
|
-
throw new Error("Unsupported schema input");
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* Validates, dereferences and upgrades the OpenAPI schema (to v3.1) if necessary.
|
|
71
|
-
*/
|
|
72
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
73
|
-
export const validate = async (schemaInput: any) => {
|
|
74
|
-
const schema = await parseSchemaInput(schemaInput);
|
|
75
|
-
|
|
76
|
-
if (!schema.openapi) {
|
|
77
|
-
throw new Error("OpenAPI version is not defined");
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// const validator = await getValidator(schema.openapi);
|
|
81
|
-
// const result = validator.validate(schema);
|
|
82
|
-
//
|
|
83
|
-
// if (!result.valid) {
|
|
84
|
-
// throw new ValidationError(result.errors);
|
|
85
|
-
// }
|
|
86
|
-
|
|
87
|
-
const dereferenced = await dereference(schema);
|
|
88
|
-
|
|
89
|
-
const upgraded = upgradeSchema(
|
|
90
|
-
dereferenced as OpenAPIV3_1.Document | OpenAPIV3.Document,
|
|
91
|
-
);
|
|
92
|
-
|
|
93
|
-
return upgraded;
|
|
94
|
-
};
|