schema-components 1.20.0 → 1.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/dist/core/adapter.d.mts +9 -2
  2. package/dist/core/adapter.mjs +220 -64
  3. package/dist/core/constraints.d.mts +1 -1
  4. package/dist/core/constraints.mjs +0 -2
  5. package/dist/core/errors.d.mts +1 -1
  6. package/dist/core/errors.mjs +9 -15
  7. package/dist/core/fieldOrder.d.mts +1 -1
  8. package/dist/core/merge.d.mts +10 -1
  9. package/dist/core/merge.mjs +11 -0
  10. package/dist/core/normalise.d.mts +7 -1
  11. package/dist/core/normalise.mjs +1 -1
  12. package/dist/core/openapi30.d.mts +24 -1
  13. package/dist/core/openapi30.mjs +2 -2
  14. package/dist/core/ref.d.mts +1 -1
  15. package/dist/core/ref.mjs +34 -9
  16. package/dist/core/renderer.d.mts +1 -1
  17. package/dist/core/swagger2.mjs +1 -1
  18. package/dist/core/typeInference.d.mts +1 -1
  19. package/dist/core/types.d.mts +1 -1
  20. package/dist/core/walkBuilders.d.mts +12 -4
  21. package/dist/core/walkBuilders.mjs +11 -3
  22. package/dist/core/walker.d.mts +1 -1
  23. package/dist/core/walker.mjs +32 -25
  24. package/dist/{errors-C2iABcn9.d.mts → errors-QEwOtQAA.d.mts} +7 -11
  25. package/dist/html/a11y.d.mts +2 -2
  26. package/dist/html/renderToHtml.d.mts +2 -2
  27. package/dist/html/renderToHtmlStream.d.mts +2 -2
  28. package/dist/html/renderers.d.mts +2 -2
  29. package/dist/html/renderers.mjs +1 -1
  30. package/dist/html/streamRenderers.d.mts +2 -2
  31. package/dist/{normalise-CMMEl4cd.mjs → normalise-DaSrnr8g.mjs} +325 -28
  32. package/dist/openapi/ApiCallbacks.d.mts +1 -1
  33. package/dist/openapi/ApiLinks.d.mts +1 -1
  34. package/dist/openapi/ApiResponseHeaders.d.mts +1 -1
  35. package/dist/openapi/ApiSecurity.d.mts +1 -1
  36. package/dist/openapi/ApiSecurity.mjs +113 -7
  37. package/dist/openapi/components.d.mts +32 -10
  38. package/dist/openapi/components.mjs +22 -12
  39. package/dist/openapi/parser.d.mts +1 -1
  40. package/dist/openapi/parser.mjs +39 -4
  41. package/dist/openapi/resolve.d.mts +60 -9
  42. package/dist/openapi/resolve.mjs +86 -23
  43. package/dist/react/SchemaComponent.d.mts +4 -4
  44. package/dist/react/SchemaComponent.mjs +32 -4
  45. package/dist/react/SchemaView.d.mts +2 -2
  46. package/dist/react/fieldPath.d.mts +1 -1
  47. package/dist/react/headless.d.mts +1 -1
  48. package/dist/react/headlessRenderers.d.mts +2 -2
  49. package/dist/react/headlessRenderers.mjs +1 -1
  50. package/dist/{ref-C8JbwfiS.d.mts → ref-si8ViYun.d.mts} +6 -1
  51. package/dist/{renderer-SOIbJBtk.d.mts → renderer-DI6ZYf7a.d.mts} +1 -1
  52. package/dist/themes/mantine.d.mts +1 -1
  53. package/dist/themes/mui.d.mts +1 -1
  54. package/dist/themes/radix.d.mts +1 -1
  55. package/dist/themes/shadcn.d.mts +1 -1
  56. package/dist/{typeInference-CDoD_LZ_.d.mts → typeInference-Bxw3NOG1.d.mts} +162 -48
  57. package/dist/{types-C9zw9wbX.d.mts → types-BnxPEElk.d.mts} +12 -2
  58. package/package.json +1 -1
@@ -6,7 +6,7 @@ import { ApiResponseHeaders } from "./ApiResponseHeaders.mjs";
6
6
  import { ApiSecurity } from "./ApiSecurity.mjs";
7
7
  import { getLinks, getSecurityRequirements, getSecuritySchemes, listCallbacks } from "./parser.mjs";
8
8
  import { joinPath, renderField, sanitisePrefix } from "../react/SchemaComponent.mjs";
9
- import { getParsed, resolveOperation, resolveParameters, resolveRequestBody, resolveResponse, toDoc } from "./resolve.mjs";
9
+ import { getParsed, resolveOperationFromParsed, resolveParametersFromParsed, resolveRequestBodyFromParsed, resolveResponseFromParsed, toDoc } from "./resolve.mjs";
10
10
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
11
11
  import { useId } from "react";
12
12
  //#region src/openapi/components.tsx
@@ -23,6 +23,13 @@ import { useId } from "react";
23
23
  * rendered via the walker + headless resolver directly, bypassing
24
24
  * SchemaComponent to avoid deferred-conditional-type compatibility issues.
25
25
  */
26
+ function buildDiagnostics(onDiagnostic, strict) {
27
+ if (onDiagnostic === void 0 && strict !== true) return void 0;
28
+ const opts = {};
29
+ if (onDiagnostic !== void 0) opts.diagnostics = onDiagnostic;
30
+ if (strict === true) opts.strict = true;
31
+ return opts;
32
+ }
26
33
  function noop() {}
27
34
  function renderSchema(schema, rootDocument, options) {
28
35
  if (!isObject(schema)) throw new Error("renderSchema received a non-object schema from the resolver.");
@@ -42,10 +49,10 @@ function renderSchema(schema, rootDocument, options) {
42
49
  };
43
50
  return renderField(tree, options.value, options.onChange ?? noop, void 0, makeRenderChild(options.rootPath), options.rootPath, options.widgets);
44
51
  }
45
- function ApiOperation({ schema: doc, path, method, requestBodyValue, onRequestBodyChange, responseValue, meta, requestBodyFields, widgets }) {
52
+ function ApiOperation({ schema: doc, path, method, requestBodyValue, onRequestBodyChange, responseValue, meta, requestBodyFields, widgets, onDiagnostic, strict }) {
46
53
  const rootDoc = toDoc(doc);
47
- const resolved = resolveOperation(rootDoc, path, method);
48
- const parsed = getParsed(rootDoc);
54
+ const parsed = getParsed(rootDoc, buildDiagnostics(onDiagnostic, strict));
55
+ const resolved = resolveOperationFromParsed(parsed, path, method);
49
56
  const securityReqs = getSecurityRequirements(parsed, path, method);
50
57
  const securitySchemes = getSecuritySchemes(parsed);
51
58
  const callbacks = listCallbacks(parsed, path, method);
@@ -99,6 +106,7 @@ function ApiOperation({ schema: doc, path, method, requestBodyValue, onRequestBo
99
106
  children: [/* @__PURE__ */ jsx("h4", { children: "Responses" }), resolved.responses.map((response) => /* @__PURE__ */ jsx(ResponseCard, {
100
107
  response,
101
108
  rootDoc,
109
+ parsed,
102
110
  value: responseValue,
103
111
  meta,
104
112
  widgets,
@@ -110,9 +118,9 @@ function ApiOperation({ schema: doc, path, method, requestBodyValue, onRequestBo
110
118
  ]
111
119
  });
112
120
  }
113
- function ApiParameters({ schema: doc, path, method, meta, overrides, widgets }) {
121
+ function ApiParameters({ schema: doc, path, method, meta, overrides, widgets, onDiagnostic, strict }) {
114
122
  const rootDoc = toDoc(doc);
115
- const params = resolveParameters(rootDoc, path, method);
123
+ const params = resolveParametersFromParsed(getParsed(rootDoc, buildDiagnostics(onDiagnostic, strict)), path, method);
116
124
  const instancePrefix = sanitisePrefix(useId());
117
125
  if (params.length === 0) return null;
118
126
  return /* @__PURE__ */ jsxs("section", {
@@ -127,9 +135,9 @@ function ApiParameters({ schema: doc, path, method, meta, overrides, widgets })
127
135
  })]
128
136
  });
129
137
  }
130
- function ApiRequestBody({ schema: doc, path, method, value, onChange, meta, fields, widgets }) {
138
+ function ApiRequestBody({ schema: doc, path, method, value, onChange, meta, fields, widgets, onDiagnostic, strict }) {
131
139
  const rootDoc = toDoc(doc);
132
- const requestBody = resolveRequestBody(rootDoc, path, method);
140
+ const requestBody = resolveRequestBodyFromParsed(getParsed(rootDoc, buildDiagnostics(onDiagnostic, strict)), path, method);
133
141
  const instancePrefix = sanitisePrefix(useId());
134
142
  if (requestBody?.schema === void 0) return null;
135
143
  return /* @__PURE__ */ jsxs("section", {
@@ -155,9 +163,10 @@ function ApiRequestBody({ schema: doc, path, method, value, onChange, meta, fiel
155
163
  ]
156
164
  });
157
165
  }
158
- function ApiResponse({ schema: doc, path, method, status, value, meta, fields, widgets }) {
166
+ function ApiResponse({ schema: doc, path, method, status, value, meta, fields, widgets, onDiagnostic, strict }) {
159
167
  const rootDoc = toDoc(doc);
160
- const response = resolveResponse(rootDoc, path, method, status);
168
+ const parsed = getParsed(rootDoc, buildDiagnostics(onDiagnostic, strict));
169
+ const response = resolveResponseFromParsed(parsed, path, method, status);
161
170
  const instancePrefix = sanitisePrefix(useId());
162
171
  if (response.schema === void 0) return /* @__PURE__ */ jsxs("div", {
163
172
  "data-status": status,
@@ -170,6 +179,7 @@ function ApiResponse({ schema: doc, path, method, status, value, meta, fields, w
170
179
  return /* @__PURE__ */ jsx(ResponseCard, {
171
180
  response,
172
181
  rootDoc,
182
+ parsed,
173
183
  value,
174
184
  fields,
175
185
  meta,
@@ -227,7 +237,7 @@ function ParameterList({ parameters, rootDoc, overrides, meta, widgets, idPrefix
227
237
  ]
228
238
  }, param.name)) });
229
239
  }
230
- function ResponseCard({ response, rootDoc, value, fields, meta, widgets, path, method, idPrefix }) {
240
+ function ResponseCard({ response, rootDoc, parsed, value, fields, meta, widgets, path, method, idPrefix }) {
231
241
  if (response.schema === void 0) return /* @__PURE__ */ jsxs("div", {
232
242
  "data-status": response.statusCode,
233
243
  children: [
@@ -237,7 +247,7 @@ function ResponseCard({ response, rootDoc, value, fields, meta, widgets, path, m
237
247
  ]
238
248
  });
239
249
  let links = [];
240
- if (path !== void 0 && method !== void 0) links = getLinks(getParsed(rootDoc), path, method, response.statusCode);
250
+ if (path !== void 0 && method !== void 0) links = getLinks(parsed, path, method, response.statusCode);
241
251
  return /* @__PURE__ */ jsxs("div", {
242
252
  "data-status": response.statusCode,
243
253
  children: [
@@ -1,4 +1,4 @@
1
- import { m as JsonObject } from "../types-C9zw9wbX.mjs";
1
+ import { m as JsonObject } from "../types-BnxPEElk.mjs";
2
2
 
3
3
  //#region src/openapi/parser.d.ts
4
4
  interface OpenApiDocument {
@@ -120,8 +120,10 @@ function resolveParam(doc, param) {
120
120
  return param;
121
121
  }
122
122
  function getRequestBody(parsed, path, method) {
123
- const requestBody = getProperty(getProperty(lookupPathItem(parsed, path), method), "requestBody");
124
- if (!isObject(requestBody)) return void 0;
123
+ const requestBodyRaw = getProperty(getProperty(lookupPathItem(parsed, path), method), "requestBody");
124
+ if (!isObject(requestBodyRaw)) return void 0;
125
+ const requestBody = resolveWrapperRef(parsed.doc, requestBodyRaw);
126
+ if (requestBody === void 0) return void 0;
125
127
  const content = getProperty(requestBody, "content");
126
128
  if (!isObject(content)) return {
127
129
  required: getProperty(requestBody, "required") === true,
@@ -142,8 +144,10 @@ function getResponses(parsed, path, method) {
142
144
  const responses = getProperty(getProperty(lookupPathItem(parsed, path), method), "responses");
143
145
  if (!isObject(responses)) return [];
144
146
  const result = [];
145
- for (const [statusCode, response] of Object.entries(responses)) {
146
- if (!isObject(response)) continue;
147
+ for (const [statusCode, responseRaw] of Object.entries(responses)) {
148
+ if (!isObject(responseRaw)) continue;
149
+ const response = resolveWrapperRef(parsed.doc, responseRaw);
150
+ if (response === void 0) continue;
147
151
  const content = getProperty(response, "content");
148
152
  const contentTypes = isObject(content) ? Object.keys(content) : [];
149
153
  const schema = isObject(content) ? extractSchemaFromContent(content) : void 0;
@@ -158,15 +162,46 @@ function getResponses(parsed, path, method) {
158
162
  }
159
163
  return result;
160
164
  }
165
+ /**
166
+ * Resolve a single-hop `$ref` on a wrapper object — Response Object,
167
+ * Request Body Object, etc. — against the document root. Returns the
168
+ * referenced node when the wrapper is a `$ref`, the wrapper itself when
169
+ * it has no `$ref`, or `undefined` when the `$ref` is malformed or
170
+ * cannot be resolved (so the caller skips the entry rather than reading
171
+ * stale fields from the bare `{ $ref }` envelope).
172
+ */
173
+ function resolveWrapperRef(doc, wrapper) {
174
+ const ref = getString(wrapper, "$ref");
175
+ if (ref === void 0) return wrapper;
176
+ return resolveRefInDoc(doc, ref);
177
+ }
161
178
  function extractSchemaFromContent(content) {
162
179
  const jsonSchema = getProperty(getProperty(content, "application/json"), "schema");
163
180
  if (isObject(jsonSchema)) return jsonSchema;
181
+ for (const [mediaType, mediaObj] of Object.entries(content)) {
182
+ if (!isJsonSuffixMediaType(mediaType)) continue;
183
+ if (!isObject(mediaObj)) continue;
184
+ const schema = getProperty(mediaObj, "schema");
185
+ if (isObject(schema)) return schema;
186
+ }
164
187
  for (const mediaType of Object.values(content)) {
165
188
  if (!isObject(mediaType)) continue;
166
189
  const schema = getProperty(mediaType, "schema");
167
190
  if (isObject(schema)) return schema;
168
191
  }
169
192
  }
193
+ /**
194
+ * Detect RFC 6839 structured-syntax-suffix media types that encode JSON.
195
+ * Matches `application/<anything>+json`, optionally with parameters
196
+ * (`; charset=utf-8`). Excludes the literal `application/json`, which
197
+ * the caller checks separately to preserve preference order.
198
+ */
199
+ function isJsonSuffixMediaType(mediaType) {
200
+ const lower = mediaType.toLowerCase();
201
+ if (lower === "application/json") return false;
202
+ const baseType = lower.split(";", 1)[0]?.trim() ?? "";
203
+ return baseType.startsWith("application/") && baseType.endsWith("+json");
204
+ }
170
205
  function resolveRefInDoc(doc, ref) {
171
206
  if (!ref.startsWith("#/")) return void 0;
172
207
  const parts = ref.slice(2).split("/");
@@ -1,3 +1,4 @@
1
+ import { i as DiagnosticsOptions } from "../diagnostics-CbBPsxSt.mjs";
1
2
  import { OpenApiDocument, OperationInfo, ParameterInfo, ResponseInfo, getRequestBody } from "./parser.mjs";
2
3
 
3
4
  //#region src/openapi/resolve.d.ts
@@ -14,10 +15,19 @@ import { OpenApiDocument, OperationInfo, ParameterInfo, ResponseInfo, getRequest
14
15
  * same form `<SchemaComponent>` does, keeping the OpenAPI components on
15
16
  * the same pipeline as the top-level adapter.
16
17
  *
17
- * The cache is keyed by the caller-supplied document so subsequent calls
18
- * with the same input bypass both normalisation and parsing.
18
+ * When `diagnostics` is supplied, normalisation events
19
+ * (`duplicate-body-parameter`, `dropped-swagger-feature`,
20
+ * `unknown-json-schema-dialect`, `divisible-by-conflict`,
21
+ * `relative-ref-resolved`, etc.) are forwarded to the sink. Passing
22
+ * diagnostics also bypasses the cache so each call observes the
23
+ * normalisation pipeline running against the supplied sink — caching
24
+ * would silently swallow every emission after the first.
25
+ *
26
+ * The cache is keyed by the caller-supplied document so subsequent
27
+ * cache-eligible calls with the same input bypass both normalisation
28
+ * and parsing.
19
29
  */
20
- declare function getParsed(doc: Record<string, unknown>): OpenApiDocument;
30
+ declare function getParsed(doc: Record<string, unknown>, diagnostics?: DiagnosticsOptions): OpenApiDocument;
21
31
  /**
22
32
  * Coerce an unknown value to a record, returning an empty record
23
33
  * for non-objects.
@@ -39,26 +49,67 @@ interface ResolvedOperation {
39
49
  requestBody: ReturnType<typeof getRequestBody>;
40
50
  responses: ResponseInfo[];
41
51
  }
52
+ /**
53
+ * Resolve an operation against an already-parsed document. Throws if
54
+ * the operation is not found.
55
+ *
56
+ * Used by callers that have already obtained a parsed document via
57
+ * {@link getParsed} — most importantly the React components, which
58
+ * supply `diagnostics` to `getParsed` and must avoid re-running the
59
+ * normalisation pipeline (every re-run would emit each diagnostic
60
+ * again into the sink).
61
+ */
62
+ declare function resolveOperationFromParsed(parsed: OpenApiDocument, path: string, method: string): ResolvedOperation;
42
63
  /**
43
64
  * Resolve an operation from an OpenAPI document by path and method.
44
65
  * Throws if the operation is not found.
66
+ *
67
+ * `diagnostics` is forwarded to {@link getParsed} so normalisation
68
+ * events surface to the caller's sink.
69
+ */
70
+ declare function resolveOperation(doc: Record<string, unknown>, path: string, method: string, diagnostics?: DiagnosticsOptions): ResolvedOperation;
71
+ /**
72
+ * Resolve parameters against an already-parsed document. See
73
+ * {@link resolveOperationFromParsed} for the rationale.
45
74
  */
46
- declare function resolveOperation(doc: Record<string, unknown>, path: string, method: string): ResolvedOperation;
75
+ declare function resolveParametersFromParsed(parsed: OpenApiDocument, path: string, method: string): ParameterInfo[];
47
76
  /**
48
77
  * Resolve parameters for an operation. Returns empty array if none.
78
+ *
79
+ * `diagnostics` is forwarded to {@link getParsed} so normalisation
80
+ * events surface to the caller's sink.
49
81
  */
50
- declare function resolveParameters(doc: Record<string, unknown>, path: string, method: string): ParameterInfo[];
82
+ declare function resolveParameters(doc: Record<string, unknown>, path: string, method: string, diagnostics?: DiagnosticsOptions): ParameterInfo[];
83
+ /**
84
+ * Resolve a request body against an already-parsed document. See
85
+ * {@link resolveOperationFromParsed} for the rationale.
86
+ */
87
+ declare function resolveRequestBodyFromParsed(parsed: OpenApiDocument, path: string, method: string): ReturnType<typeof getRequestBody>;
51
88
  /**
52
89
  * Resolve request body for an operation. Returns undefined if none.
90
+ *
91
+ * `diagnostics` is forwarded to {@link getParsed} so normalisation
92
+ * events surface to the caller's sink.
53
93
  */
54
- declare function resolveRequestBody(doc: Record<string, unknown>, path: string, method: string): ReturnType<typeof getRequestBody>;
94
+ declare function resolveRequestBody(doc: Record<string, unknown>, path: string, method: string, diagnostics?: DiagnosticsOptions): ReturnType<typeof getRequestBody>;
95
+ /**
96
+ * Resolve a specific response against an already-parsed document. See
97
+ * {@link resolveOperationFromParsed} for the rationale.
98
+ */
99
+ declare function resolveResponseFromParsed(parsed: OpenApiDocument, path: string, method: string, statusCode: string): ResponseInfo;
55
100
  /**
56
101
  * Resolve a specific response by status code. Throws if not found.
102
+ *
103
+ * `diagnostics` is forwarded to {@link getParsed} so normalisation
104
+ * events surface to the caller's sink.
57
105
  */
58
- declare function resolveResponse(doc: Record<string, unknown>, path: string, method: string, statusCode: string): ResponseInfo;
106
+ declare function resolveResponse(doc: Record<string, unknown>, path: string, method: string, statusCode: string, diagnostics?: DiagnosticsOptions): ResponseInfo;
59
107
  /**
60
108
  * Resolve all responses for an operation.
109
+ *
110
+ * `diagnostics` is forwarded to {@link getParsed} so normalisation
111
+ * events surface to the caller's sink.
61
112
  */
62
- declare function resolveResponses(doc: Record<string, unknown>, path: string, method: string): ResponseInfo[];
113
+ declare function resolveResponses(doc: Record<string, unknown>, path: string, method: string, diagnostics?: DiagnosticsOptions): ResponseInfo[];
63
114
  //#endregion
64
- export { PathItemInfo, ResolvedOperation, getParsed, resolveOperation, resolveParameters, resolveRequestBody, resolveResponse, resolveResponses, toDoc };
115
+ export { PathItemInfo, ResolvedOperation, getParsed, resolveOperation, resolveOperationFromParsed, resolveParameters, resolveParametersFromParsed, resolveRequestBody, resolveRequestBodyFromParsed, resolveResponse, resolveResponseFromParsed, resolveResponses, toDoc };
@@ -1,6 +1,7 @@
1
1
  import { getProperty, isObject } from "../core/guards.mjs";
2
+ import { isPrototypePollutingKey } from "../core/uri.mjs";
2
3
  import { detectOpenApiVersion } from "../core/version.mjs";
3
- import { a as normaliseOpenApiSchemas } from "../normalise-CMMEl4cd.mjs";
4
+ import { a as normaliseOpenApiSchemas } from "../normalise-DaSrnr8g.mjs";
4
5
  import { getParameters, getRequestBody, getResponses, listOperations, parseOpenApiDocument } from "./parser.mjs";
5
6
  //#region src/openapi/resolve.ts
6
7
  /**
@@ -24,17 +25,30 @@ const docCache = /* @__PURE__ */ new WeakMap();
24
25
  * same form `<SchemaComponent>` does, keeping the OpenAPI components on
25
26
  * the same pipeline as the top-level adapter.
26
27
  *
27
- * The cache is keyed by the caller-supplied document so subsequent calls
28
- * with the same input bypass both normalisation and parsing.
28
+ * When `diagnostics` is supplied, normalisation events
29
+ * (`duplicate-body-parameter`, `dropped-swagger-feature`,
30
+ * `unknown-json-schema-dialect`, `divisible-by-conflict`,
31
+ * `relative-ref-resolved`, etc.) are forwarded to the sink. Passing
32
+ * diagnostics also bypasses the cache so each call observes the
33
+ * normalisation pipeline running against the supplied sink — caching
34
+ * would silently swallow every emission after the first.
35
+ *
36
+ * The cache is keyed by the caller-supplied document so subsequent
37
+ * cache-eligible calls with the same input bypass both normalisation
38
+ * and parsing.
29
39
  */
30
- function getParsed(doc) {
31
- const cached = docCache.get(doc);
32
- if (cached !== void 0) return cached;
40
+ function getParsed(doc, diagnostics) {
41
+ if (diagnostics === void 0) {
42
+ const cached = docCache.get(doc);
43
+ if (cached !== void 0) return cached;
44
+ }
33
45
  const version = detectOpenApiVersion(doc);
34
- const normalisedDoc = version !== void 0 ? normaliseOpenApiSchemas(doc, version) : doc;
46
+ const normalisedDoc = version !== void 0 ? normaliseOpenApiSchemas(doc, version, diagnostics) : doc;
35
47
  const parsed = parseOpenApiDocument(normalisedDoc);
36
- docCache.set(doc, parsed);
37
- if (normalisedDoc !== doc) docCache.set(normalisedDoc, parsed);
48
+ if (diagnostics === void 0) {
49
+ docCache.set(doc, parsed);
50
+ if (normalisedDoc !== doc) docCache.set(normalisedDoc, parsed);
51
+ }
38
52
  return parsed;
39
53
  }
40
54
  /**
@@ -66,6 +80,7 @@ function resolvePathItemNode(parsed, pathItem) {
66
80
  for (const part of parts) {
67
81
  if (!isObject(current)) return void 0;
68
82
  const decoded = part.replace(/~1/g, "/").replace(/~0/g, "~");
83
+ if (isPrototypePollutingKey(decoded)) return void 0;
69
84
  current = current[decoded];
70
85
  }
71
86
  return isObject(current) ? current : pathItem;
@@ -79,11 +94,16 @@ function extractPathItemInfo(pathItem) {
79
94
  };
80
95
  }
81
96
  /**
82
- * Resolve an operation from an OpenAPI document by path and method.
83
- * Throws if the operation is not found.
97
+ * Resolve an operation against an already-parsed document. Throws if
98
+ * the operation is not found.
99
+ *
100
+ * Used by callers that have already obtained a parsed document via
101
+ * {@link getParsed} — most importantly the React components, which
102
+ * supply `diagnostics` to `getParsed` and must avoid re-running the
103
+ * normalisation pipeline (every re-run would emit each diagnostic
104
+ * again into the sink).
84
105
  */
85
- function resolveOperation(doc, path, method) {
86
- const parsed = getParsed(doc);
106
+ function resolveOperationFromParsed(parsed, path, method) {
87
107
  const operation = listOperations(parsed).find((op) => op.path === path && op.method === method);
88
108
  if (operation === void 0) throw new Error(`Operation not found: ${method.toUpperCase()} ${path}`);
89
109
  const pathItemNode = lookupPathItemNode(parsed, path);
@@ -97,30 +117,73 @@ function resolveOperation(doc, path, method) {
97
117
  };
98
118
  }
99
119
  /**
120
+ * Resolve an operation from an OpenAPI document by path and method.
121
+ * Throws if the operation is not found.
122
+ *
123
+ * `diagnostics` is forwarded to {@link getParsed} so normalisation
124
+ * events surface to the caller's sink.
125
+ */
126
+ function resolveOperation(doc, path, method, diagnostics) {
127
+ return resolveOperationFromParsed(getParsed(doc, diagnostics), path, method);
128
+ }
129
+ /**
130
+ * Resolve parameters against an already-parsed document. See
131
+ * {@link resolveOperationFromParsed} for the rationale.
132
+ */
133
+ function resolveParametersFromParsed(parsed, path, method) {
134
+ return getParameters(parsed, path, method);
135
+ }
136
+ /**
100
137
  * Resolve parameters for an operation. Returns empty array if none.
138
+ *
139
+ * `diagnostics` is forwarded to {@link getParsed} so normalisation
140
+ * events surface to the caller's sink.
101
141
  */
102
- function resolveParameters(doc, path, method) {
103
- return getParameters(getParsed(doc), path, method);
142
+ function resolveParameters(doc, path, method, diagnostics) {
143
+ return resolveParametersFromParsed(getParsed(doc, diagnostics), path, method);
144
+ }
145
+ /**
146
+ * Resolve a request body against an already-parsed document. See
147
+ * {@link resolveOperationFromParsed} for the rationale.
148
+ */
149
+ function resolveRequestBodyFromParsed(parsed, path, method) {
150
+ return getRequestBody(parsed, path, method);
104
151
  }
105
152
  /**
106
153
  * Resolve request body for an operation. Returns undefined if none.
154
+ *
155
+ * `diagnostics` is forwarded to {@link getParsed} so normalisation
156
+ * events surface to the caller's sink.
107
157
  */
108
- function resolveRequestBody(doc, path, method) {
109
- return getRequestBody(getParsed(doc), path, method);
158
+ function resolveRequestBody(doc, path, method, diagnostics) {
159
+ return resolveRequestBodyFromParsed(getParsed(doc, diagnostics), path, method);
110
160
  }
111
161
  /**
112
- * Resolve a specific response by status code. Throws if not found.
162
+ * Resolve a specific response against an already-parsed document. See
163
+ * {@link resolveOperationFromParsed} for the rationale.
113
164
  */
114
- function resolveResponse(doc, path, method, statusCode) {
115
- const response = getResponses(getParsed(doc), path, method).find((r) => r.statusCode === statusCode);
165
+ function resolveResponseFromParsed(parsed, path, method, statusCode) {
166
+ const response = getResponses(parsed, path, method).find((r) => r.statusCode === statusCode);
116
167
  if (response === void 0) throw new Error(`Response not found: ${statusCode}`);
117
168
  return response;
118
169
  }
119
170
  /**
171
+ * Resolve a specific response by status code. Throws if not found.
172
+ *
173
+ * `diagnostics` is forwarded to {@link getParsed} so normalisation
174
+ * events surface to the caller's sink.
175
+ */
176
+ function resolveResponse(doc, path, method, statusCode, diagnostics) {
177
+ return resolveResponseFromParsed(getParsed(doc, diagnostics), path, method, statusCode);
178
+ }
179
+ /**
120
180
  * Resolve all responses for an operation.
181
+ *
182
+ * `diagnostics` is forwarded to {@link getParsed} so normalisation
183
+ * events surface to the caller's sink.
121
184
  */
122
- function resolveResponses(doc, path, method) {
123
- return getResponses(getParsed(doc), path, method);
185
+ function resolveResponses(doc, path, method, diagnostics) {
186
+ return getResponses(getParsed(doc, diagnostics), path, method);
124
187
  }
125
188
  //#endregion
126
- export { getParsed, resolveOperation, resolveParameters, resolveRequestBody, resolveResponse, resolveResponses, toDoc };
189
+ export { getParsed, resolveOperation, resolveOperationFromParsed, resolveParameters, resolveParametersFromParsed, resolveRequestBody, resolveRequestBodyFromParsed, resolveResponse, resolveResponseFromParsed, resolveResponses, toDoc };
@@ -1,8 +1,8 @@
1
- import { M as WalkedField, T as SchemaMeta, d as FieldOverrides, u as FieldOverride } from "../types-C9zw9wbX.mjs";
1
+ import { M as WalkedField, T as SchemaMeta, d as FieldOverrides, u as FieldOverride } from "../types-BnxPEElk.mjs";
2
2
  import { t as Diagnostic } from "../diagnostics-CbBPsxSt.mjs";
3
- import { t as SchemaError } from "../errors-C2iABcn9.mjs";
4
- import { l as RenderProps, r as ComponentResolver } from "../renderer-SOIbJBtk.mjs";
5
- import { c as PathOfType, l as RejectUnrepresentableZod, n as FromJSONSchema, u as ResolveOpenAPIRef } from "../typeInference-CDoD_LZ_.mjs";
3
+ import { t as SchemaError } from "../errors-QEwOtQAA.mjs";
4
+ import { l as RenderProps, r as ComponentResolver } from "../renderer-DI6ZYf7a.mjs";
5
+ import { c as PathOfType, l as RejectUnrepresentableZod, n as FromJSONSchema, u as ResolveOpenAPIRef } from "../typeInference-Bxw3NOG1.mjs";
6
6
  import { z } from "zod";
7
7
  import * as _$react_jsx_runtime0 from "react/jsx-runtime";
8
8
  import { ReactNode } from "react";
@@ -87,7 +87,7 @@ function SchemaComponent({ schema: schemaInput, ref: refInput, value, onChange,
87
87
  }
88
88
  const handleChange = useCallback((nextValue) => {
89
89
  if (validate) {
90
- const error = runValidation(zodSchema, jsonSchema, nextValue);
90
+ const error = runValidation(zodSchema, jsonSchema, nextValue, onDiagnostic);
91
91
  if (error !== void 0) {
92
92
  onValidationError?.(error);
93
93
  dispatchFieldErrors(fields, error);
@@ -100,7 +100,8 @@ function SchemaComponent({ schema: schemaInput, ref: refInput, value, onChange,
100
100
  jsonSchema,
101
101
  onChange,
102
102
  onValidationError,
103
- fields
103
+ fields,
104
+ onDiagnostic
104
105
  ]);
105
106
  const walkOptions = {
106
107
  componentMeta: mergedMeta,
@@ -145,7 +146,7 @@ function sanitisePrefix(value) {
145
146
  if (sanitised.length === 0) throw new Error(`Cannot derive a DOM-safe id prefix from "${value}". Pass an explicit idPrefix prop.`);
146
147
  return sanitised;
147
148
  }
148
- function runValidation(zodSchema, jsonSchema, value) {
149
+ function runValidation(zodSchema, jsonSchema, value, onDiagnostic) {
149
150
  if (zodSchema !== void 0 && isObject(zodSchema)) {
150
151
  const safeParseFn = zodSchema.safeParse;
151
152
  if (isCallable(safeParseFn)) {
@@ -154,7 +155,13 @@ function runValidation(zodSchema, jsonSchema, value) {
154
155
  return;
155
156
  }
156
157
  }
157
- const parsed = z.fromJSONSchema(jsonSchema);
158
+ let parsed;
159
+ try {
160
+ parsed = z.fromJSONSchema(jsonSchema);
161
+ } catch (err) {
162
+ emitFromJsonSchemaDiagnostic(err, onDiagnostic);
163
+ return;
164
+ }
158
165
  if (isObject(parsed)) {
159
166
  const safeParseFn = parsed.safeParse;
160
167
  if (isCallable(safeParseFn)) {
@@ -163,6 +170,27 @@ function runValidation(zodSchema, jsonSchema, value) {
163
170
  }
164
171
  }
165
172
  }
173
+ /**
174
+ * Emit a diagnostic when `z.fromJSONSchema` refuses to round-trip the
175
+ * already-normalised JSON Schema. The diagnostic reuses the existing
176
+ * `unsupported-type` code because the failure mode is the same — a
177
+ * keyword/structure Zod cannot represent — and the consumer should be
178
+ * able to opt in to noticing it via the existing diagnostics channel.
179
+ *
180
+ * Best-effort: when no `onDiagnostic` sink is configured we still swallow
181
+ * the throw (the alternative would crash the React render for a
182
+ * non-essential validation step), matching the silent-fallback contract
183
+ * the rest of the diagnostics system uses.
184
+ */
185
+ function emitFromJsonSchemaDiagnostic(err, onDiagnostic) {
186
+ if (onDiagnostic === void 0) return;
187
+ onDiagnostic({
188
+ code: "unsupported-type",
189
+ message: `Skipping fallback validation: z.fromJSONSchema could not round-trip the normalised JSON Schema. Original message: ${err instanceof Error ? err.message : "z.fromJSONSchema threw a non-Error value"}`,
190
+ pointer: "",
191
+ detail: { source: "z.fromJSONSchema" }
192
+ });
193
+ }
166
194
  /** Maximum rendering depth before treating a field as recursive. */
167
195
  const MAX_RENDER_DEPTH = 10;
168
196
  function renderField(tree, value, onChange, userResolver, renderChild, path, instanceWidgets, contextWidgets, depth = 0) {
@@ -1,6 +1,6 @@
1
- import { T as SchemaMeta } from "../types-C9zw9wbX.mjs";
1
+ import { T as SchemaMeta } from "../types-BnxPEElk.mjs";
2
2
  import { t as Diagnostic } from "../diagnostics-CbBPsxSt.mjs";
3
- import { r as ComponentResolver } from "../renderer-SOIbJBtk.mjs";
3
+ import { r as ComponentResolver } from "../renderer-DI6ZYf7a.mjs";
4
4
  import { WidgetMap } from "./SchemaComponent.mjs";
5
5
  import { ReactNode } from "react";
6
6
 
@@ -1,4 +1,4 @@
1
- import { M as WalkedField } from "../types-C9zw9wbX.mjs";
1
+ import { M as WalkedField } from "../types-BnxPEElk.mjs";
2
2
 
3
3
  //#region src/react/fieldPath.d.ts
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { r as ComponentResolver } from "../renderer-SOIbJBtk.mjs";
1
+ import { r as ComponentResolver } from "../renderer-DI6ZYf7a.mjs";
2
2
 
3
3
  //#region src/react/headless.d.ts
4
4
  /**
@@ -1,5 +1,5 @@
1
- import { M as WalkedField } from "../types-C9zw9wbX.mjs";
2
- import { l as RenderProps } from "../renderer-SOIbJBtk.mjs";
1
+ import { M as WalkedField } from "../types-BnxPEElk.mjs";
2
+ import { l as RenderProps } from "../renderer-DI6ZYf7a.mjs";
3
3
  import { ReactNode } from "react";
4
4
 
5
5
  //#region src/react/headlessRenderers.d.ts
@@ -1,6 +1,6 @@
1
1
  import { isObject } from "../core/guards.mjs";
2
- import { sortFieldsByOrder } from "../core/fieldOrder.mjs";
3
2
  import { isSafeHyperlink, isSafeMailtoAddress } from "../core/uri.mjs";
3
+ import { sortFieldsByOrder } from "../core/fieldOrder.mjs";
4
4
  import { jsx, jsxs } from "react/jsx-runtime";
5
5
  import { isValidElement, useCallback, useEffect, useRef } from "react";
6
6
  //#region src/react/headlessRenderers.tsx
@@ -38,7 +38,12 @@ declare function dereference(ref: string, root: Record<string, unknown>): Record
38
38
  /**
39
39
  * Recursively scan a schema document for a `$anchor` matching the given name.
40
40
  * Returns the schema object containing the anchor, or undefined.
41
+ *
42
+ * The optional `visited` set guards against shared object references and
43
+ * cycles introduced by the OpenAPI bundler's `structuredClone`-based
44
+ * inlining of external refs. Without it a recursive document would stack
45
+ * overflow before reaching the matching anchor.
41
46
  */
42
- declare function findAnchor(node: unknown, anchorName: string): Record<string, unknown> | undefined;
47
+ declare function findAnchor(node: unknown, anchorName: string, visited?: WeakSet<object>): Record<string, unknown> | undefined;
43
48
  //#endregion
44
49
  export { findAnchor as a, dereference as i, RefOptions as n, resolveRef as o, countDistinctRefs as r, ExternalResolver as t };
@@ -1,4 +1,4 @@
1
- import { D as StringConstraints, M as WalkedField, T as SchemaMeta, f as FileConstraints, t as ArrayConstraints, x as ObjectConstraints, y as NumberConstraints } from "./types-C9zw9wbX.mjs";
1
+ import { D as StringConstraints, M as WalkedField, T as SchemaMeta, f as FileConstraints, t as ArrayConstraints, x as ObjectConstraints, y as NumberConstraints } from "./types-BnxPEElk.mjs";
2
2
 
3
3
  //#region src/core/renderer.d.ts
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { r as ComponentResolver } from "../renderer-SOIbJBtk.mjs";
1
+ import { r as ComponentResolver } from "../renderer-DI6ZYf7a.mjs";
2
2
 
3
3
  //#region src/themes/mantine.d.ts
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { r as ComponentResolver } from "../renderer-SOIbJBtk.mjs";
1
+ import { r as ComponentResolver } from "../renderer-DI6ZYf7a.mjs";
2
2
 
3
3
  //#region src/themes/mui.d.ts
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { r as ComponentResolver } from "../renderer-SOIbJBtk.mjs";
1
+ import { r as ComponentResolver } from "../renderer-DI6ZYf7a.mjs";
2
2
 
3
3
  //#region src/themes/radix.d.ts
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { r as ComponentResolver } from "../renderer-SOIbJBtk.mjs";
1
+ import { r as ComponentResolver } from "../renderer-DI6ZYf7a.mjs";
2
2
 
3
3
  //#region src/themes/shadcn.d.ts
4
4
  declare const shadcnResolver: ComponentResolver;