schema-components 1.13.0 → 1.15.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 (71) hide show
  1. package/README.md +4 -0
  2. package/dist/core/adapter.d.mts +8 -3
  3. package/dist/core/adapter.mjs +25 -10
  4. package/dist/core/constraints.d.mts +3 -2
  5. package/dist/core/constraints.mjs +14 -2
  6. package/dist/core/diagnostics.d.mts +2 -0
  7. package/dist/core/diagnostics.mjs +33 -0
  8. package/dist/core/errors.d.mts +1 -1
  9. package/dist/core/formats.d.mts +33 -0
  10. package/dist/core/formats.mjs +67 -0
  11. package/dist/core/merge.d.mts +17 -1
  12. package/dist/core/merge.mjs +30 -1
  13. package/dist/core/normalise.d.mts +3 -2
  14. package/dist/core/normalise.mjs +1 -170
  15. package/dist/core/openapi30.d.mts +4 -1
  16. package/dist/core/openapi30.mjs +1 -222
  17. package/dist/core/ref.d.mts +2 -25
  18. package/dist/core/ref.mjs +102 -23
  19. package/dist/core/renderer.d.mts +1 -1
  20. package/dist/core/swagger2.d.mts +2 -1
  21. package/dist/core/swagger2.mjs +1 -293
  22. package/dist/core/typeInference.d.mts +2 -2
  23. package/dist/core/types.d.mts +2 -2
  24. package/dist/core/types.mjs +4 -1
  25. package/dist/core/version.d.mts +2 -2
  26. package/dist/core/version.mjs +84 -12
  27. package/dist/core/walkBuilders.d.mts +15 -1
  28. package/dist/core/walkBuilders.mjs +1 -1
  29. package/dist/core/walker.d.mts +1 -1
  30. package/dist/core/walker.mjs +122 -22
  31. package/dist/diagnostics-DzbZmcLI.d.mts +64 -0
  32. package/dist/html/a11y.d.mts +2 -2
  33. package/dist/html/renderToHtml.d.mts +2 -2
  34. package/dist/html/renderToHtmlStream.d.mts +2 -2
  35. package/dist/html/renderers.d.mts +2 -2
  36. package/dist/html/streamRenderers.d.mts +2 -2
  37. package/dist/normalise-tL9FckAk.mjs +748 -0
  38. package/dist/openapi/ApiCallbacks.d.mts +16 -0
  39. package/dist/openapi/ApiCallbacks.mjs +34 -0
  40. package/dist/openapi/ApiLinks.d.mts +16 -0
  41. package/dist/openapi/ApiLinks.mjs +42 -0
  42. package/dist/openapi/ApiResponseHeaders.d.mts +16 -0
  43. package/dist/openapi/ApiResponseHeaders.mjs +35 -0
  44. package/dist/openapi/ApiSecurity.d.mts +19 -0
  45. package/dist/openapi/ApiSecurity.mjs +33 -0
  46. package/dist/openapi/bundle.d.mts +47 -0
  47. package/dist/openapi/bundle.mjs +95 -0
  48. package/dist/openapi/components.d.mts +7 -2
  49. package/dist/openapi/components.mjs +30 -6
  50. package/dist/openapi/parser.d.mts +1 -1
  51. package/dist/react/SchemaComponent.d.mts +12 -5
  52. package/dist/react/SchemaComponent.mjs +13 -7
  53. package/dist/react/SchemaView.d.mts +10 -3
  54. package/dist/react/SchemaView.mjs +13 -7
  55. package/dist/react/fieldPath.d.mts +1 -1
  56. package/dist/react/headless.d.mts +1 -1
  57. package/dist/react/headlessRenderers.d.mts +1 -1
  58. package/dist/react/headlessRenderers.mjs +1 -1
  59. package/dist/ref-DvWoULcy.d.mts +44 -0
  60. package/dist/{renderer-DseHeliw.d.mts → renderer-BdSqllx5.d.mts} +1 -1
  61. package/dist/themes/mantine.d.mts +1 -1
  62. package/dist/themes/mui.d.mts +1 -1
  63. package/dist/themes/mui.mjs +1 -1
  64. package/dist/themes/radix.d.mts +1 -1
  65. package/dist/themes/shadcn.d.mts +1 -1
  66. package/dist/{typeInference-CRPqVwKu.d.mts → typeInference-k7FXfTVO.d.mts} +44 -8
  67. package/dist/{types-ag2jYLqQ.d.mts → types-D_5ST7SS.d.mts} +11 -3
  68. package/dist/version-B5NV-35j.d.mts +69 -0
  69. package/package.json +1 -1
  70. package/dist/version-CLchheaH.d.mts +0 -40
  71. /package/dist/{errors-DIKI2C78.d.mts → errors-C5zRC2PU.d.mts} +0 -0
@@ -0,0 +1,16 @@
1
+ import { T as SchemaMeta } from "../types-D_5ST7SS.mjs";
2
+ import { CallbackInfo } from "./parser.mjs";
3
+ import { ReactNode } from "react";
4
+
5
+ //#region src/openapi/ApiCallbacks.d.ts
6
+ interface ApiCallbacksProps {
7
+ /** Callback definitions for this operation. */
8
+ callbacks: CallbackInfo[];
9
+ /** Optional meta overrides. */
10
+ meta?: SchemaMeta;
11
+ }
12
+ declare function ApiCallbacks({
13
+ callbacks
14
+ }: ApiCallbacksProps): ReactNode;
15
+ //#endregion
16
+ export { ApiCallbacks, ApiCallbacksProps };
@@ -0,0 +1,34 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ //#region src/openapi/ApiCallbacks.tsx
3
+ function ApiCallbacks({ callbacks }) {
4
+ if (callbacks.length === 0) return null;
5
+ return /* @__PURE__ */ jsxs("section", {
6
+ "data-callbacks": true,
7
+ children: [/* @__PURE__ */ jsx("h4", { children: "Callbacks" }), callbacks.map((callback) => /* @__PURE__ */ jsxs("div", {
8
+ "data-callback": callback.name,
9
+ children: [/* @__PURE__ */ jsx("span", {
10
+ "data-callback-name": true,
11
+ children: callback.name
12
+ }), callback.operations.map((op) => /* @__PURE__ */ jsxs("div", {
13
+ "data-callback-operation": true,
14
+ children: [
15
+ /* @__PURE__ */ jsx("span", {
16
+ "data-callback-method": true,
17
+ children: op.method.toUpperCase()
18
+ }),
19
+ " ",
20
+ /* @__PURE__ */ jsx("span", {
21
+ "data-callback-path": true,
22
+ children: op.path
23
+ }),
24
+ op.summary && /* @__PURE__ */ jsx("span", {
25
+ "data-callback-summary": true,
26
+ children: op.summary
27
+ })
28
+ ]
29
+ }, `${op.method}-${op.path}`))]
30
+ }, callback.name))]
31
+ });
32
+ }
33
+ //#endregion
34
+ export { ApiCallbacks };
@@ -0,0 +1,16 @@
1
+ import { T as SchemaMeta } from "../types-D_5ST7SS.mjs";
2
+ import { LinkInfo } from "./parser.mjs";
3
+ import { ReactNode } from "react";
4
+
5
+ //#region src/openapi/ApiLinks.d.ts
6
+ interface ApiLinksProps {
7
+ /** Link definitions for a response. */
8
+ links: LinkInfo[];
9
+ /** Optional meta overrides. */
10
+ meta?: SchemaMeta;
11
+ }
12
+ declare function ApiLinks({
13
+ links
14
+ }: ApiLinksProps): ReactNode;
15
+ //#endregion
16
+ export { ApiLinks, ApiLinksProps };
@@ -0,0 +1,42 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ //#region src/openapi/ApiLinks.tsx
3
+ function ApiLinks({ links }) {
4
+ if (links.length === 0) return null;
5
+ return /* @__PURE__ */ jsxs("section", {
6
+ "data-links": true,
7
+ children: [/* @__PURE__ */ jsx("h4", { children: "Links" }), links.map((link) => /* @__PURE__ */ jsxs("div", {
8
+ "data-link": link.name,
9
+ children: [
10
+ /* @__PURE__ */ jsx("span", {
11
+ "data-link-name": true,
12
+ children: link.name
13
+ }),
14
+ link.operationId && /* @__PURE__ */ jsx("span", {
15
+ "data-link-operation-id": true,
16
+ children: link.operationId
17
+ }),
18
+ link.operationRef && /* @__PURE__ */ jsx("span", {
19
+ "data-link-operation-ref": true,
20
+ children: link.operationRef
21
+ }),
22
+ link.description && /* @__PURE__ */ jsx("span", {
23
+ "data-link-description": true,
24
+ children: link.description
25
+ }),
26
+ link.parameters.size > 0 && /* @__PURE__ */ jsx("dl", {
27
+ "data-link-parameters": true,
28
+ children: [...link.parameters.entries()].map(([paramName, paramValue]) => /* @__PURE__ */ jsxs("span", {
29
+ "data-link-parameter": paramName,
30
+ children: [
31
+ paramName,
32
+ ": ",
33
+ paramValue
34
+ ]
35
+ }, paramName))
36
+ })
37
+ ]
38
+ }, link.name))]
39
+ });
40
+ }
41
+ //#endregion
42
+ export { ApiLinks };
@@ -0,0 +1,16 @@
1
+ import { T as SchemaMeta } from "../types-D_5ST7SS.mjs";
2
+ import { HeaderInfo } from "./parser.mjs";
3
+ import { ReactNode } from "react";
4
+
5
+ //#region src/openapi/ApiResponseHeaders.d.ts
6
+ interface ApiResponseHeadersProps {
7
+ /** Header definitions for a response. */
8
+ headers: Map<string, HeaderInfo>;
9
+ /** Optional meta overrides. */
10
+ meta?: SchemaMeta;
11
+ }
12
+ declare function ApiResponseHeaders({
13
+ headers
14
+ }: ApiResponseHeadersProps): ReactNode;
15
+ //#endregion
16
+ export { ApiResponseHeaders, ApiResponseHeadersProps };
@@ -0,0 +1,35 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ //#region src/openapi/ApiResponseHeaders.tsx
3
+ function ApiResponseHeaders({ headers }) {
4
+ if (headers.size === 0) return null;
5
+ return /* @__PURE__ */ jsxs("section", {
6
+ "data-response-headers": true,
7
+ children: [/* @__PURE__ */ jsx("h5", { children: "Headers" }), [...headers.entries()].map(([name, header]) => /* @__PURE__ */ jsxs("div", {
8
+ "data-header": name,
9
+ children: [
10
+ /* @__PURE__ */ jsx("span", {
11
+ "data-header-name": true,
12
+ children: name
13
+ }),
14
+ header.description && /* @__PURE__ */ jsx("span", {
15
+ "data-header-description": true,
16
+ children: header.description
17
+ }),
18
+ header.required && /* @__PURE__ */ jsx("span", {
19
+ "data-required": true,
20
+ children: "*"
21
+ }),
22
+ header.deprecated && /* @__PURE__ */ jsx("span", {
23
+ "data-deprecated": true,
24
+ children: "Deprecated"
25
+ }),
26
+ header.schema !== void 0 && "type" in header.schema && typeof header.schema.type === "string" ? /* @__PURE__ */ jsx("span", {
27
+ "data-header-type": true,
28
+ children: header.schema.type
29
+ }) : void 0
30
+ ]
31
+ }, name))]
32
+ });
33
+ }
34
+ //#endregion
35
+ export { ApiResponseHeaders };
@@ -0,0 +1,19 @@
1
+ import { T as SchemaMeta } from "../types-D_5ST7SS.mjs";
2
+ import { SecurityRequirement, SecurityScheme } from "./parser.mjs";
3
+ import { ReactNode } from "react";
4
+
5
+ //#region src/openapi/ApiSecurity.d.ts
6
+ interface ApiSecurityProps {
7
+ /** Security requirements for this operation. */
8
+ requirements: SecurityRequirement[];
9
+ /** Security schemes from the document's components. */
10
+ schemes: Map<string, SecurityScheme>;
11
+ /** Optional meta overrides. */
12
+ meta?: SchemaMeta;
13
+ }
14
+ declare function ApiSecurity({
15
+ requirements,
16
+ schemes
17
+ }: ApiSecurityProps): ReactNode;
18
+ //#endregion
19
+ export { ApiSecurity, ApiSecurityProps };
@@ -0,0 +1,33 @@
1
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
+ //#region src/openapi/ApiSecurity.tsx
3
+ function ApiSecurity({ requirements, schemes }) {
4
+ if (requirements.length === 0) return null;
5
+ return /* @__PURE__ */ jsxs("section", {
6
+ "data-security": true,
7
+ children: [/* @__PURE__ */ jsx("h4", { children: "Security" }), requirements.map((req, index) => {
8
+ const scheme = schemes.get(req.name);
9
+ return /* @__PURE__ */ jsxs("div", {
10
+ "data-security-scheme": req.name,
11
+ children: [
12
+ /* @__PURE__ */ jsx("span", {
13
+ "data-security-name": true,
14
+ children: req.name
15
+ }),
16
+ scheme !== void 0 && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("span", {
17
+ "data-security-type": true,
18
+ children: scheme.type
19
+ }), scheme.description && /* @__PURE__ */ jsx("span", {
20
+ "data-security-description": true,
21
+ children: scheme.description
22
+ })] }),
23
+ req.scopes.length > 0 && /* @__PURE__ */ jsx("span", {
24
+ "data-security-scopes": true,
25
+ children: req.scopes.join(", ")
26
+ })
27
+ ]
28
+ }, `${req.name}-${String(index)}`);
29
+ })]
30
+ });
31
+ }
32
+ //#endregion
33
+ export { ApiSecurity };
@@ -0,0 +1,47 @@
1
+ //#region src/openapi/bundle.d.ts
2
+ /**
3
+ * OpenAPI document bundler — inlines external $ref files.
4
+ *
5
+ * Walks all `$ref` strings in an OpenAPI document, fetches external
6
+ * documents via a user-provided resolver, inlines their schemas into
7
+ * `components.schemas` with synthesised names, and rewrites the refs
8
+ * to point to the inlined copies.
9
+ *
10
+ * This is an opt-in async pre-step. The synchronous core API is unchanged;
11
+ * consumers call `bundleOpenApiDoc` once before rendering.
12
+ *
13
+ * Usage:
14
+ * ```ts
15
+ * import { bundleOpenApiDoc } from "schema-components/openapi/bundle";
16
+ *
17
+ * const resolver = async (uri: string) => {
18
+ * const response = await fetch(uri);
19
+ * return response.json();
20
+ * };
21
+ *
22
+ * const bundled = await bundleOpenApiDoc(doc, resolver);
23
+ * // Now pass bundled to SchemaComponent / ApiOperation
24
+ * ```
25
+ */
26
+ /**
27
+ * Resolver function for external documents.
28
+ * Called with the URI portion of an external $ref (everything before `#`).
29
+ * Returns the parsed JSON document.
30
+ */
31
+ type BundleResolver = (uri: string) => unknown;
32
+ /**
33
+ * Bundle an OpenAPI document by inlining all external $ref targets.
34
+ *
35
+ * Walks every $ref in the document. For external refs (not starting with `#`),
36
+ * calls the resolver to fetch the external document, extracts the referenced
37
+ * schema, inlines it into `components.schemas` with a synthesised name, and
38
+ * rewrites the $ref to point to the inlined copy.
39
+ *
40
+ * The resolver is called once per unique URI and the result is cached.
41
+ *
42
+ * Returns a deep-cloned document with all external refs resolved.
43
+ * The original document is never mutated.
44
+ */
45
+ declare function bundleOpenApiDoc(doc: Record<string, unknown>, resolver: BundleResolver): Promise<Record<string, unknown>>;
46
+ //#endregion
47
+ export { BundleResolver, bundleOpenApiDoc };
@@ -0,0 +1,95 @@
1
+ import { isObject } from "../core/guards.mjs";
2
+ //#region src/openapi/bundle.ts
3
+ /**
4
+ * OpenAPI document bundler — inlines external $ref files.
5
+ *
6
+ * Walks all `$ref` strings in an OpenAPI document, fetches external
7
+ * documents via a user-provided resolver, inlines their schemas into
8
+ * `components.schemas` with synthesised names, and rewrites the refs
9
+ * to point to the inlined copies.
10
+ *
11
+ * This is an opt-in async pre-step. The synchronous core API is unchanged;
12
+ * consumers call `bundleOpenApiDoc` once before rendering.
13
+ *
14
+ * Usage:
15
+ * ```ts
16
+ * import { bundleOpenApiDoc } from "schema-components/openapi/bundle";
17
+ *
18
+ * const resolver = async (uri: string) => {
19
+ * const response = await fetch(uri);
20
+ * return response.json();
21
+ * };
22
+ *
23
+ * const bundled = await bundleOpenApiDoc(doc, resolver);
24
+ * // Now pass bundled to SchemaComponent / ApiOperation
25
+ * ```
26
+ */
27
+ /**
28
+ * Bundle an OpenAPI document by inlining all external $ref targets.
29
+ *
30
+ * Walks every $ref in the document. For external refs (not starting with `#`),
31
+ * calls the resolver to fetch the external document, extracts the referenced
32
+ * schema, inlines it into `components.schemas` with a synthesised name, and
33
+ * rewrites the $ref to point to the inlined copy.
34
+ *
35
+ * The resolver is called once per unique URI and the result is cached.
36
+ *
37
+ * Returns a deep-cloned document with all external refs resolved.
38
+ * The original document is never mutated.
39
+ */
40
+ async function bundleOpenApiDoc(doc, resolver) {
41
+ const result = structuredClone(doc);
42
+ const uriCache = /* @__PURE__ */ new Map();
43
+ if (!isObject(result.components)) result.components = {};
44
+ if (!isObject(result.components)) result.components = {};
45
+ if (isObject(result.components) && !isObject(result.components.schemas)) result.components.schemas = {};
46
+ await walkAndInline(result, uriCache, resolver);
47
+ return result;
48
+ }
49
+ /**
50
+ * Walk a document tree, find external $ref strings, resolve them,
51
+ * inline the targets, and rewrite the refs.
52
+ */
53
+ async function walkAndInline(node, uriCache, resolver) {
54
+ if (!isObject(node)) return;
55
+ if (typeof node.$ref === "string" && !node.$ref.startsWith("#")) {
56
+ const ref = node.$ref;
57
+ const hashIndex = ref.indexOf("#");
58
+ const uri = hashIndex >= 0 ? ref.slice(0, hashIndex) : ref;
59
+ const fragment = hashIndex >= 0 ? ref.slice(hashIndex) : "#";
60
+ let externalDoc = uriCache.get(uri);
61
+ if (externalDoc === void 0) {
62
+ const resolved = await resolver(uri);
63
+ if (isObject(resolved)) {
64
+ externalDoc = resolved;
65
+ uriCache.set(uri, externalDoc);
66
+ }
67
+ }
68
+ if (externalDoc !== void 0) {
69
+ const target = resolveFragment(externalDoc, fragment);
70
+ if (isObject(target)) {
71
+ delete node.$ref;
72
+ for (const [key, value] of Object.entries(target)) node[key] = value;
73
+ }
74
+ }
75
+ }
76
+ for (const value of Object.values(node)) if (isObject(value)) await walkAndInline(value, uriCache, resolver);
77
+ else if (Array.isArray(value)) for (const item of value) await walkAndInline(item, uriCache, resolver);
78
+ }
79
+ /**
80
+ * Resolve a JSON Pointer fragment within a document.
81
+ */
82
+ function resolveFragment(doc, fragment) {
83
+ if (fragment === "#" || fragment === "") return doc;
84
+ if (!fragment.startsWith("#/")) return void 0;
85
+ const parts = fragment.slice(2).split("/");
86
+ let current = doc;
87
+ for (const part of parts) {
88
+ if (!isObject(current)) return void 0;
89
+ const decoded = part.replace(/~1/g, "/").replace(/~0/g, "~");
90
+ current = current[decoded];
91
+ }
92
+ return isObject(current) ? current : void 0;
93
+ }
94
+ //#endregion
95
+ export { bundleOpenApiDoc };
@@ -1,5 +1,5 @@
1
- import { u as FieldOverride, w as SchemaMeta } from "../types-ag2jYLqQ.mjs";
2
- import { i as InferResponseFields, n as InferParameterOverrides, r as InferRequestBodyFields } from "../typeInference-CRPqVwKu.mjs";
1
+ import { T as SchemaMeta, u as FieldOverride } from "../types-D_5ST7SS.mjs";
2
+ import { i as InferResponseFields, n as InferParameterOverrides, r as InferRequestBodyFields, u as UnsafeFields } from "../typeInference-k7FXfTVO.mjs";
3
3
  import { WidgetMap } from "../react/SchemaComponent.mjs";
4
4
  import { ReactNode } from "react";
5
5
 
@@ -13,6 +13,11 @@ interface ApiOperationProps<Doc = unknown, Path extends string = string, Method
13
13
  responseValue?: unknown;
14
14
  meta?: SchemaMeta;
15
15
  requestBodyFields?: Doc extends Record<string, unknown> ? InferRequestBodyFields<Doc, Path, Method> : Record<string, FieldOverride>;
16
+ /** Escape hatch for recursive schemas where type-level inference fails.
17
+ * Typed as Record<string, FieldOverride> — use when the schema contains
18
+ * deeply nested $ref chains.
19
+ */
20
+ unsafeFields?: UnsafeFields;
16
21
  /** Instance-scoped widgets. */
17
22
  widgets?: WidgetMap;
18
23
  }
@@ -1,9 +1,14 @@
1
1
  import { toRecordOrUndefined } from "../core/guards.mjs";
2
- import { normaliseSchema } from "../core/adapter.mjs";
3
2
  import { SchemaNormalisationError } from "../core/errors.mjs";
3
+ import { normaliseSchema } from "../core/adapter.mjs";
4
4
  import { walk } from "../core/walker.mjs";
5
+ import { ApiCallbacks } from "./ApiCallbacks.mjs";
6
+ import { ApiLinks } from "./ApiLinks.mjs";
7
+ import { ApiResponseHeaders } from "./ApiResponseHeaders.mjs";
8
+ import { ApiSecurity } from "./ApiSecurity.mjs";
9
+ import { getLinks, getSecurityRequirements, getSecuritySchemes, listCallbacks } from "./parser.mjs";
5
10
  import { renderField } from "../react/SchemaComponent.mjs";
6
- import { resolveOperation, resolveParameters, resolveRequestBody, resolveResponse, toDoc } from "./resolve.mjs";
11
+ import { getParsed, resolveOperation, resolveParameters, resolveRequestBody, resolveResponse, toDoc } from "./resolve.mjs";
7
12
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
8
13
  //#region src/openapi/components.tsx
9
14
  function noop() {}
@@ -33,10 +38,19 @@ function renderSchema(schema, rootDocument, options) {
33
38
  function ApiOperation({ schema: doc, path, method, requestBodyValue, onRequestBodyChange, responseValue, meta, requestBodyFields, widgets }) {
34
39
  const rootDoc = toDoc(doc);
35
40
  const resolved = resolveOperation(rootDoc, path, method);
41
+ const parsed = getParsed(rootDoc);
42
+ const securityReqs = getSecurityRequirements(parsed, path, method);
43
+ const securitySchemes = getSecuritySchemes(parsed);
44
+ const callbacks = listCallbacks(parsed, path, method);
36
45
  return /* @__PURE__ */ jsxs("section", {
37
46
  "data-operation": `${method.toUpperCase()} ${path}`,
38
47
  children: [
39
48
  /* @__PURE__ */ jsx(OperationHeader, { operation: resolved.operation }),
49
+ /* @__PURE__ */ jsx(ApiSecurity, {
50
+ requirements: securityReqs,
51
+ schemes: securitySchemes
52
+ }),
53
+ /* @__PURE__ */ jsx(ApiCallbacks, { callbacks }),
40
54
  resolved.parameters.length > 0 && /* @__PURE__ */ jsxs("section", {
41
55
  "data-parameters": true,
42
56
  children: [/* @__PURE__ */ jsx("h4", { children: "Parameters" }), /* @__PURE__ */ jsx(ParameterList, {
@@ -74,7 +88,9 @@ function ApiOperation({ schema: doc, path, method, requestBodyValue, onRequestBo
74
88
  rootDoc,
75
89
  value: responseValue,
76
90
  meta,
77
- widgets
91
+ widgets,
92
+ path,
93
+ method
78
94
  }, response.statusCode))]
79
95
  })
80
96
  ]
@@ -138,7 +154,9 @@ function ApiResponse({ schema: doc, path, method, status, value, meta, fields, w
138
154
  value,
139
155
  fields,
140
156
  meta,
141
- widgets
157
+ widgets,
158
+ path,
159
+ method
142
160
  });
143
161
  }
144
162
  function OperationHeader({ operation }) {
@@ -174,7 +192,7 @@ function ParameterList({ parameters, rootDoc, overrides, meta, widgets }) {
174
192
  ]
175
193
  }, param.name)) });
176
194
  }
177
- function ResponseCard({ response, rootDoc, value, fields, meta, widgets }) {
195
+ function ResponseCard({ response, rootDoc, value, fields, meta, widgets, path, method }) {
178
196
  if (response.schema === void 0) return /* @__PURE__ */ jsxs("div", {
179
197
  "data-status": response.statusCode,
180
198
  children: [
@@ -183,6 +201,10 @@ function ResponseCard({ response, rootDoc, value, fields, meta, widgets }) {
183
201
  /* @__PURE__ */ jsx("p", { children: /* @__PURE__ */ jsx("em", { children: "No schema" }) })
184
202
  ]
185
203
  });
204
+ let links = [];
205
+ if (path !== void 0 && method !== void 0) try {
206
+ links = getLinks(getParsed(rootDoc), path, method, response.statusCode);
207
+ } catch {}
186
208
  return /* @__PURE__ */ jsxs("div", {
187
209
  "data-status": response.statusCode,
188
210
  children: [
@@ -196,7 +218,9 @@ function ResponseCard({ response, rootDoc, value, fields, meta, widgets }) {
196
218
  ...meta
197
219
  },
198
220
  widgets
199
- })
221
+ }),
222
+ /* @__PURE__ */ jsx(ApiResponseHeaders, { headers: response.headers }),
223
+ /* @__PURE__ */ jsx(ApiLinks, { links })
200
224
  ]
201
225
  });
202
226
  }
@@ -1,4 +1,4 @@
1
- import { m as JsonObject } from "../types-ag2jYLqQ.mjs";
1
+ import { m as JsonObject } from "../types-D_5ST7SS.mjs";
2
2
 
3
3
  //#region src/openapi/parser.d.ts
4
4
  interface OpenApiDocument {
@@ -1,10 +1,11 @@
1
- import { d as FieldOverrides, j as WalkedField, u as FieldOverride, w as SchemaMeta } from "../types-ag2jYLqQ.mjs";
2
- import { t as SchemaError } from "../errors-DIKI2C78.mjs";
3
- import { l as RenderProps, r as ComponentResolver } from "../renderer-DseHeliw.mjs";
4
- import { c as ResolveOpenAPIRef, s as PathOfType, t as FromJSONSchema } from "../typeInference-CRPqVwKu.mjs";
1
+ import { M as WalkedField, T as SchemaMeta, d as FieldOverrides, u as FieldOverride } from "../types-D_5ST7SS.mjs";
2
+ import { t as Diagnostic } from "../diagnostics-DzbZmcLI.mjs";
3
+ import { t as SchemaError } from "../errors-C5zRC2PU.mjs";
4
+ import { l as RenderProps, r as ComponentResolver } from "../renderer-BdSqllx5.mjs";
5
+ import { c as ResolveOpenAPIRef, s as PathOfType, t as FromJSONSchema } from "../typeInference-k7FXfTVO.mjs";
5
6
  import { z } from "zod";
6
- import { ReactNode } from "react";
7
7
  import * as _$react_jsx_runtime0 from "react/jsx-runtime";
8
+ import { ReactNode } from "react";
8
9
 
9
10
  //#region src/react/SchemaComponent.d.ts
10
11
  /**
@@ -53,6 +54,10 @@ interface SchemaComponentProps<T = unknown, Ref extends string | undefined = und
53
54
  onValidationError?: (error: unknown) => void;
54
55
  /** Called when schema normalisation or rendering fails. */
55
56
  onError?: (error: SchemaError) => void;
57
+ /** Called with each diagnostic emitted during schema processing. */
58
+ onDiagnostic?: (diagnostic: Diagnostic) => void;
59
+ /** When true, any diagnostic becomes a thrown error. */
60
+ strict?: boolean;
56
61
  /** Per-field meta overrides — nested object mirroring schema shape. */
57
62
  fields?: InferFields<T, Ref>;
58
63
  /** Meta overrides applied to the root schema. */
@@ -74,6 +79,8 @@ declare function SchemaComponent<T = unknown, Ref extends string | undefined = u
74
79
  validate,
75
80
  onValidationError,
76
81
  onError,
82
+ onDiagnostic,
83
+ strict,
77
84
  fields,
78
85
  meta: componentMeta,
79
86
  readOnly,
@@ -1,14 +1,14 @@
1
1
  "use client";
2
2
  import { isObject, toRecordOrUndefined } from "../core/guards.mjs";
3
- import { normaliseSchema } from "../core/adapter.mjs";
4
3
  import { SchemaFieldError, SchemaNormalisationError, SchemaRenderError } from "../core/errors.mjs";
4
+ import { normaliseSchema } from "../core/adapter.mjs";
5
5
  import { getRenderFunction, mergeResolvers } from "../core/renderer.mjs";
6
6
  import { walk } from "../core/walker.mjs";
7
7
  import { headlessResolver } from "./headless.mjs";
8
8
  import { resolvePath, resolveValue, setNestedValue } from "./fieldPath.mjs";
9
9
  import { z } from "zod";
10
- import { createContext, isValidElement, useCallback, useContext, useMemo } from "react";
11
10
  import { jsx, jsxs } from "react/jsx-runtime";
11
+ import { createContext, isValidElement, useCallback, useContext, useMemo } from "react";
12
12
  //#region src/react/SchemaComponent.tsx
13
13
  /**
14
14
  * <SchemaComponent> — renders UI from Zod, JSON Schema, or OpenAPI schemas.
@@ -46,7 +46,7 @@ const globalWidgets = /* @__PURE__ */ new Map();
46
46
  function registerWidget(name, render) {
47
47
  globalWidgets.set(name, render);
48
48
  }
49
- function SchemaComponent({ schema: schemaInput, ref: refInput, value, onChange, validate, onValidationError, onError, fields, meta: componentMeta, readOnly, writeOnly, description, widgets: instanceWidgets }) {
49
+ function SchemaComponent({ schema: schemaInput, ref: refInput, value, onChange, validate, onValidationError, onError, onDiagnostic, strict, fields, meta: componentMeta, readOnly, writeOnly, description, widgets: instanceWidgets }) {
50
50
  const userResolver = useContext(UserResolverContext);
51
51
  const contextWidgets = useContext(WidgetsContext);
52
52
  const mergedMeta = useMemo(() => {
@@ -61,12 +61,16 @@ function SchemaComponent({ schema: schemaInput, ref: refInput, value, onChange,
61
61
  writeOnly,
62
62
  description
63
63
  ]);
64
+ const diagnostics = onDiagnostic !== void 0 || strict === true ? {
65
+ ...onDiagnostic !== void 0 ? { diagnostics: onDiagnostic } : {},
66
+ ...strict !== void 0 ? { strict } : {}
67
+ } : void 0;
64
68
  let jsonSchema;
65
69
  let zodSchema;
66
70
  let rootMeta;
67
71
  let rootDocument;
68
72
  try {
69
- const normalised = normaliseSchema(schemaInput, refInput);
73
+ const normalised = normaliseSchema(schemaInput, refInput, diagnostics !== void 0 ? { diagnostics } : void 0);
70
74
  jsonSchema = normalised.jsonSchema;
71
75
  zodSchema = normalised.zodSchema;
72
76
  rootMeta = normalised.rootMeta;
@@ -96,12 +100,14 @@ function SchemaComponent({ schema: schemaInput, ref: refInput, value, onChange,
96
100
  onValidationError,
97
101
  fields
98
102
  ]);
99
- const tree = walk(jsonSchema, {
103
+ const walkOptions = {
100
104
  componentMeta: mergedMeta,
101
105
  rootMeta,
102
106
  fieldOverrides: fields,
103
- rootDocument
104
- });
107
+ rootDocument,
108
+ ...diagnostics !== void 0 ? { diagnostics } : {}
109
+ };
110
+ const tree = walk(jsonSchema, walkOptions);
105
111
  const makeRenderChild = (currentDepth) => (childTree, childValue, childOnChange) => {
106
112
  return renderField(childTree, childValue, childOnChange, userResolver, makeRenderChild(currentDepth + 1), instanceWidgets, contextWidgets, currentDepth + 1);
107
113
  };
@@ -1,5 +1,6 @@
1
- import { w as SchemaMeta } from "../types-ag2jYLqQ.mjs";
2
- import { r as ComponentResolver } from "../renderer-DseHeliw.mjs";
1
+ import { T as SchemaMeta } from "../types-D_5ST7SS.mjs";
2
+ import { t as Diagnostic } from "../diagnostics-DzbZmcLI.mjs";
3
+ import { r as ComponentResolver } from "../renderer-BdSqllx5.mjs";
3
4
  import { WidgetMap } from "./SchemaComponent.mjs";
4
5
  import { ReactNode } from "react";
5
6
 
@@ -25,6 +26,10 @@ interface SchemaViewProps {
25
26
  resolver?: ComponentResolver;
26
27
  /** Instance-scoped widgets. */
27
28
  widgets?: WidgetMap;
29
+ /** Called with each diagnostic emitted during schema processing. */
30
+ onDiagnostic?: (diagnostic: Diagnostic) => void;
31
+ /** When true, any diagnostic becomes a thrown error. */
32
+ strict?: boolean;
28
33
  }
29
34
  /**
30
35
  * Server-safe schema renderer — no hooks, no context, no state.
@@ -40,7 +45,9 @@ declare function SchemaView({
40
45
  meta: componentMeta,
41
46
  description,
42
47
  resolver,
43
- widgets
48
+ widgets,
49
+ onDiagnostic,
50
+ strict
44
51
  }: SchemaViewProps): ReactNode;
45
52
  //#endregion
46
53
  export { SchemaView, SchemaViewProps };
@@ -1,10 +1,10 @@
1
- import { normaliseSchema } from "../core/adapter.mjs";
2
1
  import { SchemaNormalisationError, SchemaRenderError } from "../core/errors.mjs";
2
+ import { normaliseSchema } from "../core/adapter.mjs";
3
3
  import { getRenderFunction, mergeResolvers } from "../core/renderer.mjs";
4
4
  import { walk } from "../core/walker.mjs";
5
5
  import { headlessResolver } from "./headless.mjs";
6
- import { createElement, isValidElement } from "react";
7
6
  import { jsx } from "react/jsx-runtime";
7
+ import { createElement, isValidElement } from "react";
8
8
  //#region src/react/SchemaView.tsx
9
9
  /**
10
10
  * React Server Component for read-only schema rendering.
@@ -37,29 +37,35 @@ function noop() {}
37
37
  * Always renders in read-only mode. For editable forms, use
38
38
  * `<SchemaComponent>` with `"use client"`.
39
39
  */
40
- function SchemaView({ schema: schemaInput, ref: refInput, value, fields, meta: componentMeta, description, resolver, widgets }) {
40
+ function SchemaView({ schema: schemaInput, ref: refInput, value, fields, meta: componentMeta, description, resolver, widgets, onDiagnostic, strict }) {
41
41
  const mergedMeta = {
42
42
  ...componentMeta,
43
43
  readOnly: true
44
44
  };
45
45
  if (description !== void 0) mergedMeta.description = description;
46
+ const diagnostics = onDiagnostic !== void 0 || strict === true ? {
47
+ ...onDiagnostic !== void 0 ? { diagnostics: onDiagnostic } : {},
48
+ ...strict !== void 0 ? { strict } : {}
49
+ } : void 0;
46
50
  let jsonSchema;
47
51
  let rootMeta;
48
52
  let rootDocument;
49
53
  try {
50
- const normalised = normaliseSchema(schemaInput, refInput);
54
+ const normalised = normaliseSchema(schemaInput, refInput, diagnostics !== void 0 ? { diagnostics } : void 0);
51
55
  jsonSchema = normalised.jsonSchema;
52
56
  rootMeta = normalised.rootMeta;
53
57
  rootDocument = normalised.rootDocument;
54
58
  } catch (err) {
55
59
  throw new SchemaNormalisationError(err instanceof Error ? err.message : "Failed to normalise schema", schemaInput, "unknown");
56
60
  }
57
- const tree = walk(jsonSchema, {
61
+ const walkOptions = {
58
62
  componentMeta: mergedMeta,
59
63
  rootMeta,
60
64
  fieldOverrides: fields,
61
- rootDocument
62
- });
65
+ rootDocument,
66
+ ...diagnostics !== void 0 ? { diagnostics } : {}
67
+ };
68
+ const tree = walk(jsonSchema, walkOptions);
63
69
  const userResolver = resolver !== void 0 ? mergeResolvers(resolver, headlessResolver) : headlessResolver;
64
70
  const MAX_SERVER_DEPTH = 10;
65
71
  const makeRenderChild = (currentDepth) => (childTree, childValue) => {