schema-components 1.29.0 → 2.0.1
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/README.md +38 -16
- package/dist/core/adapter.d.mts +213 -3
- package/dist/core/adapter.mjs +1 -1
- package/dist/core/constraintHint.d.mts +15 -0
- package/dist/core/constraintHint.mjs +24 -0
- package/dist/core/constraints.d.mts +2 -2
- package/dist/core/constraints.mjs +1 -1
- package/dist/core/diagnostics.d.mts +1 -1
- package/dist/core/errors.d.mts +1 -1
- package/dist/core/fieldOrder.d.mts +1 -1
- package/dist/core/formats.d.mts +1 -1
- package/dist/core/idPath.d.mts +35 -5
- package/dist/core/idPath.mjs +79 -7
- package/dist/core/inferValue.d.mts +2 -0
- package/dist/core/inferValue.mjs +1 -0
- package/dist/core/limits.d.mts +1 -1
- package/dist/core/limits.mjs +5 -0
- package/dist/core/merge.d.mts +12 -1
- package/dist/core/merge.mjs +66 -3
- package/dist/core/normalise.d.mts +1 -1
- package/dist/core/normalise.mjs +1 -1
- package/dist/core/openapi30.mjs +1 -1
- package/dist/core/ref.d.mts +1 -1
- package/dist/core/refChain.d.mts +3 -4
- package/dist/core/refChain.mjs +2 -3
- package/dist/core/renderer.d.mts +199 -2
- package/dist/core/swagger2.d.mts +1 -1
- package/dist/core/swagger2.mjs +1 -1
- package/dist/core/typeInference.d.mts +3 -3
- package/dist/core/types.d.mts +1 -1
- package/dist/core/unionMatch.d.mts +1 -1
- package/dist/core/uri.d.mts +12 -4
- package/dist/core/uri.mjs +30 -4
- package/dist/core/walkBuilders.d.mts +18 -6
- package/dist/core/walkBuilders.mjs +3 -1
- package/dist/core/walker.d.mts +1 -1
- package/dist/core/walker.mjs +5 -0
- package/dist/{diagnostics-ByEzkjrA.d.mts → diagnostics-BTrm3O6J.d.mts} +1 -1
- package/dist/{errors-D8JndRwI.d.mts → errors-Dki7tji4.d.mts} +1 -1
- package/dist/html/a11y.d.mts +3 -7
- package/dist/html/a11y.mjs +1 -16
- package/dist/html/renderToHtml.d.mts +22 -9
- package/dist/html/renderToHtml.mjs +2 -1
- package/dist/html/renderToHtmlStream.d.mts +24 -11
- package/dist/html/renderToHtmlStream.mjs +2 -1
- package/dist/html/renderers.d.mts +2 -33
- package/dist/html/renderers.mjs +39 -91
- package/dist/html/streamRenderers.d.mts +3 -3
- package/dist/html/streamRenderers.mjs +13 -8
- package/dist/inferValue-PPXWJpbN.d.mts +77 -0
- package/dist/{limits-DswmqWuy.d.mts → limits-x4OiyJxh.d.mts} +5 -0
- package/dist/{normalise-Db1xaxgx.mjs → normalise-DB-Xtjmn.mjs} +43 -2
- package/dist/openapi/ApiCallbacks.d.mts +1 -1
- package/dist/openapi/ApiLinks.d.mts +1 -1
- package/dist/openapi/ApiResponseHeaders.d.mts +1 -1
- package/dist/openapi/ApiSecurity.d.mts +1 -1
- package/dist/openapi/ApiSecurity.mjs +21 -8
- package/dist/openapi/bundle.d.mts +31 -0
- package/dist/openapi/components.d.mts +41 -10
- package/dist/openapi/components.mjs +19 -13
- package/dist/openapi/parser.d.mts +13 -13
- package/dist/openapi/parser.mjs +12 -12
- package/dist/openapi/resolve.d.mts +38 -49
- package/dist/openapi/resolve.mjs +62 -56
- package/dist/react/SchemaComponent.d.mts +19 -95
- package/dist/react/SchemaComponent.mjs +12 -1
- package/dist/react/SchemaView.d.mts +11 -7
- package/dist/react/SchemaView.mjs +3 -1
- package/dist/react/a11y.d.mts +74 -7
- package/dist/react/a11y.mjs +67 -6
- package/dist/react/fieldPath.d.mts +16 -1
- package/dist/react/fieldPath.mjs +25 -1
- package/dist/react/fieldShell.d.mts +49 -0
- package/dist/react/fieldShell.mjs +37 -0
- package/dist/react/headless.d.mts +1 -1
- package/dist/react/headlessRenderers.d.mts +2 -2
- package/dist/react/headlessRenderers.mjs +123 -54
- package/dist/{ref-CPh8rKQ3.d.mts → ref-DdsbekXX.d.mts} +33 -1
- package/dist/themes/mantine.d.mts +36 -20
- package/dist/themes/mantine.mjs +179 -150
- package/dist/themes/mui.d.mts +47 -21
- package/dist/themes/mui.mjs +259 -222
- package/dist/themes/radix.d.mts +38 -23
- package/dist/themes/radix.mjs +208 -180
- package/dist/themes/shadcn.d.mts +6 -3
- package/dist/themes/shadcn.mjs +93 -93
- package/dist/{types-C2Ay1FEh.d.mts → types-BrYbjC7_.d.mts} +7 -0
- package/package.json +5 -1
- package/dist/adapter-DcWi4XXn.d.mts +0 -223
- package/dist/renderer-OaOz-n6-.d.mts +0 -185
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { isObject } from "./core/guards.mjs";
|
|
2
2
|
import { appendPointer, emitDiagnostic } from "./core/diagnostics.mjs";
|
|
3
|
+
import { isPrototypePollutingKey } from "./core/uri.mjs";
|
|
3
4
|
import { RECURSIVE_ANCHOR_SENTINEL } from "./core/ref.mjs";
|
|
4
5
|
import { isOpenApi30, isOpenApi31, isSwagger2, matchJsonSchemaDraftUri, readJsonSchemaDialect } from "./core/version.mjs";
|
|
5
6
|
import { SWAGGER_2_METHODS, rewriteSwaggerRefPrefix } from "./core/openapiConstants.mjs";
|
|
@@ -801,7 +802,18 @@ function normaliseSwaggerOperation(operation, doc, path, method, diagnostics) {
|
|
|
801
802
|
const producesResolution = resolveSwaggerContentTypes(operation.produces, doc.produces);
|
|
802
803
|
const produces = producesResolution.types;
|
|
803
804
|
const consumes = consumesResolution.types;
|
|
804
|
-
for (const [key, value] of Object.entries(operation)) if (key !== "parameters" && key !== "responses" && key !== "produces" && key !== "consumes")
|
|
805
|
+
for (const [key, value] of Object.entries(operation)) if (key !== "parameters" && key !== "responses" && key !== "produces" && key !== "consumes") {
|
|
806
|
+
if (isPrototypePollutingKey(key)) {
|
|
807
|
+
emitDiagnostic(diagnostics, {
|
|
808
|
+
code: "prototype-polluting-property",
|
|
809
|
+
message: `Refusing to copy prototype-polluting property name into normalised operation: ${key}`,
|
|
810
|
+
pointer: appendPointer(`/paths/${path}/${method}`, key),
|
|
811
|
+
detail: { propertyName: key }
|
|
812
|
+
});
|
|
813
|
+
continue;
|
|
814
|
+
}
|
|
815
|
+
result[key] = value;
|
|
816
|
+
}
|
|
805
817
|
const params = operation.parameters;
|
|
806
818
|
if (Array.isArray(params)) {
|
|
807
819
|
const nonBodyParams = [];
|
|
@@ -1038,6 +1050,15 @@ function normaliseSwaggerParameter(param, doc, diagnostics, pointer = "") {
|
|
|
1038
1050
|
const result = {};
|
|
1039
1051
|
for (const [key, value] of Object.entries(param)) {
|
|
1040
1052
|
if (PARAM_KEYWORDS_LIFTED_INTO_SCHEMA.has(key)) continue;
|
|
1053
|
+
if (isPrototypePollutingKey(key)) {
|
|
1054
|
+
emitDiagnostic(diagnostics, {
|
|
1055
|
+
code: "prototype-polluting-property",
|
|
1056
|
+
message: `Refusing to copy prototype-polluting property name into normalised parameter: ${key}`,
|
|
1057
|
+
pointer: appendPointer(pointer, key),
|
|
1058
|
+
detail: { propertyName: key }
|
|
1059
|
+
});
|
|
1060
|
+
continue;
|
|
1061
|
+
}
|
|
1041
1062
|
result[key] = value;
|
|
1042
1063
|
}
|
|
1043
1064
|
if (typeof param.type === "string") if (param.type === "file" && param.in !== "formData") {
|
|
@@ -1186,7 +1207,18 @@ function normaliseSwaggerResponses(responses, doc, produces, producesSource, dia
|
|
|
1186
1207
|
function normaliseSwaggerSingleResponse(response, doc, produces, producesSource = "synthesised", diagnostics, path, method, statusCode) {
|
|
1187
1208
|
const resolved = resolveSwaggerResponse(response, doc);
|
|
1188
1209
|
const normalised = {};
|
|
1189
|
-
for (const [key, value] of Object.entries(resolved)) if (key !== "schema" && key !== "headers")
|
|
1210
|
+
for (const [key, value] of Object.entries(resolved)) if (key !== "schema" && key !== "headers") {
|
|
1211
|
+
if (isPrototypePollutingKey(key)) {
|
|
1212
|
+
emitDiagnostic(diagnostics, {
|
|
1213
|
+
code: "prototype-polluting-property",
|
|
1214
|
+
message: `Refusing to copy prototype-polluting property name into normalised response: ${key}`,
|
|
1215
|
+
pointer: path !== void 0 && method !== void 0 && statusCode !== void 0 ? appendPointer(`/paths/${path}/${method}/responses/${statusCode}`, key) : key,
|
|
1216
|
+
detail: { propertyName: key }
|
|
1217
|
+
});
|
|
1218
|
+
continue;
|
|
1219
|
+
}
|
|
1220
|
+
normalised[key] = value;
|
|
1221
|
+
}
|
|
1190
1222
|
const schema = resolved.schema;
|
|
1191
1223
|
if (isObject(schema)) {
|
|
1192
1224
|
const content = {};
|
|
@@ -1232,6 +1264,15 @@ function normaliseSwaggerHeader(header, diagnostics, pointer = "") {
|
|
|
1232
1264
|
const result = {};
|
|
1233
1265
|
for (const [key, value] of Object.entries(header)) {
|
|
1234
1266
|
if (PARAM_KEYWORDS_LIFTED_INTO_SCHEMA.has(key)) continue;
|
|
1267
|
+
if (isPrototypePollutingKey(key)) {
|
|
1268
|
+
emitDiagnostic(diagnostics, {
|
|
1269
|
+
code: "prototype-polluting-property",
|
|
1270
|
+
message: `Refusing to copy prototype-polluting property name into normalised header: ${key}`,
|
|
1271
|
+
pointer: appendPointer(pointer, key),
|
|
1272
|
+
detail: { propertyName: key }
|
|
1273
|
+
});
|
|
1274
|
+
continue;
|
|
1275
|
+
}
|
|
1235
1276
|
result[key] = value;
|
|
1236
1277
|
}
|
|
1237
1278
|
if (typeof header.type === "string") result.schema = buildSchemaFromSwaggerParameterShape(header);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { isObject } from "../core/guards.mjs";
|
|
2
|
+
import { isSafeHyperlink } from "../core/uri.mjs";
|
|
2
3
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
4
|
//#region src/openapi/ApiSecurity.tsx
|
|
4
5
|
/**
|
|
@@ -113,11 +114,14 @@ function SchemeDetails({ scheme }) {
|
|
|
113
114
|
"data-security-apikey-in": true,
|
|
114
115
|
children: scheme.location
|
|
115
116
|
}),
|
|
116
|
-
scheme.openIdConnectUrl !== void 0 && /* @__PURE__ */ jsx("a", {
|
|
117
|
+
scheme.openIdConnectUrl !== void 0 && (isSafeHyperlink(scheme.openIdConnectUrl) ? /* @__PURE__ */ jsx("a", {
|
|
117
118
|
"data-security-openid-url": true,
|
|
118
119
|
href: scheme.openIdConnectUrl,
|
|
119
120
|
children: scheme.openIdConnectUrl
|
|
120
|
-
}),
|
|
121
|
+
}) : /* @__PURE__ */ jsx("span", {
|
|
122
|
+
"data-security-openid-url": true,
|
|
123
|
+
children: scheme.openIdConnectUrl
|
|
124
|
+
})),
|
|
121
125
|
flows.length > 0 && /* @__PURE__ */ jsx("section", {
|
|
122
126
|
"data-security-flows": true,
|
|
123
127
|
children: flows.map((flow) => /* @__PURE__ */ jsx(FlowDetails, { flow }, flow.name))
|
|
@@ -132,21 +136,30 @@ function FlowDetails({ flow }) {
|
|
|
132
136
|
"data-security-flow-name": true,
|
|
133
137
|
children: flow.name
|
|
134
138
|
}),
|
|
135
|
-
flow.authorizationUrl !== void 0 && /* @__PURE__ */ jsx("a", {
|
|
139
|
+
flow.authorizationUrl !== void 0 && (isSafeHyperlink(flow.authorizationUrl) ? /* @__PURE__ */ jsx("a", {
|
|
136
140
|
"data-security-flow-authorization-url": true,
|
|
137
141
|
href: flow.authorizationUrl,
|
|
138
142
|
children: flow.authorizationUrl
|
|
139
|
-
}),
|
|
140
|
-
|
|
143
|
+
}) : /* @__PURE__ */ jsx("span", {
|
|
144
|
+
"data-security-flow-authorization-url": true,
|
|
145
|
+
children: flow.authorizationUrl
|
|
146
|
+
})),
|
|
147
|
+
flow.tokenUrl !== void 0 && (isSafeHyperlink(flow.tokenUrl) ? /* @__PURE__ */ jsx("a", {
|
|
141
148
|
"data-security-flow-token-url": true,
|
|
142
149
|
href: flow.tokenUrl,
|
|
143
150
|
children: flow.tokenUrl
|
|
144
|
-
}),
|
|
145
|
-
|
|
151
|
+
}) : /* @__PURE__ */ jsx("span", {
|
|
152
|
+
"data-security-flow-token-url": true,
|
|
153
|
+
children: flow.tokenUrl
|
|
154
|
+
})),
|
|
155
|
+
flow.refreshUrl !== void 0 && (isSafeHyperlink(flow.refreshUrl) ? /* @__PURE__ */ jsx("a", {
|
|
146
156
|
"data-security-flow-refresh-url": true,
|
|
147
157
|
href: flow.refreshUrl,
|
|
148
158
|
children: flow.refreshUrl
|
|
149
|
-
}),
|
|
159
|
+
}) : /* @__PURE__ */ jsx("span", {
|
|
160
|
+
"data-security-flow-refresh-url": true,
|
|
161
|
+
children: flow.refreshUrl
|
|
162
|
+
})),
|
|
150
163
|
flow.scopes.size > 0 && /* @__PURE__ */ jsx("dl", {
|
|
151
164
|
"data-security-flow-scopes": true,
|
|
152
165
|
children: [...flow.scopes.entries()].map(([name, description]) => /* @__PURE__ */ jsxs("div", {
|
|
@@ -27,6 +27,37 @@
|
|
|
27
27
|
* Resolver function for external documents.
|
|
28
28
|
* Called with the URI portion of an external $ref (everything before `#`).
|
|
29
29
|
* Returns the parsed JSON document.
|
|
30
|
+
*
|
|
31
|
+
* ### Security warning — SSRF and local-file disclosure
|
|
32
|
+
*
|
|
33
|
+
* Consumers MUST validate the URI before fetching the target document.
|
|
34
|
+
* The bundler hands the resolver the raw `$ref` URI from the OpenAPI
|
|
35
|
+
* document — which is typically user-controlled — and any network or
|
|
36
|
+
* filesystem access the resolver performs runs with the host
|
|
37
|
+
* application's full privileges. An attacker-crafted document that
|
|
38
|
+
* references an internal endpoint or a local filesystem path will
|
|
39
|
+
* happily exfiltrate or expose data the application never intended to
|
|
40
|
+
* surface.
|
|
41
|
+
*
|
|
42
|
+
* At a minimum the resolver should:
|
|
43
|
+
*
|
|
44
|
+
* - Refuse non-`https:` schemes by default. Permit `http:` only on an
|
|
45
|
+
* explicit allow-list. Refuse `file:`, `data:`, `javascript:`,
|
|
46
|
+
* `ftp:`, `gopher:`, and every other scheme outright.
|
|
47
|
+
* - Resolve the URI's hostname and refuse loopback addresses
|
|
48
|
+
* (`127.0.0.0/8`, `::1`), link-local addresses (`169.254.0.0/16`,
|
|
49
|
+
* `fe80::/10`), private ranges (`10.0.0.0/8`, `172.16.0.0/12`,
|
|
50
|
+
* `192.168.0.0/16`, `fc00::/7`), and cloud-metadata IPs
|
|
51
|
+
* (`169.254.169.254`, `fd00:ec2::254`).
|
|
52
|
+
* - Apply a strict allow-list of permitted hosts where possible.
|
|
53
|
+
* - Set request timeouts and a maximum response size.
|
|
54
|
+
* - Disable HTTP redirects, or re-validate the redirected URL against
|
|
55
|
+
* the same denylist before following.
|
|
56
|
+
* - Reject responses that are not `application/json` or
|
|
57
|
+
* `application/yaml`.
|
|
58
|
+
*
|
|
59
|
+
* The bundler itself performs no validation — that responsibility sits
|
|
60
|
+
* exclusively with the resolver implementation supplied by the caller.
|
|
30
61
|
*/
|
|
31
62
|
type BundleResolver = (uri: string) => unknown;
|
|
32
63
|
/**
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { u as FieldOverride, w as SchemaMeta } from "../types-
|
|
2
|
-
import { r as DiagnosticSink } from "../diagnostics-
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
1
|
+
import { u as FieldOverride, w as SchemaMeta } from "../types-BrYbjC7_.mjs";
|
|
2
|
+
import { r as DiagnosticSink } from "../diagnostics-BTrm3O6J.mjs";
|
|
3
|
+
import { WidgetMap } from "../core/renderer.mjs";
|
|
4
|
+
import { InferParameterOverrides, InferRequestBodyFields, InferResponseFields, OpenAPIRequestBodyType, OpenAPIResponseType } from "../core/typeInference.mjs";
|
|
5
5
|
import { ReactNode } from "react";
|
|
6
6
|
|
|
7
7
|
//#region src/openapi/components.d.ts
|
|
@@ -173,13 +173,30 @@ interface ApiDiagnosticsProps {
|
|
|
173
173
|
*
|
|
174
174
|
* @group OpenAPI
|
|
175
175
|
*/
|
|
176
|
-
interface ApiOperationProps<Doc = unknown, Path extends PathKeysOf<Doc> = PathKeysOf<Doc>, Method extends MethodKeysOf<Doc, Path> = MethodKeysOf<Doc, Path>, ContentType extends RequestContentTypesOf<Doc, Path, Method> = RequestContentTypesOf<Doc, Path, Method>> extends ApiDiagnosticsProps {
|
|
176
|
+
interface ApiOperationProps<Doc = unknown, Path extends PathKeysOf<Doc> = PathKeysOf<Doc>, Method extends MethodKeysOf<Doc, Path> = MethodKeysOf<Doc, Path>, ContentType extends RequestContentTypesOf<Doc, Path, Method> = RequestContentTypesOf<Doc, Path, Method>, ResponseStatus extends StatusKeysOf<Doc, Path, Method> = StatusKeysOf<Doc, Path, Method>, ResponseContentType extends ResponseContentTypesOf<Doc, Path, Method, ResponseStatus> = ResponseContentTypesOf<Doc, Path, Method, ResponseStatus>> extends ApiDiagnosticsProps {
|
|
177
177
|
schema: Doc;
|
|
178
178
|
path: Path;
|
|
179
179
|
method: Method;
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
180
|
+
/**
|
|
181
|
+
* Current request body value. Inferred from the operation's
|
|
182
|
+
* request body schema via {@link OpenAPIRequestBodyType} so a
|
|
183
|
+
* typed `schema` argument drives the rendered value's shape.
|
|
184
|
+
*/
|
|
185
|
+
requestBodyValue?: OpenAPIRequestBodyType<Doc, Path & string, Method & string, ContentType & string>;
|
|
186
|
+
/**
|
|
187
|
+
* Called when the request body value changes. Parameter type
|
|
188
|
+
* mirrors {@link ApiOperationProps.requestBodyValue}.
|
|
189
|
+
*/
|
|
190
|
+
onRequestBodyChange?: (value: OpenAPIRequestBodyType<Doc, Path & string, Method & string, ContentType & string>) => void;
|
|
191
|
+
/**
|
|
192
|
+
* Current response value. Inferred via {@link OpenAPIResponseType}
|
|
193
|
+
* from the operation's response schema for the supplied
|
|
194
|
+
* `responseStatus` (defaulting to the union of declared statuses)
|
|
195
|
+
* and `responseContentType` (defaulting to the union of declared
|
|
196
|
+
* media types). The same value is rendered against every response
|
|
197
|
+
* card the component emits.
|
|
198
|
+
*/
|
|
199
|
+
responseValue?: OpenAPIResponseType<Doc, Path & string, Method & string, ResponseStatus & string, ResponseContentType & string>;
|
|
183
200
|
meta?: SchemaMeta;
|
|
184
201
|
/**
|
|
185
202
|
* Media type whose request body schema drives `requestBodyFields`
|
|
@@ -190,6 +207,20 @@ interface ApiOperationProps<Doc = unknown, Path extends PathKeysOf<Doc> = PathKe
|
|
|
190
207
|
* same precision as `<ApiRequestBody>`.
|
|
191
208
|
*/
|
|
192
209
|
requestBodyContentType?: ContentType;
|
|
210
|
+
/**
|
|
211
|
+
* Status code whose response schema drives `responseValue`
|
|
212
|
+
* inference. Defaults to the union of declared statuses so
|
|
213
|
+
* callers can omit it; supply explicitly to narrow inference to
|
|
214
|
+
* a specific response (e.g. `"200"`).
|
|
215
|
+
*/
|
|
216
|
+
responseStatus?: ResponseStatus;
|
|
217
|
+
/**
|
|
218
|
+
* Media type whose response schema drives `responseValue`
|
|
219
|
+
* inference. Defaults to the union of declared content types so
|
|
220
|
+
* callers can omit it; supply explicitly to narrow inference to
|
|
221
|
+
* a specific media type.
|
|
222
|
+
*/
|
|
223
|
+
responseContentType?: ResponseContentType;
|
|
193
224
|
requestBodyFields?: Doc extends Record<string, unknown> ? InferRequestBodyFields<Doc, Path & string, Method & string, ContentType & string> : Record<string, FieldOverride>;
|
|
194
225
|
/** Instance-scoped widgets. */
|
|
195
226
|
widgets?: WidgetMap;
|
|
@@ -213,7 +244,7 @@ interface ApiOperationProps<Doc = unknown, Path extends PathKeysOf<Doc> = PathKe
|
|
|
213
244
|
* <ApiOperation schema={petStore} path="/pets" method="post" />
|
|
214
245
|
* ```
|
|
215
246
|
*/
|
|
216
|
-
declare function ApiOperation<Doc = unknown, Path extends PathKeysOf<Doc> = PathKeysOf<Doc>, Method extends MethodKeysOf<Doc, Path> = MethodKeysOf<Doc, Path>, ContentType extends RequestContentTypesOf<Doc, Path, Method> = RequestContentTypesOf<Doc, Path, Method>>({
|
|
247
|
+
declare function ApiOperation<Doc = unknown, Path extends PathKeysOf<Doc> = PathKeysOf<Doc>, Method extends MethodKeysOf<Doc, Path> = MethodKeysOf<Doc, Path>, ContentType extends RequestContentTypesOf<Doc, Path, Method> = RequestContentTypesOf<Doc, Path, Method>, ResponseStatus extends StatusKeysOf<Doc, Path, Method> = StatusKeysOf<Doc, Path, Method>, ResponseContentType extends ResponseContentTypesOf<Doc, Path, Method, ResponseStatus> = ResponseContentTypesOf<Doc, Path, Method, ResponseStatus>>({
|
|
217
248
|
schema: doc,
|
|
218
249
|
path,
|
|
219
250
|
method,
|
|
@@ -225,7 +256,7 @@ declare function ApiOperation<Doc = unknown, Path extends PathKeysOf<Doc> = Path
|
|
|
225
256
|
widgets,
|
|
226
257
|
onDiagnostic,
|
|
227
258
|
strict
|
|
228
|
-
}: ApiOperationProps<Doc, Path, Method, ContentType>): ReactNode;
|
|
259
|
+
}: ApiOperationProps<Doc, Path, Method, ContentType, ResponseStatus, ResponseContentType>): ReactNode;
|
|
229
260
|
/**
|
|
230
261
|
* Props accepted by {@link ApiParameters}.
|
|
231
262
|
*
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import { isObject, toRecordOrUndefined } from "../core/guards.mjs";
|
|
2
2
|
import { emitDiagnostic } from "../core/diagnostics.mjs";
|
|
3
|
+
import { isSafeHyperlink } from "../core/uri.mjs";
|
|
3
4
|
import { extractRootMetaFromJson } from "../core/adapter.mjs";
|
|
4
5
|
import { walk } from "../core/walker.mjs";
|
|
5
6
|
import { ApiCallbacks } from "./ApiCallbacks.mjs";
|
|
6
7
|
import { ApiLinks } from "./ApiLinks.mjs";
|
|
7
8
|
import { ApiResponseHeaders } from "./ApiResponseHeaders.mjs";
|
|
8
9
|
import { ApiSecurity } from "./ApiSecurity.mjs";
|
|
9
|
-
import {
|
|
10
|
+
import { extractExternalDocs, extractLinks, extractSecurityRequirements, extractSecuritySchemes, extractXmlInfo, listCallbacks, listWebhooks } from "./parser.mjs";
|
|
10
11
|
import { joinPath, renderField, sanitisePrefix } from "../react/SchemaComponent.mjs";
|
|
11
|
-
import { getParsed,
|
|
12
|
+
import { getParsed, resolveOperation, resolveParameters, resolveRequestBody, resolveResponse, toDoc } from "./resolve.mjs";
|
|
12
13
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
13
14
|
import { useId } from "react";
|
|
14
15
|
//#region src/openapi/components.tsx
|
|
@@ -78,11 +79,16 @@ function renderSchema(schema, rootDocument, options) {
|
|
|
78
79
|
*/
|
|
79
80
|
function ExternalDocsLink({ externalDocs }) {
|
|
80
81
|
if (externalDocs === void 0) return null;
|
|
82
|
+
const label = externalDocs.description ?? externalDocs.url;
|
|
83
|
+
if (!isSafeHyperlink(externalDocs.url)) return /* @__PURE__ */ jsx("p", {
|
|
84
|
+
"data-external-docs": true,
|
|
85
|
+
children: /* @__PURE__ */ jsx("span", { children: label })
|
|
86
|
+
});
|
|
81
87
|
return /* @__PURE__ */ jsx("p", {
|
|
82
88
|
"data-external-docs": true,
|
|
83
89
|
children: /* @__PURE__ */ jsx("a", {
|
|
84
90
|
href: externalDocs.url,
|
|
85
|
-
children:
|
|
91
|
+
children: label
|
|
86
92
|
})
|
|
87
93
|
});
|
|
88
94
|
}
|
|
@@ -132,12 +138,12 @@ function ApiOperation({ schema: doc, path, method, requestBodyValue, onRequestBo
|
|
|
132
138
|
const rootDoc = resolveRootDoc(doc, diagnostics);
|
|
133
139
|
if (rootDoc === void 0) return null;
|
|
134
140
|
const parsed = getParsed(rootDoc, diagnostics);
|
|
135
|
-
const resolved =
|
|
136
|
-
const securityReqs =
|
|
137
|
-
const securitySchemes =
|
|
141
|
+
const resolved = resolveOperation(parsed, path, method, diagnostics);
|
|
142
|
+
const securityReqs = extractSecurityRequirements(parsed, path, method);
|
|
143
|
+
const securitySchemes = extractSecuritySchemes(parsed);
|
|
138
144
|
const callbacks = listCallbacks(parsed, path, method);
|
|
139
|
-
const operationExternalDocs =
|
|
140
|
-
const requestBodyXml = resolved.requestBody?.schema !== void 0 ?
|
|
145
|
+
const operationExternalDocs = extractExternalDocs(resolved.operation.operation);
|
|
146
|
+
const requestBodyXml = resolved.requestBody?.schema !== void 0 ? extractXmlInfo(resolved.requestBody.schema) : void 0;
|
|
141
147
|
return /* @__PURE__ */ jsxs("section", {
|
|
142
148
|
"data-operation": `${method.toUpperCase()} ${path}`,
|
|
143
149
|
children: [
|
|
@@ -216,7 +222,7 @@ function ApiParameters({ schema: doc, path, method, meta, overrides, widgets, on
|
|
|
216
222
|
const instancePrefix = sanitisePrefix(useId());
|
|
217
223
|
const rootDoc = resolveRootDoc(doc, diagnostics);
|
|
218
224
|
if (rootDoc === void 0) return null;
|
|
219
|
-
const params =
|
|
225
|
+
const params = resolveParameters(getParsed(rootDoc, diagnostics), path, method);
|
|
220
226
|
if (params.length === 0) return null;
|
|
221
227
|
return /* @__PURE__ */ jsxs("section", {
|
|
222
228
|
"data-parameters": true,
|
|
@@ -248,9 +254,9 @@ function ApiRequestBody({ schema: doc, path, method, value, onChange, meta, fiel
|
|
|
248
254
|
const instancePrefix = sanitisePrefix(useId());
|
|
249
255
|
const rootDoc = resolveRootDoc(doc, diagnostics);
|
|
250
256
|
if (rootDoc === void 0) return null;
|
|
251
|
-
const requestBody =
|
|
257
|
+
const requestBody = resolveRequestBody(getParsed(rootDoc, diagnostics), path, method);
|
|
252
258
|
if (requestBody?.schema === void 0) return null;
|
|
253
|
-
const requestBodyXml =
|
|
259
|
+
const requestBodyXml = extractXmlInfo(requestBody.schema);
|
|
254
260
|
return /* @__PURE__ */ jsxs("section", {
|
|
255
261
|
"data-request-body": true,
|
|
256
262
|
children: [
|
|
@@ -293,7 +299,7 @@ function ApiResponse({ schema: doc, path, method, status, value, meta, fields, w
|
|
|
293
299
|
const rootDoc = resolveRootDoc(doc, diagnostics);
|
|
294
300
|
if (rootDoc === void 0) return null;
|
|
295
301
|
const parsed = getParsed(rootDoc, diagnostics);
|
|
296
|
-
const response =
|
|
302
|
+
const response = resolveResponse(parsed, path, method, status);
|
|
297
303
|
if (response.schema === void 0) return /* @__PURE__ */ jsxs("div", {
|
|
298
304
|
"data-status": status,
|
|
299
305
|
children: [
|
|
@@ -449,7 +455,7 @@ function ResponseCard({ response, rootDoc, parsed, value, fields, meta, widgets,
|
|
|
449
455
|
]
|
|
450
456
|
});
|
|
451
457
|
let links = [];
|
|
452
|
-
if (path !== void 0 && method !== void 0) links =
|
|
458
|
+
if (path !== void 0 && method !== void 0) links = extractLinks(parsed, path, method, response.statusCode);
|
|
453
459
|
return /* @__PURE__ */ jsxs("div", {
|
|
454
460
|
"data-status": response.statusCode,
|
|
455
461
|
children: [
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { m as JsonObject } from "../types-
|
|
2
|
-
import { i as DiagnosticsOptions } from "../diagnostics-
|
|
1
|
+
import { m as JsonObject } from "../types-BrYbjC7_.mjs";
|
|
2
|
+
import { i as DiagnosticsOptions } from "../diagnostics-BTrm3O6J.mjs";
|
|
3
3
|
|
|
4
4
|
//#region src/openapi/parser.d.ts
|
|
5
5
|
/**
|
|
@@ -155,7 +155,7 @@ declare function parseOpenApiDocument(doc: JsonObject): OpenApiDocument;
|
|
|
155
155
|
* resolved value for arbitrary fragment refs), or `undefined` when the
|
|
156
156
|
* ref cannot be resolved.
|
|
157
157
|
*/
|
|
158
|
-
declare function
|
|
158
|
+
declare function extractSchema(parsed: OpenApiDocument, ref: string): JsonObject | undefined;
|
|
159
159
|
/**
|
|
160
160
|
* List every operation declared under the document's `paths` map.
|
|
161
161
|
* Follows Path Item `$ref` chains internally; cycles and over-deep
|
|
@@ -167,36 +167,36 @@ declare function listOperations(parsed: OpenApiDocument, diagnostics?: Diagnosti
|
|
|
167
167
|
* parameters with operation-level overrides and following any
|
|
168
168
|
* Parameter Object `$ref` chains.
|
|
169
169
|
*/
|
|
170
|
-
declare function
|
|
170
|
+
declare function extractParameters(parsed: OpenApiDocument, path: string, method: string, diagnostics?: DiagnosticsOptions): ParameterInfo[];
|
|
171
171
|
/**
|
|
172
172
|
* Resolve the request body of a single operation, including its
|
|
173
173
|
* declared content types and schema. Returns `undefined` when the
|
|
174
174
|
* operation declares no request body.
|
|
175
175
|
*/
|
|
176
|
-
declare function
|
|
176
|
+
declare function extractRequestBody(parsed: OpenApiDocument, path: string, method: string): RequestBodyInfo | undefined;
|
|
177
177
|
/**
|
|
178
178
|
* Resolve the responses of a single operation, returning one
|
|
179
179
|
* {@link ResponseInfo} per declared status code (including class
|
|
180
180
|
* wildcards and `default`).
|
|
181
181
|
*/
|
|
182
|
-
declare function
|
|
182
|
+
declare function extractResponses(parsed: OpenApiDocument, path: string, method: string, diagnostics?: DiagnosticsOptions): ResponseInfo[];
|
|
183
183
|
/**
|
|
184
184
|
* Resolve the effective security requirements for a single operation.
|
|
185
185
|
* Operation-level requirements override the document-level defaults
|
|
186
186
|
* when present.
|
|
187
187
|
*/
|
|
188
|
-
declare function
|
|
188
|
+
declare function extractSecurityRequirements(parsed: OpenApiDocument, path: string, method: string): SecurityRequirement[];
|
|
189
189
|
/**
|
|
190
190
|
* Read the document's `components.securitySchemes` map as a map of
|
|
191
191
|
* scheme names to {@link SecurityScheme} entries.
|
|
192
192
|
*/
|
|
193
|
-
declare function
|
|
193
|
+
declare function extractSecuritySchemes(parsed: OpenApiDocument): Map<string, SecurityScheme>;
|
|
194
194
|
/**
|
|
195
195
|
* Resolve the headers of a single OpenAPI Response Object as a map of
|
|
196
196
|
* header name to {@link HeaderInfo}. Follows Header Object `$ref`
|
|
197
197
|
* chains via the optional document root.
|
|
198
198
|
*/
|
|
199
|
-
declare function
|
|
199
|
+
declare function extractResponseHeaders(response: JsonObject, doc?: JsonObject, diagnostics?: DiagnosticsOptions): Map<string, HeaderInfo>;
|
|
200
200
|
/**
|
|
201
201
|
* List every OpenAPI 3.1 webhook declared under the document's
|
|
202
202
|
* `webhooks` map, each with its name and resolved operations.
|
|
@@ -216,13 +216,13 @@ declare function listAllOperations(parsed: OpenApiDocument, diagnostics?: Diagno
|
|
|
216
216
|
* (document, operation, tag, schema, ...) into an {@link ExternalDocs}
|
|
217
217
|
* record. Returns `undefined` when absent or malformed.
|
|
218
218
|
*/
|
|
219
|
-
declare function
|
|
219
|
+
declare function extractExternalDocs(obj: JsonObject): ExternalDocs | undefined;
|
|
220
220
|
/**
|
|
221
221
|
* Read the optional `xml` keyword on a JSON Schema object into an
|
|
222
222
|
* {@link XmlInfo} record describing how the field is serialised in an
|
|
223
223
|
* XML payload. Returns `undefined` when absent or malformed.
|
|
224
224
|
*/
|
|
225
|
-
declare function
|
|
225
|
+
declare function extractXmlInfo(schema: JsonObject): XmlInfo | undefined;
|
|
226
226
|
/**
|
|
227
227
|
* List the OpenAPI callback definitions declared on a single
|
|
228
228
|
* operation. Each entry carries the callback name and the operations
|
|
@@ -234,6 +234,6 @@ declare function listCallbacks(parsed: OpenApiDocument, path: string, method: st
|
|
|
234
234
|
* a single operation, returning each link's parsed
|
|
235
235
|
* {@link LinkInfo} entry.
|
|
236
236
|
*/
|
|
237
|
-
declare function
|
|
237
|
+
declare function extractLinks(parsed: OpenApiDocument, path: string, method: string, statusCode: string, diagnostics?: DiagnosticsOptions): LinkInfo[];
|
|
238
238
|
//#endregion
|
|
239
|
-
export { CallbackInfo, ExternalDocs, HeaderInfo, LinkInfo, OpenApiDocument, OperationInfo, ParameterInfo, ParameterLocation, RequestBodyInfo, ResponseInfo, SecurityRequirement, SecurityScheme, WebhookInfo, XmlInfo,
|
|
239
|
+
export { CallbackInfo, ExternalDocs, HeaderInfo, LinkInfo, OpenApiDocument, OperationInfo, ParameterInfo, ParameterLocation, RequestBodyInfo, ResponseInfo, SecurityRequirement, SecurityScheme, WebhookInfo, XmlInfo, extractExternalDocs, extractLinks, extractParameters, extractRequestBody, extractResponseHeaders, extractResponses, extractSchema, extractSecurityRequirements, extractSecuritySchemes, extractXmlInfo, listAllOperations, listCallbacks, listOperations, listWebhooks, parseOpenApiDocument };
|
package/dist/openapi/parser.mjs
CHANGED
|
@@ -58,7 +58,7 @@ function parseOpenApiDocument(doc) {
|
|
|
58
58
|
* resolved value for arbitrary fragment refs), or `undefined` when the
|
|
59
59
|
* ref cannot be resolved.
|
|
60
60
|
*/
|
|
61
|
-
function
|
|
61
|
+
function extractSchema(parsed, ref) {
|
|
62
62
|
const cached = parsed.schemas.get(ref);
|
|
63
63
|
if (cached !== void 0) return cached;
|
|
64
64
|
const resolved = resolveRefInDoc(parsed.doc, ref);
|
|
@@ -174,7 +174,7 @@ function listOperations(parsed, diagnostics, seenIds = /* @__PURE__ */ new Map()
|
|
|
174
174
|
* parameters with operation-level overrides and following any
|
|
175
175
|
* Parameter Object `$ref` chains.
|
|
176
176
|
*/
|
|
177
|
-
function
|
|
177
|
+
function extractParameters(parsed, path, method, diagnostics) {
|
|
178
178
|
const pathItem = lookupPathItem(parsed, path);
|
|
179
179
|
if (pathItem === void 0) return [];
|
|
180
180
|
const operation = getProperty(pathItem, method);
|
|
@@ -275,7 +275,7 @@ function jsonPointerEscape(segment) {
|
|
|
275
275
|
* declared content types and schema. Returns `undefined` when the
|
|
276
276
|
* operation declares no request body.
|
|
277
277
|
*/
|
|
278
|
-
function
|
|
278
|
+
function extractRequestBody(parsed, path, method) {
|
|
279
279
|
const requestBodyRaw = getProperty(getProperty(lookupPathItem(parsed, path), method), "requestBody");
|
|
280
280
|
if (!isObject(requestBodyRaw)) return void 0;
|
|
281
281
|
const requestBody = resolveWrapperRef(parsed.doc, requestBodyRaw);
|
|
@@ -301,7 +301,7 @@ function getRequestBody(parsed, path, method) {
|
|
|
301
301
|
* {@link ResponseInfo} per declared status code (including class
|
|
302
302
|
* wildcards and `default`).
|
|
303
303
|
*/
|
|
304
|
-
function
|
|
304
|
+
function extractResponses(parsed, path, method, diagnostics) {
|
|
305
305
|
const responses = getProperty(getProperty(lookupPathItem(parsed, path), method), "responses");
|
|
306
306
|
if (!isObject(responses)) return [];
|
|
307
307
|
const result = [];
|
|
@@ -312,7 +312,7 @@ function getResponses(parsed, path, method, diagnostics) {
|
|
|
312
312
|
const content = getProperty(response, "content");
|
|
313
313
|
const contentTypes = isObject(content) ? Object.keys(content) : [];
|
|
314
314
|
const schema = isObject(content) ? extractSchemaFromContent(content) : void 0;
|
|
315
|
-
const headers =
|
|
315
|
+
const headers = extractResponseHeaders(response, parsed.doc, diagnostics);
|
|
316
316
|
result.push({
|
|
317
317
|
statusCode,
|
|
318
318
|
description: getString(response, "description"),
|
|
@@ -448,7 +448,7 @@ function resolveRefInDoc(doc, ref) {
|
|
|
448
448
|
* Operation-level requirements override the document-level defaults
|
|
449
449
|
* when present.
|
|
450
450
|
*/
|
|
451
|
-
function
|
|
451
|
+
function extractSecurityRequirements(parsed, path, method) {
|
|
452
452
|
const opSecurity = getProperty(getProperty(lookupPathItem(parsed, path), method), "security");
|
|
453
453
|
const globalSecurity = getProperty(parsed.doc, "security");
|
|
454
454
|
const securityArray = Array.isArray(opSecurity) ? opSecurity : Array.isArray(globalSecurity) ? globalSecurity : [];
|
|
@@ -466,7 +466,7 @@ function getSecurityRequirements(parsed, path, method) {
|
|
|
466
466
|
* Read the document's `components.securitySchemes` map as a map of
|
|
467
467
|
* scheme names to {@link SecurityScheme} entries.
|
|
468
468
|
*/
|
|
469
|
-
function
|
|
469
|
+
function extractSecuritySchemes(parsed) {
|
|
470
470
|
const result = /* @__PURE__ */ new Map();
|
|
471
471
|
const securitySchemes = getProperty(getProperty(parsed.doc, "components"), "securitySchemes");
|
|
472
472
|
if (!isObject(securitySchemes)) return result;
|
|
@@ -491,7 +491,7 @@ function getSecuritySchemes(parsed) {
|
|
|
491
491
|
* header name to {@link HeaderInfo}. Follows Header Object `$ref`
|
|
492
492
|
* chains via the optional document root.
|
|
493
493
|
*/
|
|
494
|
-
function
|
|
494
|
+
function extractResponseHeaders(response, doc, diagnostics) {
|
|
495
495
|
const result = /* @__PURE__ */ new Map();
|
|
496
496
|
const headers = getProperty(response, "headers");
|
|
497
497
|
if (!isObject(headers)) return result;
|
|
@@ -562,7 +562,7 @@ function listAllOperations(parsed, diagnostics) {
|
|
|
562
562
|
* (document, operation, tag, schema, ...) into an {@link ExternalDocs}
|
|
563
563
|
* record. Returns `undefined` when absent or malformed.
|
|
564
564
|
*/
|
|
565
|
-
function
|
|
565
|
+
function extractExternalDocs(obj) {
|
|
566
566
|
const docs = getProperty(obj, "externalDocs");
|
|
567
567
|
if (!isObject(docs)) return void 0;
|
|
568
568
|
const url = getString(docs, "url");
|
|
@@ -577,7 +577,7 @@ function getExternalDocs(obj) {
|
|
|
577
577
|
* {@link XmlInfo} record describing how the field is serialised in an
|
|
578
578
|
* XML payload. Returns `undefined` when absent or malformed.
|
|
579
579
|
*/
|
|
580
|
-
function
|
|
580
|
+
function extractXmlInfo(schema) {
|
|
581
581
|
const xml = getProperty(schema, "xml");
|
|
582
582
|
if (!isObject(xml)) return void 0;
|
|
583
583
|
return {
|
|
@@ -631,7 +631,7 @@ function listCallbacks(parsed, path, method, diagnostics) {
|
|
|
631
631
|
* a single operation, returning each link's parsed
|
|
632
632
|
* {@link LinkInfo} entry.
|
|
633
633
|
*/
|
|
634
|
-
function
|
|
634
|
+
function extractLinks(parsed, path, method, statusCode, diagnostics) {
|
|
635
635
|
const response = getProperty(getProperty(getProperty(lookupPathItem(parsed, path), method), "responses"), statusCode);
|
|
636
636
|
if (!isObject(response)) return [];
|
|
637
637
|
const links = getProperty(response, "links");
|
|
@@ -657,4 +657,4 @@ function getLinks(parsed, path, method, statusCode, diagnostics) {
|
|
|
657
657
|
return result;
|
|
658
658
|
}
|
|
659
659
|
//#endregion
|
|
660
|
-
export {
|
|
660
|
+
export { extractExternalDocs, extractLinks, extractParameters, extractRequestBody, extractResponseHeaders, extractResponses, extractSchema, extractSecurityRequirements, extractSecuritySchemes, extractXmlInfo, listAllOperations, listCallbacks, listOperations, listWebhooks, parseOpenApiDocument };
|