schema-components 1.21.0 → 1.22.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.
- package/README.md +1 -1
- package/dist/core/adapter.d.mts +20 -3
- package/dist/core/adapter.mjs +209 -28
- package/dist/core/constraints.d.mts +2 -2
- 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 +22 -1
- package/dist/core/formats.mjs +21 -0
- package/dist/core/limits.d.mts +2 -0
- package/dist/core/limits.mjs +23 -0
- package/dist/core/merge.d.mts +1 -1
- package/dist/core/normalise.d.mts +29 -3
- package/dist/core/normalise.mjs +2 -2
- package/dist/core/openapi30.mjs +1 -1
- package/dist/core/ref.d.mts +1 -1
- package/dist/core/ref.mjs +1 -0
- package/dist/core/renderer.d.mts +1 -1
- package/dist/core/renderer.mjs +0 -2
- package/dist/core/swagger2.d.mts +1 -1
- package/dist/core/swagger2.mjs +1 -1
- package/dist/core/typeInference.d.mts +2 -2
- package/dist/core/types.d.mts +2 -2
- package/dist/core/types.mjs +1 -4
- package/dist/core/version.d.mts +1 -1
- package/dist/core/walkBuilders.d.mts +3 -3
- package/dist/core/walker.d.mts +1 -1
- package/dist/core/walker.mjs +79 -2
- package/dist/{diagnostics-CbBPsxSt.d.mts → diagnostics-D0QCYGv0.d.mts} +1 -1
- package/dist/{errors-QEwOtQAA.d.mts → errors-DpFwqs5C.d.mts} +1 -1
- package/dist/html/a11y.d.mts +2 -2
- package/dist/html/a11y.mjs +10 -3
- package/dist/html/renderToHtml.d.mts +10 -3
- package/dist/html/renderToHtml.mjs +13 -3
- package/dist/html/renderToHtmlStream.d.mts +2 -2
- package/dist/html/renderers.d.mts +2 -2
- package/dist/html/renderers.mjs +0 -5
- package/dist/html/streamRenderers.d.mts +5 -4
- package/dist/html/streamRenderers.mjs +91 -30
- package/dist/limits-Cw5QZND8.d.mts +29 -0
- package/dist/{normalise-DaSrnr8g.mjs → normalise-DVEJQmF7.mjs} +468 -115
- 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 +16 -2
- package/dist/openapi/components.d.mts +150 -18
- package/dist/openapi/components.mjs +129 -15
- package/dist/openapi/parser.d.mts +1 -1
- package/dist/openapi/parser.mjs +35 -3
- package/dist/openapi/resolve.d.mts +12 -5
- package/dist/openapi/resolve.mjs +183 -23
- package/dist/react/SchemaComponent.d.mts +100 -35
- package/dist/react/SchemaComponent.mjs +59 -45
- package/dist/react/SchemaView.d.mts +3 -3
- package/dist/react/SchemaView.mjs +2 -2
- package/dist/react/fieldPath.d.mts +1 -1
- package/dist/react/headless.d.mts +1 -1
- package/dist/react/headless.mjs +1 -2
- package/dist/react/headlessRenderers.d.mts +3 -4
- package/dist/react/headlessRenderers.mjs +10 -30
- package/dist/{ref-si8ViYun.d.mts → ref-D-_JBZkF.d.mts} +1 -1
- package/dist/{renderer-DI6ZYf7a.d.mts → renderer-BaRlQIuN.d.mts} +2 -2
- package/dist/themes/mantine.d.mts +1 -1
- package/dist/themes/mui.d.mts +1 -1
- package/dist/themes/radix.d.mts +1 -1
- package/dist/themes/shadcn.d.mts +1 -1
- package/dist/typeInference-DkcUHfaM.d.mts +982 -0
- package/dist/{types-BnxPEElk.d.mts → types-BrRMV0en.d.mts} +3 -10
- package/package.json +1 -3
- package/dist/typeInference-Bxw3NOG1.d.mts +0 -647
- /package/dist/{version-D-u7aMfy.d.mts → version-D2jfdX6E.d.mts} +0 -0
|
@@ -11,6 +11,18 @@ const OAUTH_FLOW_KEYS = [
|
|
|
11
11
|
"clientCredentials",
|
|
12
12
|
"authorizationCode"
|
|
13
13
|
];
|
|
14
|
+
/**
|
|
15
|
+
* Known Security Scheme `type` values per the OpenAPI 3.0/3.1 spec.
|
|
16
|
+
* Used to flag unknown values in the rendered output so authors can
|
|
17
|
+
* spot typos like `mutalTLS` without consulting the diagnostic sink.
|
|
18
|
+
*/
|
|
19
|
+
const KNOWN_SECURITY_SCHEME_TYPES = new Set([
|
|
20
|
+
"apiKey",
|
|
21
|
+
"http",
|
|
22
|
+
"oauth2",
|
|
23
|
+
"openIdConnect",
|
|
24
|
+
"mutualTLS"
|
|
25
|
+
]);
|
|
14
26
|
function readString(source, key) {
|
|
15
27
|
const value = source[key];
|
|
16
28
|
return typeof value === "string" ? value : void 0;
|
|
@@ -66,10 +78,12 @@ function ApiSecurity({ requirements, schemes }) {
|
|
|
66
78
|
}
|
|
67
79
|
function SchemeDetails({ scheme }) {
|
|
68
80
|
const flows = extractFlows(scheme.flows);
|
|
81
|
+
const isKnownType = scheme.type !== void 0 && KNOWN_SECURITY_SCHEME_TYPES.has(scheme.type);
|
|
69
82
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
70
|
-
scheme.type !== void 0 && /* @__PURE__ */
|
|
83
|
+
scheme.type !== void 0 && /* @__PURE__ */ jsxs("span", {
|
|
71
84
|
"data-security-type": true,
|
|
72
|
-
|
|
85
|
+
"data-security-type-unknown": isKnownType ? void 0 : "true",
|
|
86
|
+
children: [scheme.type, !isKnownType && " (unknown type)"]
|
|
73
87
|
}),
|
|
74
88
|
scheme.description !== void 0 && /* @__PURE__ */ jsx("span", {
|
|
75
89
|
"data-security-description": true,
|
|
@@ -1,10 +1,85 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { r as DiagnosticSink } from "../diagnostics-
|
|
3
|
-
import { a as
|
|
1
|
+
import { u as FieldOverride, w as SchemaMeta } from "../types-BrRMV0en.mjs";
|
|
2
|
+
import { r as DiagnosticSink } from "../diagnostics-D0QCYGv0.mjs";
|
|
3
|
+
import { a as InferParameterOverrides, g as UnsafeFields, o as InferRequestBodyFields, s as InferResponseFields } from "../typeInference-DkcUHfaM.mjs";
|
|
4
4
|
import { WidgetMap } from "../react/SchemaComponent.mjs";
|
|
5
5
|
import { ReactNode } from "react";
|
|
6
6
|
|
|
7
7
|
//#region src/openapi/components.d.ts
|
|
8
|
+
/**
|
|
9
|
+
* The canonical set of HTTP method strings recognised by OpenAPI 3.x.
|
|
10
|
+
* Used to constrain `Method` generics so autocomplete on typed
|
|
11
|
+
* documents only suggests methods the path item actually declares,
|
|
12
|
+
* not arbitrary string keys.
|
|
13
|
+
*/
|
|
14
|
+
type HttpMethod = "get" | "put" | "post" | "delete" | "options" | "head" | "patch" | "trace";
|
|
15
|
+
/**
|
|
16
|
+
* Extract the literal path keys from a document type, or the broad
|
|
17
|
+
* `string` fallback when the document is untyped at compile time.
|
|
18
|
+
*
|
|
19
|
+
* The `string extends keyof D["paths"]` guard distinguishes a typed
|
|
20
|
+
* `as const` document (whose `paths` map has literal keys) from a
|
|
21
|
+
* runtime `Record<string, unknown>` document (whose `keyof` collapses
|
|
22
|
+
* to `string`). For the runtime case we surface `string` so callers
|
|
23
|
+
* pass arbitrary path values without losing the existing freedom.
|
|
24
|
+
*/
|
|
25
|
+
type PathKeysOf<D> = D extends {
|
|
26
|
+
paths: infer P;
|
|
27
|
+
} ? P extends Record<string, unknown> ? string extends keyof P ? string : Extract<keyof P, string> : string : string;
|
|
28
|
+
/**
|
|
29
|
+
* Extract the methods declared on a specific path item, restricted to
|
|
30
|
+
* the OpenAPI-recognised method set so non-method extension keys
|
|
31
|
+
* (e.g. `summary`, `description`, `parameters`) do not pollute the
|
|
32
|
+
* autocomplete.
|
|
33
|
+
*
|
|
34
|
+
* Runtime documents (typed `Record<string, unknown>`) widen back to
|
|
35
|
+
* `string` so callers retain the freedom to pass arbitrary method
|
|
36
|
+
* strings without surfacing an `HttpMethod` constraint at runtime
|
|
37
|
+
* call sites.
|
|
38
|
+
*/
|
|
39
|
+
type MethodKeysOf<D, P extends string> = IsRuntimeDoc<D> extends true ? string : D extends {
|
|
40
|
+
paths: infer Paths;
|
|
41
|
+
} ? Paths extends Record<string, unknown> ? P extends keyof Paths ? Extract<keyof Paths[P], HttpMethod> : HttpMethod : HttpMethod : HttpMethod;
|
|
42
|
+
/**
|
|
43
|
+
* True for the runtime-document sentinel — a `Record<string, unknown>`
|
|
44
|
+
* (or wider) where `keyof` collapses to `string`. Used to drop
|
|
45
|
+
* narrow-constraint defaults so runtime callers retain the prior
|
|
46
|
+
* freedom to pass arbitrary path/method/status values.
|
|
47
|
+
*/
|
|
48
|
+
type IsRuntimeDoc<D> = D extends Record<string, unknown> ? string extends keyof D ? true : false : false;
|
|
49
|
+
/**
|
|
50
|
+
* Extract the status-code keys declared by an operation's `responses`
|
|
51
|
+
* map. Includes class wildcards (`2XX`, etc.) and the `default`
|
|
52
|
+
* sentinel; runtime documents widen to `string`.
|
|
53
|
+
*/
|
|
54
|
+
type StatusKeysOf<D, P extends string, M extends string> = D extends {
|
|
55
|
+
paths: infer Paths;
|
|
56
|
+
} ? Paths extends Record<string, unknown> ? P extends keyof Paths ? Paths[P] extends Record<string, unknown> ? M extends keyof Paths[P] ? Paths[P][M] extends {
|
|
57
|
+
responses: infer R;
|
|
58
|
+
} ? R extends Record<string, unknown> ? string extends keyof R ? string : Extract<keyof R, string> : string : string : string : string : string : string : string;
|
|
59
|
+
/**
|
|
60
|
+
* Extract the content-type keys declared on a request body's
|
|
61
|
+
* `content` map for the given path and method. Runtime documents
|
|
62
|
+
* widen to `string`.
|
|
63
|
+
*/
|
|
64
|
+
type RequestContentTypesOf<D, P extends string, M extends string> = D extends {
|
|
65
|
+
paths: infer Paths;
|
|
66
|
+
} ? Paths extends Record<string, unknown> ? P extends keyof Paths ? Paths[P] extends Record<string, unknown> ? M extends keyof Paths[P] ? Paths[P][M] extends {
|
|
67
|
+
requestBody: {
|
|
68
|
+
content: infer C;
|
|
69
|
+
};
|
|
70
|
+
} ? C extends Record<string, unknown> ? string extends keyof C ? string : Extract<keyof C, string> : string : string : string : string : string : string : string;
|
|
71
|
+
/**
|
|
72
|
+
* Extract the content-type keys declared on a response entry's
|
|
73
|
+
* `content` map for the given path, method, and status. Runtime
|
|
74
|
+
* documents widen to `string`.
|
|
75
|
+
*/
|
|
76
|
+
type ResponseContentTypesOf<D, P extends string, M extends string, S extends string> = D extends {
|
|
77
|
+
paths: infer Paths;
|
|
78
|
+
} ? Paths extends Record<string, unknown> ? P extends keyof Paths ? Paths[P] extends Record<string, unknown> ? M extends keyof Paths[P] ? Paths[P][M] extends {
|
|
79
|
+
responses: infer R;
|
|
80
|
+
} ? R extends Record<string, unknown> ? S extends keyof R ? R[S] extends {
|
|
81
|
+
content: infer C;
|
|
82
|
+
} ? C extends Record<string, unknown> ? string extends keyof C ? string : Extract<keyof C, string> : string : string : string : string : string : string : string : string : string : string;
|
|
8
83
|
/**
|
|
9
84
|
* Diagnostics props accepted by every top-level OpenAPI component.
|
|
10
85
|
*
|
|
@@ -18,7 +93,7 @@ interface ApiDiagnosticsProps {
|
|
|
18
93
|
onDiagnostic?: DiagnosticSink;
|
|
19
94
|
strict?: boolean;
|
|
20
95
|
}
|
|
21
|
-
interface ApiOperationProps<Doc = unknown, Path extends
|
|
96
|
+
interface ApiOperationProps<Doc = unknown, Path extends PathKeysOf<Doc> = PathKeysOf<Doc>, Method extends MethodKeysOf<Doc, Path> = MethodKeysOf<Doc, Path>> extends ApiDiagnosticsProps {
|
|
22
97
|
schema: Doc;
|
|
23
98
|
path: Path;
|
|
24
99
|
method: Method;
|
|
@@ -26,7 +101,7 @@ interface ApiOperationProps<Doc = unknown, Path extends string = string, Method
|
|
|
26
101
|
onRequestBodyChange?: (value: unknown) => void;
|
|
27
102
|
responseValue?: unknown;
|
|
28
103
|
meta?: SchemaMeta;
|
|
29
|
-
requestBodyFields?: Doc extends Record<string, unknown> ? InferRequestBodyFields<Doc, Path, Method> : Record<string, FieldOverride>;
|
|
104
|
+
requestBodyFields?: Doc extends Record<string, unknown> ? InferRequestBodyFields<Doc, Path & string, Method & string> : Record<string, FieldOverride>;
|
|
30
105
|
/** Escape hatch for recursive schemas where type-level inference fails.
|
|
31
106
|
* Typed as Record<string, FieldOverride> — use when the schema contains
|
|
32
107
|
* deeply nested $ref chains.
|
|
@@ -35,7 +110,7 @@ interface ApiOperationProps<Doc = unknown, Path extends string = string, Method
|
|
|
35
110
|
/** Instance-scoped widgets. */
|
|
36
111
|
widgets?: WidgetMap;
|
|
37
112
|
}
|
|
38
|
-
declare function ApiOperation<Doc = unknown, Path extends
|
|
113
|
+
declare function ApiOperation<Doc = unknown, Path extends PathKeysOf<Doc> = PathKeysOf<Doc>, Method extends MethodKeysOf<Doc, Path> = MethodKeysOf<Doc, Path>>({
|
|
39
114
|
schema: doc,
|
|
40
115
|
path,
|
|
41
116
|
method,
|
|
@@ -48,16 +123,16 @@ declare function ApiOperation<Doc = unknown, Path extends string = string, Metho
|
|
|
48
123
|
onDiagnostic,
|
|
49
124
|
strict
|
|
50
125
|
}: ApiOperationProps<Doc, Path, Method>): ReactNode;
|
|
51
|
-
interface ApiParametersProps<Doc = unknown, Path extends
|
|
126
|
+
interface ApiParametersProps<Doc = unknown, Path extends PathKeysOf<Doc> = PathKeysOf<Doc>, Method extends MethodKeysOf<Doc, Path> = MethodKeysOf<Doc, Path>> extends ApiDiagnosticsProps {
|
|
52
127
|
schema: Doc;
|
|
53
128
|
path: Path;
|
|
54
129
|
method: Method;
|
|
55
130
|
meta?: SchemaMeta;
|
|
56
|
-
overrides?: Doc extends Record<string, unknown> ? InferParameterOverrides<Doc, Path, Method> : Record<string, FieldOverride>;
|
|
131
|
+
overrides?: Doc extends Record<string, unknown> ? InferParameterOverrides<Doc, Path & string, Method & string> : Record<string, FieldOverride>;
|
|
57
132
|
/** Instance-scoped widgets. */
|
|
58
133
|
widgets?: WidgetMap;
|
|
59
134
|
}
|
|
60
|
-
declare function ApiParameters<Doc = unknown, Path extends
|
|
135
|
+
declare function ApiParameters<Doc = unknown, Path extends PathKeysOf<Doc> = PathKeysOf<Doc>, Method extends MethodKeysOf<Doc, Path> = MethodKeysOf<Doc, Path>>({
|
|
61
136
|
schema: doc,
|
|
62
137
|
path,
|
|
63
138
|
method,
|
|
@@ -67,18 +142,25 @@ declare function ApiParameters<Doc = unknown, Path extends string = string, Meth
|
|
|
67
142
|
onDiagnostic,
|
|
68
143
|
strict
|
|
69
144
|
}: ApiParametersProps<Doc, Path, Method>): ReactNode;
|
|
70
|
-
interface ApiRequestBodyProps<Doc = unknown, Path extends
|
|
145
|
+
interface ApiRequestBodyProps<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 {
|
|
71
146
|
schema: Doc;
|
|
72
147
|
path: Path;
|
|
73
148
|
method: Method;
|
|
149
|
+
/**
|
|
150
|
+
* Media type whose schema should be rendered for the request body.
|
|
151
|
+
* Defaults to the union of declared content types so callers can
|
|
152
|
+
* omit it; supply explicitly to narrow `fields` inference to a
|
|
153
|
+
* specific media type via {@link InferRequestBodyFields}.
|
|
154
|
+
*/
|
|
155
|
+
contentType?: ContentType;
|
|
74
156
|
value?: unknown;
|
|
75
157
|
onChange?: (value: unknown) => void;
|
|
76
158
|
meta?: SchemaMeta;
|
|
77
|
-
fields?: Doc extends Record<string, unknown> ? InferRequestBodyFields<Doc, Path, Method> : Record<string, FieldOverride>;
|
|
159
|
+
fields?: Doc extends Record<string, unknown> ? InferRequestBodyFields<Doc, Path & string, Method & string, ContentType & string> : Record<string, FieldOverride>;
|
|
78
160
|
/** Instance-scoped widgets. */
|
|
79
161
|
widgets?: WidgetMap;
|
|
80
162
|
}
|
|
81
|
-
declare function ApiRequestBody<Doc = unknown, Path extends
|
|
163
|
+
declare function ApiRequestBody<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>>({
|
|
82
164
|
schema: doc,
|
|
83
165
|
path,
|
|
84
166
|
method,
|
|
@@ -89,19 +171,26 @@ declare function ApiRequestBody<Doc = unknown, Path extends string = string, Met
|
|
|
89
171
|
widgets,
|
|
90
172
|
onDiagnostic,
|
|
91
173
|
strict
|
|
92
|
-
}: ApiRequestBodyProps<Doc, Path, Method>): ReactNode;
|
|
93
|
-
interface ApiResponseProps<Doc = unknown, Path extends
|
|
174
|
+
}: ApiRequestBodyProps<Doc, Path, Method, ContentType>): ReactNode;
|
|
175
|
+
interface ApiResponseProps<Doc = unknown, Path extends PathKeysOf<Doc> = PathKeysOf<Doc>, Method extends MethodKeysOf<Doc, Path> = MethodKeysOf<Doc, Path>, Status extends StatusKeysOf<Doc, Path, Method> = StatusKeysOf<Doc, Path, Method>, ContentType extends ResponseContentTypesOf<Doc, Path, Method, Status> = ResponseContentTypesOf<Doc, Path, Method, Status>> extends ApiDiagnosticsProps {
|
|
94
176
|
schema: Doc;
|
|
95
177
|
path: Path;
|
|
96
178
|
method: Method;
|
|
97
179
|
status: Status;
|
|
180
|
+
/**
|
|
181
|
+
* Media type whose schema should be rendered. Defaults to the
|
|
182
|
+
* union of declared content types so callers can omit it;
|
|
183
|
+
* supply explicitly to narrow `fields` inference via
|
|
184
|
+
* {@link InferResponseFields}.
|
|
185
|
+
*/
|
|
186
|
+
contentType?: ContentType;
|
|
98
187
|
value?: unknown;
|
|
99
188
|
meta?: SchemaMeta;
|
|
100
|
-
fields?: Doc extends Record<string, unknown> ? InferResponseFields<Doc, Path, Method, Status> : Record<string, FieldOverride>;
|
|
189
|
+
fields?: Doc extends Record<string, unknown> ? InferResponseFields<Doc, Path & string, Method & string, Status & string, ContentType & string> : Record<string, FieldOverride>;
|
|
101
190
|
/** Instance-scoped widgets. */
|
|
102
191
|
widgets?: WidgetMap;
|
|
103
192
|
}
|
|
104
|
-
declare function ApiResponse<Doc = unknown, Path extends
|
|
193
|
+
declare function ApiResponse<Doc = unknown, Path extends PathKeysOf<Doc> = PathKeysOf<Doc>, Method extends MethodKeysOf<Doc, Path> = MethodKeysOf<Doc, Path>, Status extends StatusKeysOf<Doc, Path, Method> = StatusKeysOf<Doc, Path, Method>, ContentType extends ResponseContentTypesOf<Doc, Path, Method, Status> = ResponseContentTypesOf<Doc, Path, Method, Status>>({
|
|
105
194
|
schema: doc,
|
|
106
195
|
path,
|
|
107
196
|
method,
|
|
@@ -112,6 +201,49 @@ declare function ApiResponse<Doc = unknown, Path extends string = string, Method
|
|
|
112
201
|
widgets,
|
|
113
202
|
onDiagnostic,
|
|
114
203
|
strict
|
|
115
|
-
}: ApiResponseProps<Doc, Path, Method, Status>): ReactNode;
|
|
204
|
+
}: ApiResponseProps<Doc, Path, Method, Status, ContentType>): ReactNode;
|
|
205
|
+
/**
|
|
206
|
+
* Render a single OpenAPI 3.1 webhook by name. A webhook is a Path Item
|
|
207
|
+
* Object under the document's top-level `webhooks` map; once resolved,
|
|
208
|
+
* its operations are structurally identical to operations under `paths`.
|
|
209
|
+
*
|
|
210
|
+
* Internally, this delegates to `ApiOperation` for each method present
|
|
211
|
+
* on the webhook's Path Item Object. The parser's `lookupPathItem`
|
|
212
|
+
* resolves webhook names through the same code path as paths, so
|
|
213
|
+
* `ApiOperation` works for both with no special-casing in the renderer.
|
|
214
|
+
*/
|
|
215
|
+
interface ApiWebhookProps extends ApiDiagnosticsProps {
|
|
216
|
+
schema: unknown;
|
|
217
|
+
/** Webhook name (key under the document's `webhooks` map). */
|
|
218
|
+
name: string;
|
|
219
|
+
/** Instance-scoped widgets, forwarded to each rendered operation. */
|
|
220
|
+
widgets?: WidgetMap;
|
|
221
|
+
meta?: SchemaMeta;
|
|
222
|
+
}
|
|
223
|
+
declare function ApiWebhook({
|
|
224
|
+
schema: doc,
|
|
225
|
+
name,
|
|
226
|
+
widgets,
|
|
227
|
+
meta,
|
|
228
|
+
onDiagnostic,
|
|
229
|
+
strict
|
|
230
|
+
}: ApiWebhookProps): ReactNode;
|
|
231
|
+
/**
|
|
232
|
+
* Render every OpenAPI 3.1 webhook declared on the document, one
|
|
233
|
+
* `<ApiWebhook>` per entry. Returns `null` when the document has no
|
|
234
|
+
* `webhooks` map or it is empty.
|
|
235
|
+
*/
|
|
236
|
+
interface ApiWebhooksProps extends ApiDiagnosticsProps {
|
|
237
|
+
schema: unknown;
|
|
238
|
+
widgets?: WidgetMap;
|
|
239
|
+
meta?: SchemaMeta;
|
|
240
|
+
}
|
|
241
|
+
declare function ApiWebhooks({
|
|
242
|
+
schema: doc,
|
|
243
|
+
widgets,
|
|
244
|
+
meta,
|
|
245
|
+
onDiagnostic,
|
|
246
|
+
strict
|
|
247
|
+
}: ApiWebhooksProps): ReactNode;
|
|
116
248
|
//#endregion
|
|
117
|
-
export { ApiOperation, ApiOperationProps, ApiParameters, ApiParametersProps, ApiRequestBody, ApiRequestBodyProps, ApiResponse, ApiResponseProps };
|
|
249
|
+
export { ApiOperation, ApiOperationProps, ApiParameters, ApiParametersProps, ApiRequestBody, ApiRequestBodyProps, ApiResponse, ApiResponseProps, ApiWebhook, ApiWebhookProps, ApiWebhooks, ApiWebhooksProps };
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { isObject, toRecordOrUndefined } from "../core/guards.mjs";
|
|
2
|
+
import { emitDiagnostic } from "../core/diagnostics.mjs";
|
|
2
3
|
import { walk } from "../core/walker.mjs";
|
|
3
4
|
import { ApiCallbacks } from "./ApiCallbacks.mjs";
|
|
4
5
|
import { ApiLinks } from "./ApiLinks.mjs";
|
|
5
6
|
import { ApiResponseHeaders } from "./ApiResponseHeaders.mjs";
|
|
6
7
|
import { ApiSecurity } from "./ApiSecurity.mjs";
|
|
7
|
-
import { getLinks, getSecurityRequirements, getSecuritySchemes, listCallbacks } from "./parser.mjs";
|
|
8
|
+
import { getExternalDocs, getLinks, getSecurityRequirements, getSecuritySchemes, getXmlInfo, listCallbacks, listWebhooks } from "./parser.mjs";
|
|
8
9
|
import { joinPath, renderField, sanitisePrefix } from "../react/SchemaComponent.mjs";
|
|
9
10
|
import { getParsed, resolveOperationFromParsed, resolveParametersFromParsed, resolveRequestBodyFromParsed, resolveResponseFromParsed, toDoc } from "./resolve.mjs";
|
|
10
11
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -30,6 +31,25 @@ function buildDiagnostics(onDiagnostic, strict) {
|
|
|
30
31
|
if (strict === true) opts.strict = true;
|
|
31
32
|
return opts;
|
|
32
33
|
}
|
|
34
|
+
/**
|
|
35
|
+
* Coerce an `unknown` `schema` prop to a document record. Returns
|
|
36
|
+
* `undefined` when the prop is not a plain object, surfacing a
|
|
37
|
+
* `doc-not-object` diagnostic so silent "empty document" misbehaviour
|
|
38
|
+
* (the historic `toDoc` `{}` fallback) is impossible.
|
|
39
|
+
*
|
|
40
|
+
* Components MUST short-circuit when this returns `undefined` rather
|
|
41
|
+
* than rendering empty operation lists.
|
|
42
|
+
*/
|
|
43
|
+
function resolveRootDoc(doc, diagnostics) {
|
|
44
|
+
const resolved = toDoc(doc);
|
|
45
|
+
if (resolved === void 0) emitDiagnostic(diagnostics, {
|
|
46
|
+
code: "doc-not-object",
|
|
47
|
+
message: "OpenAPI document prop is not a plain object; nothing to render",
|
|
48
|
+
pointer: "",
|
|
49
|
+
detail: { received: typeof doc }
|
|
50
|
+
});
|
|
51
|
+
return resolved;
|
|
52
|
+
}
|
|
33
53
|
function noop() {}
|
|
34
54
|
function renderSchema(schema, rootDocument, options) {
|
|
35
55
|
if (!isObject(schema)) throw new Error("renderSchema received a non-object schema from the resolver.");
|
|
@@ -49,14 +69,55 @@ function renderSchema(schema, rootDocument, options) {
|
|
|
49
69
|
};
|
|
50
70
|
return renderField(tree, options.value, options.onChange ?? noop, void 0, makeRenderChild(options.rootPath), options.rootPath, options.widgets);
|
|
51
71
|
}
|
|
72
|
+
/**
|
|
73
|
+
* Render a Schema Object or Operation Object's `externalDocs` as a
|
|
74
|
+
* simple anchor with optional descriptive text. Returns `null` when no
|
|
75
|
+
* externalDocs are attached so callers can drop it into JSX without an
|
|
76
|
+
* extra guard.
|
|
77
|
+
*/
|
|
78
|
+
function ExternalDocsLink({ externalDocs }) {
|
|
79
|
+
if (externalDocs === void 0) return null;
|
|
80
|
+
return /* @__PURE__ */ jsx("p", {
|
|
81
|
+
"data-external-docs": true,
|
|
82
|
+
children: /* @__PURE__ */ jsx("a", {
|
|
83
|
+
href: externalDocs.url,
|
|
84
|
+
children: externalDocs.description ?? externalDocs.url
|
|
85
|
+
})
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Render a Schema Object's `xml` metadata as a footnote. The library
|
|
90
|
+
* does not render XML payloads natively, but the metadata still
|
|
91
|
+
* carries author intent (namespaces, element names, wrapping rules).
|
|
92
|
+
* Surface it so consumers can audit the dropped feature without
|
|
93
|
+
* losing the underlying information.
|
|
94
|
+
*/
|
|
95
|
+
function SchemaXmlFootnote({ xml }) {
|
|
96
|
+
if (xml === void 0) return null;
|
|
97
|
+
return /* @__PURE__ */ jsx("aside", {
|
|
98
|
+
"data-schema-xml": true,
|
|
99
|
+
children: /* @__PURE__ */ jsxs("small", { children: [
|
|
100
|
+
"XML representation",
|
|
101
|
+
xml.name !== void 0 && ` — name: ${xml.name}`,
|
|
102
|
+
xml.namespace !== void 0 && ` — namespace: ${xml.namespace}`,
|
|
103
|
+
xml.prefix !== void 0 && ` — prefix: ${xml.prefix}`,
|
|
104
|
+
xml.attribute && " — attribute",
|
|
105
|
+
xml.wrapped && " — wrapped"
|
|
106
|
+
] })
|
|
107
|
+
});
|
|
108
|
+
}
|
|
52
109
|
function ApiOperation({ schema: doc, path, method, requestBodyValue, onRequestBodyChange, responseValue, meta, requestBodyFields, widgets, onDiagnostic, strict }) {
|
|
53
|
-
const
|
|
54
|
-
const
|
|
55
|
-
const
|
|
110
|
+
const diagnostics = buildDiagnostics(onDiagnostic, strict);
|
|
111
|
+
const instancePrefix = sanitisePrefix(useId());
|
|
112
|
+
const rootDoc = resolveRootDoc(doc, diagnostics);
|
|
113
|
+
if (rootDoc === void 0) return null;
|
|
114
|
+
const parsed = getParsed(rootDoc, diagnostics);
|
|
115
|
+
const resolved = resolveOperationFromParsed(parsed, path, method, diagnostics);
|
|
56
116
|
const securityReqs = getSecurityRequirements(parsed, path, method);
|
|
57
117
|
const securitySchemes = getSecuritySchemes(parsed);
|
|
58
118
|
const callbacks = listCallbacks(parsed, path, method);
|
|
59
|
-
const
|
|
119
|
+
const operationExternalDocs = getExternalDocs(resolved.operation.operation);
|
|
120
|
+
const requestBodyXml = resolved.requestBody?.schema !== void 0 ? getXmlInfo(resolved.requestBody.schema) : void 0;
|
|
60
121
|
return /* @__PURE__ */ jsxs("section", {
|
|
61
122
|
"data-operation": `${method.toUpperCase()} ${path}`,
|
|
62
123
|
children: [
|
|
@@ -64,6 +125,7 @@ function ApiOperation({ schema: doc, path, method, requestBodyValue, onRequestBo
|
|
|
64
125
|
operation: resolved.operation,
|
|
65
126
|
pathItem: resolved.pathItem
|
|
66
127
|
}),
|
|
128
|
+
/* @__PURE__ */ jsx(ExternalDocsLink, { externalDocs: operationExternalDocs }),
|
|
67
129
|
/* @__PURE__ */ jsx(ApiSecurity, {
|
|
68
130
|
requirements: securityReqs,
|
|
69
131
|
schemes: securitySchemes
|
|
@@ -98,7 +160,8 @@ function ApiOperation({ schema: doc, path, method, requestBodyValue, onRequestBo
|
|
|
98
160
|
meta,
|
|
99
161
|
widgets,
|
|
100
162
|
rootPath: joinPath(instancePrefix, "requestBody")
|
|
101
|
-
})
|
|
163
|
+
}),
|
|
164
|
+
/* @__PURE__ */ jsx(SchemaXmlFootnote, { xml: requestBodyXml })
|
|
102
165
|
]
|
|
103
166
|
}),
|
|
104
167
|
resolved.responses.length > 0 && /* @__PURE__ */ jsxs("section", {
|
|
@@ -119,9 +182,11 @@ function ApiOperation({ schema: doc, path, method, requestBodyValue, onRequestBo
|
|
|
119
182
|
});
|
|
120
183
|
}
|
|
121
184
|
function ApiParameters({ schema: doc, path, method, meta, overrides, widgets, onDiagnostic, strict }) {
|
|
122
|
-
const
|
|
123
|
-
const params = resolveParametersFromParsed(getParsed(rootDoc, buildDiagnostics(onDiagnostic, strict)), path, method);
|
|
185
|
+
const diagnostics = buildDiagnostics(onDiagnostic, strict);
|
|
124
186
|
const instancePrefix = sanitisePrefix(useId());
|
|
187
|
+
const rootDoc = resolveRootDoc(doc, diagnostics);
|
|
188
|
+
if (rootDoc === void 0) return null;
|
|
189
|
+
const params = resolveParametersFromParsed(getParsed(rootDoc, diagnostics), path, method);
|
|
125
190
|
if (params.length === 0) return null;
|
|
126
191
|
return /* @__PURE__ */ jsxs("section", {
|
|
127
192
|
"data-parameters": true,
|
|
@@ -136,10 +201,13 @@ function ApiParameters({ schema: doc, path, method, meta, overrides, widgets, on
|
|
|
136
201
|
});
|
|
137
202
|
}
|
|
138
203
|
function ApiRequestBody({ schema: doc, path, method, value, onChange, meta, fields, widgets, onDiagnostic, strict }) {
|
|
139
|
-
const
|
|
140
|
-
const requestBody = resolveRequestBodyFromParsed(getParsed(rootDoc, buildDiagnostics(onDiagnostic, strict)), path, method);
|
|
204
|
+
const diagnostics = buildDiagnostics(onDiagnostic, strict);
|
|
141
205
|
const instancePrefix = sanitisePrefix(useId());
|
|
206
|
+
const rootDoc = resolveRootDoc(doc, diagnostics);
|
|
207
|
+
if (rootDoc === void 0) return null;
|
|
208
|
+
const requestBody = resolveRequestBodyFromParsed(getParsed(rootDoc, diagnostics), path, method);
|
|
142
209
|
if (requestBody?.schema === void 0) return null;
|
|
210
|
+
const requestBodyXml = getXmlInfo(requestBody.schema);
|
|
143
211
|
return /* @__PURE__ */ jsxs("section", {
|
|
144
212
|
"data-request-body": true,
|
|
145
213
|
children: [
|
|
@@ -159,15 +227,18 @@ function ApiRequestBody({ schema: doc, path, method, value, onChange, meta, fiel
|
|
|
159
227
|
meta,
|
|
160
228
|
widgets,
|
|
161
229
|
rootPath: instancePrefix
|
|
162
|
-
})
|
|
230
|
+
}),
|
|
231
|
+
/* @__PURE__ */ jsx(SchemaXmlFootnote, { xml: requestBodyXml })
|
|
163
232
|
]
|
|
164
233
|
});
|
|
165
234
|
}
|
|
166
235
|
function ApiResponse({ schema: doc, path, method, status, value, meta, fields, widgets, onDiagnostic, strict }) {
|
|
167
|
-
const
|
|
168
|
-
const parsed = getParsed(rootDoc, buildDiagnostics(onDiagnostic, strict));
|
|
169
|
-
const response = resolveResponseFromParsed(parsed, path, method, status);
|
|
236
|
+
const diagnostics = buildDiagnostics(onDiagnostic, strict);
|
|
170
237
|
const instancePrefix = sanitisePrefix(useId());
|
|
238
|
+
const rootDoc = resolveRootDoc(doc, diagnostics);
|
|
239
|
+
if (rootDoc === void 0) return null;
|
|
240
|
+
const parsed = getParsed(rootDoc, diagnostics);
|
|
241
|
+
const response = resolveResponseFromParsed(parsed, path, method, status);
|
|
171
242
|
if (response.schema === void 0) return /* @__PURE__ */ jsxs("div", {
|
|
172
243
|
"data-status": status,
|
|
173
244
|
children: [
|
|
@@ -189,6 +260,49 @@ function ApiResponse({ schema: doc, path, method, status, value, meta, fields, w
|
|
|
189
260
|
idPrefix: instancePrefix
|
|
190
261
|
});
|
|
191
262
|
}
|
|
263
|
+
function ApiWebhook({ schema: doc, name, widgets, meta, onDiagnostic, strict }) {
|
|
264
|
+
const diagnostics = buildDiagnostics(onDiagnostic, strict);
|
|
265
|
+
const instancePrefix = sanitisePrefix(useId());
|
|
266
|
+
const rootDoc = resolveRootDoc(doc, diagnostics);
|
|
267
|
+
if (rootDoc === void 0) return null;
|
|
268
|
+
const webhook = listWebhooks(getParsed(rootDoc, diagnostics)).find((w) => w.name === name);
|
|
269
|
+
if (webhook === void 0) return null;
|
|
270
|
+
return /* @__PURE__ */ jsxs("section", {
|
|
271
|
+
"data-webhook": name,
|
|
272
|
+
"data-instance": instancePrefix,
|
|
273
|
+
children: [/* @__PURE__ */ jsxs("h3", { children: ["Webhook: ", name] }), webhook.operations.map((op) => {
|
|
274
|
+
const opProps = {
|
|
275
|
+
schema: rootDoc,
|
|
276
|
+
path: name,
|
|
277
|
+
method: op.method
|
|
278
|
+
};
|
|
279
|
+
if (widgets !== void 0) opProps.widgets = widgets;
|
|
280
|
+
if (meta !== void 0) opProps.meta = meta;
|
|
281
|
+
return /* @__PURE__ */ jsx(ApiOperation, { ...opProps }, `${name}-${op.method}`);
|
|
282
|
+
})]
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
function ApiWebhooks({ schema: doc, widgets, meta, onDiagnostic, strict }) {
|
|
286
|
+
const diagnostics = buildDiagnostics(onDiagnostic, strict);
|
|
287
|
+
const instancePrefix = sanitisePrefix(useId());
|
|
288
|
+
const rootDoc = resolveRootDoc(doc, diagnostics);
|
|
289
|
+
if (rootDoc === void 0) return null;
|
|
290
|
+
const webhooks = listWebhooks(getParsed(rootDoc, diagnostics));
|
|
291
|
+
if (webhooks.length === 0) return null;
|
|
292
|
+
return /* @__PURE__ */ jsxs("section", {
|
|
293
|
+
"data-webhooks": true,
|
|
294
|
+
"data-instance": instancePrefix,
|
|
295
|
+
children: [/* @__PURE__ */ jsx("h2", { children: "Webhooks" }), webhooks.map((webhook) => {
|
|
296
|
+
const props = {
|
|
297
|
+
schema: rootDoc,
|
|
298
|
+
name: webhook.name
|
|
299
|
+
};
|
|
300
|
+
if (widgets !== void 0) props.widgets = widgets;
|
|
301
|
+
if (meta !== void 0) props.meta = meta;
|
|
302
|
+
return /* @__PURE__ */ jsx(ApiWebhook, { ...props }, webhook.name);
|
|
303
|
+
})]
|
|
304
|
+
});
|
|
305
|
+
}
|
|
192
306
|
function OperationHeader({ operation, pathItem }) {
|
|
193
307
|
return /* @__PURE__ */ jsxs("header", { children: [
|
|
194
308
|
(pathItem.summary !== void 0 || pathItem.description !== void 0) && /* @__PURE__ */ jsxs("div", {
|
|
@@ -293,4 +407,4 @@ function extractRootMetaFromSchema(jsonSchema) {
|
|
|
293
407
|
return Object.keys(meta).length > 0 ? meta : void 0;
|
|
294
408
|
}
|
|
295
409
|
//#endregion
|
|
296
|
-
export { ApiOperation, ApiParameters, ApiRequestBody, ApiResponse };
|
|
410
|
+
export { ApiOperation, ApiParameters, ApiRequestBody, ApiResponse, ApiWebhook, ApiWebhooks };
|
package/dist/openapi/parser.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { getProperty, isObject } from "../core/guards.mjs";
|
|
2
|
+
import "../core/limits.mjs";
|
|
2
3
|
import { isPrototypePollutingKey } from "../core/uri.mjs";
|
|
3
4
|
//#region src/openapi/parser.ts
|
|
4
5
|
function getString(value, key) {
|
|
@@ -44,11 +45,27 @@ const METHODS = [
|
|
|
44
45
|
* (OpenAPI 3.1) if present. Returns `undefined` when the value is not a
|
|
45
46
|
* path item, the ref is malformed, or the target does not resolve.
|
|
46
47
|
*/
|
|
48
|
+
/**
|
|
49
|
+
* Follow Path Item Object `$ref` chains (up to MAX_PATH_ITEM_REF_HOPS).
|
|
50
|
+
* Returns the resolved Path Item, or `undefined` when the chain cycles,
|
|
51
|
+
* exceeds the cap, or any intermediate ref fails to resolve. The
|
|
52
|
+
* detailed diagnostics for cycle and depth-cap are emitted by the
|
|
53
|
+
* mirroring resolver in `resolve.ts` — this parser-side resolver simply
|
|
54
|
+
* stops walking.
|
|
55
|
+
*/
|
|
47
56
|
function resolvePathItem(parsed, pathItem) {
|
|
48
57
|
if (!isObject(pathItem)) return void 0;
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
|
|
58
|
+
const visited = /* @__PURE__ */ new Set();
|
|
59
|
+
let current = pathItem;
|
|
60
|
+
for (let hop = 0; hop < 8; hop++) {
|
|
61
|
+
const ref = getString(current, "$ref");
|
|
62
|
+
if (ref === void 0) return current;
|
|
63
|
+
if (visited.has(ref)) return void 0;
|
|
64
|
+
visited.add(ref);
|
|
65
|
+
const target = resolveRefInDoc(parsed.doc, ref);
|
|
66
|
+
if (target === void 0) return void 0;
|
|
67
|
+
current = target;
|
|
68
|
+
}
|
|
52
69
|
}
|
|
53
70
|
function lookupPathItem(parsed, path) {
|
|
54
71
|
const resolved = resolvePathItem(parsed, getProperty(getProperty(parsed.doc, "paths"), path));
|
|
@@ -202,6 +219,21 @@ function isJsonSuffixMediaType(mediaType) {
|
|
|
202
219
|
const baseType = lower.split(";", 1)[0]?.trim() ?? "";
|
|
203
220
|
return baseType.startsWith("application/") && baseType.endsWith("+json");
|
|
204
221
|
}
|
|
222
|
+
/**
|
|
223
|
+
* Resolve an in-document `$ref` against the supplied doc root.
|
|
224
|
+
*
|
|
225
|
+
* Limitation — cross-Schema-Object relative refs: refs that do NOT
|
|
226
|
+
* start with `#/` are not resolved here. The `normaliseOpenApiSchemas`
|
|
227
|
+
* pipeline (see `resolveRelativeRefs` in `core/normalise.ts`) rewrites
|
|
228
|
+
* relative refs WITHIN a Schema Object using that schema's `$id` base
|
|
229
|
+
* URI, but it does not currently model `$id` scopes that span Schema
|
|
230
|
+
* Object boundaries (e.g. a sibling component schema with its own
|
|
231
|
+
* `$id` that another schema's relative ref targets). Such refs survive
|
|
232
|
+
* normalisation unchanged and fall through this function returning
|
|
233
|
+
* `undefined`. `resolve.ts:detectUnsupportedCrossSchemaRefs` walks the
|
|
234
|
+
* normalised doc and emits `cross-schema-relative-ref-unsupported` per
|
|
235
|
+
* offending ref so consumers notice the silent failure.
|
|
236
|
+
*/
|
|
205
237
|
function resolveRefInDoc(doc, ref) {
|
|
206
238
|
if (!ref.startsWith("#/")) return void 0;
|
|
207
239
|
const parts = ref.slice(2).split("/");
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { i as DiagnosticsOptions } from "../diagnostics-
|
|
1
|
+
import { i as DiagnosticsOptions } from "../diagnostics-D0QCYGv0.mjs";
|
|
2
2
|
import { OpenApiDocument, OperationInfo, ParameterInfo, ResponseInfo, getRequestBody } from "./parser.mjs";
|
|
3
3
|
|
|
4
4
|
//#region src/openapi/resolve.d.ts
|
|
@@ -29,10 +29,17 @@ import { OpenApiDocument, OperationInfo, ParameterInfo, ResponseInfo, getRequest
|
|
|
29
29
|
*/
|
|
30
30
|
declare function getParsed(doc: Record<string, unknown>, diagnostics?: DiagnosticsOptions): OpenApiDocument;
|
|
31
31
|
/**
|
|
32
|
-
* Coerce an unknown value to a record, returning
|
|
33
|
-
*
|
|
32
|
+
* Coerce an unknown value to a record, returning `undefined` when the
|
|
33
|
+
* value is not a plain object. Callers MUST handle the `undefined` case
|
|
34
|
+
* explicitly — typically by rendering a "doc not an object" diagnostic
|
|
35
|
+
* and short-circuiting, never by silently substituting `{}`.
|
|
36
|
+
*
|
|
37
|
+
* A previous implementation fell back to `{}` for non-objects, which
|
|
38
|
+
* masked configuration mistakes (passing a string, `null`, an array, or
|
|
39
|
+
* `undefined` as the OpenAPI document) as an empty document with no
|
|
40
|
+
* operations.
|
|
34
41
|
*/
|
|
35
|
-
declare function toDoc(value: unknown): Record<string, unknown
|
|
42
|
+
declare function toDoc(value: unknown): Record<string, unknown> | undefined;
|
|
36
43
|
/**
|
|
37
44
|
* Path-Item-level metadata. OpenAPI 3.1 added `summary` and `description`
|
|
38
45
|
* to Path Item Objects alongside the existing operation-level fields.
|
|
@@ -59,7 +66,7 @@ interface ResolvedOperation {
|
|
|
59
66
|
* normalisation pipeline (every re-run would emit each diagnostic
|
|
60
67
|
* again into the sink).
|
|
61
68
|
*/
|
|
62
|
-
declare function resolveOperationFromParsed(parsed: OpenApiDocument, path: string, method: string): ResolvedOperation;
|
|
69
|
+
declare function resolveOperationFromParsed(parsed: OpenApiDocument, path: string, method: string, diagnostics?: DiagnosticsOptions): ResolvedOperation;
|
|
63
70
|
/**
|
|
64
71
|
* Resolve an operation from an OpenAPI document by path and method.
|
|
65
72
|
* Throws if the operation is not found.
|