fumadocs-openapi 11.4.2 → 12.0.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 (125) hide show
  1. package/css/generated/shared.css +1 -1
  2. package/css/preset.css +0 -1
  3. package/dist/_virtual/_rolldown/runtime.js +10 -1
  4. package/dist/generate-file.d.ts +2 -2
  5. package/dist/generate-file.js +1 -1
  6. package/dist/i18n.d.ts +6 -8
  7. package/dist/i18n.js +2 -17
  8. package/dist/index.browser.d.ts +13 -0
  9. package/dist/index.browser.js +11 -0
  10. package/dist/index.d.ts +5 -2
  11. package/dist/index.js +3 -1
  12. package/dist/operation.d.ts +133 -0
  13. package/dist/operation.js +296 -0
  14. package/dist/packages/shared-api/dist/.translations/index.d.ts +29 -0
  15. package/dist/packages/shared-api/dist/.translations/keys.js +28 -0
  16. package/dist/packages/shared-api/dist/auto-anchor/client.js +20 -0
  17. package/dist/packages/shared-api/dist/auto-anchor/index.js +17 -0
  18. package/dist/packages/shared-api/dist/codegen.d.ts +42 -0
  19. package/dist/packages/shared-api/dist/codegen.js +35 -0
  20. package/dist/packages/shared-api/dist/components/accordion.js +71 -0
  21. package/dist/packages/shared-api/dist/components/badge.js +21 -0
  22. package/dist/packages/shared-api/dist/components/collapsible.d.ts +7 -0
  23. package/dist/packages/shared-api/dist/components/collapsible.js +16 -0
  24. package/dist/packages/shared-api/dist/components/defaults.d.ts +20 -0
  25. package/dist/packages/shared-api/dist/components/defaults.js +70 -0
  26. package/dist/packages/shared-api/dist/components/dialog.js +55 -0
  27. package/dist/packages/shared-api/dist/components/input.js +14 -0
  28. package/dist/packages/shared-api/dist/components/label.js +11 -0
  29. package/dist/packages/shared-api/dist/components/playground/inputs.js +439 -0
  30. package/dist/packages/shared-api/dist/components/playground/schema.js +112 -0
  31. package/dist/packages/shared-api/dist/components/popover.js +23 -0
  32. package/dist/packages/shared-api/dist/components/schema/client.d.ts +12 -0
  33. package/dist/packages/shared-api/dist/components/schema/client.js +508 -0
  34. package/dist/packages/shared-api/dist/components/schema/index.d.ts +9 -0
  35. package/dist/packages/shared-api/dist/components/schema/index.js +28 -0
  36. package/dist/packages/shared-api/dist/components/select-tab.js +54 -0
  37. package/dist/packages/shared-api/dist/components/select.js +70 -0
  38. package/dist/packages/shared-api/dist/components/spinner.js +14 -0
  39. package/dist/packages/shared-api/dist/i18n.d.ts +3 -0
  40. package/dist/packages/shared-api/dist/i18n.js +7 -0
  41. package/dist/packages/shared-api/dist/utils/cn.js +2 -0
  42. package/dist/packages/shared-api/dist/utils/id-to-title.js +12 -0
  43. package/dist/packages/shared-api/dist/utils/is-plain-object.js +8 -0
  44. package/dist/packages/shared-api/dist/utils/merge-refs.js +11 -0
  45. package/dist/packages/shared-api/dist/utils/url.js +13 -0
  46. package/dist/{utils → packages/shared-api/dist/utils}/use-query.js +2 -1
  47. package/dist/packages/shared-api/dist/utils/use-server-store.js +56 -0
  48. package/dist/playground/auth.d.ts +37 -0
  49. package/dist/playground/auth.js +216 -21
  50. package/dist/playground/fetcher.d.ts +11 -1
  51. package/dist/playground/index.d.ts +3 -0
  52. package/dist/playground/index.js +3 -0
  53. package/dist/requests/generators/csharp.js +0 -1
  54. package/dist/requests/generators/go.js +0 -1
  55. package/dist/requests/generators/index.d.ts +4 -4
  56. package/dist/requests/generators/index.js +2 -2
  57. package/dist/requests/generators/java.js +0 -1
  58. package/dist/requests/generators/javascript.js +0 -1
  59. package/dist/requests/generators/python.js +0 -1
  60. package/dist/requests/generators/rust.js +0 -1
  61. package/dist/requests/index.d.ts +4 -0
  62. package/dist/requests/index.js +3 -0
  63. package/dist/requests/media/adapter.d.ts +1 -0
  64. package/dist/requests/media/encode.d.ts +7 -2
  65. package/dist/requests/media/resolve-adapter.d.ts +20 -0
  66. package/dist/server/index.d.ts +4 -7
  67. package/dist/server/index.js +1 -7
  68. package/dist/types.d.ts +0 -14
  69. package/dist/ui/base.d.ts +3 -2
  70. package/dist/ui/base.js +15 -166
  71. package/dist/ui/components/codeblock.js +3 -10
  72. package/dist/ui/components/heading.js +10 -19
  73. package/dist/ui/components/markdown.js +4 -6
  74. package/dist/ui/components/method-label.js +2 -17
  75. package/dist/ui/components/schema.js +28 -0
  76. package/dist/ui/index.d.ts +7 -198
  77. package/dist/ui/index.js +1 -3
  78. package/dist/ui/operation/index.js +143 -231
  79. package/dist/ui/operation/request-tabs.js +15 -23
  80. package/dist/ui/operation/response-tabs.js +9 -53
  81. package/dist/ui/operation/usage-tabs.js +35 -93
  82. package/dist/{playground → ui/playground}/client.d.ts +10 -21
  83. package/dist/ui/playground/client.js +432 -0
  84. package/dist/{playground → ui/playground}/components/oauth-dialog.js +27 -92
  85. package/dist/{playground → ui/playground}/components/result-display.d.ts +2 -2
  86. package/dist/{playground → ui/playground}/components/result-display.js +7 -7
  87. package/dist/{playground → ui/playground}/components/server-select.js +12 -13
  88. package/dist/{playground → ui/playground}/status-info.js +2 -2
  89. package/dist/{scalar → ui/scalar}/client.js +8 -6
  90. package/dist/{scalar → ui/scalar}/index.d.ts +2 -2
  91. package/dist/{scalar → ui/scalar}/index.js +3 -7
  92. package/dist/utils/create-page.d.ts +216 -0
  93. package/dist/utils/create-page.js +221 -0
  94. package/dist/utils/document/dereference.d.ts +2 -2
  95. package/dist/utils/document/dereference.js +8 -3
  96. package/dist/utils/document/load.js +2 -2
  97. package/dist/utils/get-example-requests.js +11 -13
  98. package/dist/utils/pages/builder.d.ts +15 -2
  99. package/dist/utils/pages/builder.js +6 -6
  100. package/dist/utils/pages/preset-auto.d.ts +1 -1
  101. package/dist/utils/pages/preset-auto.js +3 -3
  102. package/dist/utils/pages/to-static-data.js +4 -4
  103. package/dist/utils/pages/to-text.d.ts +1 -1
  104. package/dist/utils/pages/to-text.js +3 -5
  105. package/dist/utils/schema.js +5 -5
  106. package/dist/utils/use-server.d.ts +24 -0
  107. package/dist/utils/use-server.js +57 -0
  108. package/package.json +31 -20
  109. package/dist/node_modules/.pnpm/@scalar_openapi-upgrader@0.2.15/node_modules/@scalar/openapi-upgrader/dist/2.0-to-3.0/upgrade-from-two-to-three.js +0 -508
  110. package/dist/node_modules/.pnpm/@scalar_openapi-upgrader@0.2.15/node_modules/@scalar/openapi-upgrader/dist/3.0-to-3.1/upgrade-from-three-to-three-one.js +0 -152
  111. package/dist/node_modules/.pnpm/@scalar_openapi-upgrader@0.2.15/node_modules/@scalar/openapi-upgrader/dist/3.1-to-3.2/upgrade-from-three-one-to-three-two.js +0 -61
  112. package/dist/node_modules/.pnpm/@scalar_openapi-upgrader@0.2.15/node_modules/@scalar/openapi-upgrader/dist/helpers/traverse.js +0 -25
  113. package/dist/node_modules/.pnpm/@scalar_openapi-upgrader@0.2.15/node_modules/@scalar/openapi-upgrader/dist/upgrade.js +0 -15
  114. package/dist/playground/client.js +0 -574
  115. package/dist/ui/contexts/api.d.ts +0 -17
  116. package/dist/ui/contexts/api.js +0 -84
  117. package/dist/ui/create-client.d.ts +0 -9
  118. package/dist/ui/create-client.js +0 -7
  119. package/dist/ui/operation/context.d.ts +0 -15
  120. package/dist/ui/operation/context.js +0 -48
  121. package/dist/ui/operation/request-tabs.d.ts +0 -12
  122. package/dist/ui/operation/response-tabs.d.ts +0 -30
  123. package/dist/utils/get-example-requests.d.ts +0 -11
  124. package/dist/utils/schema.d.ts +0 -3
  125. package/dist/utils/storage-key.js +0 -15
@@ -1,61 +0,0 @@
1
- //#region ../../node_modules/.pnpm/@scalar+openapi-upgrader@0.2.15/node_modules/@scalar/openapi-upgrader/dist/3.1-to-3.2/upgrade-from-three-one-to-three-two.js
2
- /**
3
- * Recursively migrate XML object properties from 3.1 to 3.2 format
4
- */
5
- function migrateXmlObjects(obj) {
6
- if (obj === null || typeof obj !== "object") return;
7
- if (Array.isArray(obj)) {
8
- for (const item of obj) migrateXmlObjects(item);
9
- return;
10
- }
11
- if (obj.xml && typeof obj.xml === "object") {
12
- if (obj.xml.wrapped === true && obj.xml.attribute === true) throw new Error("Invalid XML configuration: wrapped and attribute cannot be true at the same time.");
13
- if (obj.xml.wrapped === true) {
14
- delete obj.xml.wrapped;
15
- obj.xml.nodeType = "element";
16
- }
17
- if (obj.xml.attribute === true) {
18
- delete obj.xml.attribute;
19
- obj.xml.nodeType = "attribute";
20
- }
21
- }
22
- for (const key in obj) if (Object.hasOwn(obj, key)) migrateXmlObjects(obj[key]);
23
- }
24
- /**
25
- * Migrate x-tagGroups to kind property on tags
26
- */
27
- function migrateTagGroups(document) {
28
- if (document["x-tagGroups"] && Array.isArray(document["x-tagGroups"])) {
29
- const tagGroups = document["x-tagGroups"];
30
- if (!document.tags) document.tags = [];
31
- const tagGroupMap = /* @__PURE__ */ new Map();
32
- for (const group of tagGroups) for (const tagName of group.tags) tagGroupMap.set(tagName, group.name);
33
- if (Array.isArray(document.tags)) {
34
- for (const tag of document.tags) if (typeof tag === "object" && tag !== null && "name" in tag) {
35
- const groupName = tagGroupMap.get(tag.name);
36
- if (groupName) {
37
- if (groupName.toLowerCase().includes("nav") || groupName.toLowerCase().includes("navigation")) tag.kind = "nav";
38
- else if (groupName.toLowerCase().includes("audience")) tag.kind = "audience";
39
- else if (groupName.toLowerCase().includes("badge")) tag.kind = "badge";
40
- else tag.kind = "nav";
41
- }
42
- }
43
- }
44
- delete document["x-tagGroups"];
45
- }
46
- }
47
- /**
48
- * Upgrade OpenAPI 3.1 to 3.2
49
- *
50
- * @see https://github.com/OAI/OpenAPI-Specification/compare/main...v3.2-dev
51
- */
52
- function upgradeFromThreeOneToThreeTwo(originalDocument) {
53
- const document = originalDocument;
54
- if (document !== null && typeof document === "object" && typeof document.openapi === "string" && document.openapi?.startsWith("3.1")) document.openapi = "3.2.0";
55
- else return document;
56
- migrateTagGroups(document);
57
- migrateXmlObjects(document);
58
- return document;
59
- }
60
- //#endregion
61
- export { upgradeFromThreeOneToThreeTwo };
@@ -1,25 +0,0 @@
1
- //#region ../../node_modules/.pnpm/@scalar+openapi-upgrader@0.2.15/node_modules/@scalar/openapi-upgrader/dist/helpers/traverse.js
2
- /**
3
- * Recursively traverses the content and applies the transform function to each node.
4
- */
5
- function traverse(content, transform, path = []) {
6
- const result = {};
7
- for (const [key, value] of Object.entries(content)) {
8
- const currentPath = [...path, key];
9
- if (Array.isArray(value)) {
10
- result[key] = value.map((item, index) => {
11
- if (typeof item === "object" && !Array.isArray(item) && item !== null) return traverse(item, transform, [...currentPath, index.toString()]);
12
- return item;
13
- });
14
- continue;
15
- }
16
- if (typeof value === "object" && value !== null) {
17
- result[key] = traverse(value, transform, currentPath);
18
- continue;
19
- }
20
- result[key] = value;
21
- }
22
- return transform(result, path);
23
- }
24
- //#endregion
25
- export { traverse };
@@ -1,15 +0,0 @@
1
- import { upgradeFromThreeOneToThreeTwo } from "./3.1-to-3.2/upgrade-from-three-one-to-three-two.js";
2
- import { upgradeFromTwoToThree } from "./2.0-to-3.0/upgrade-from-two-to-three.js";
3
- import { upgradeFromThreeToThreeOne } from "./3.0-to-3.1/upgrade-from-three-to-three-one.js";
4
- //#region ../../node_modules/.pnpm/@scalar+openapi-upgrader@0.2.15/node_modules/@scalar/openapi-upgrader/dist/upgrade.js
5
- function upgrade(value, targetVersion) {
6
- const openapi30 = upgradeFromTwoToThree(value);
7
- if (targetVersion === "3.0") return openapi30;
8
- const openapi31 = upgradeFromThreeToThreeOne(openapi30);
9
- if (targetVersion === "3.1") return openapi31;
10
- const openapi32 = upgradeFromThreeOneToThreeTwo(openapi31);
11
- if (targetVersion === "3.2") return openapi32;
12
- return openapi32;
13
- }
14
- //#endregion
15
- export { upgrade };
@@ -1,574 +0,0 @@
1
- "use client";
2
- import { getPreferredType } from "../utils/schema.js";
3
- import { useStorageKey } from "../utils/storage-key.js";
4
- import { useRenderContext, useServerContext } from "../ui/contexts/api.js";
5
- import { cn } from "../utils/cn.js";
6
- import { DefaultResultDisplay } from "./components/result-display.js";
7
- import { pathnameFromRequest } from "../requests/generators/index.js";
8
- import { MethodLabel } from "../ui/components/method-label.js";
9
- import { useQuery } from "../utils/use-query.js";
10
- import { encodeRequestData } from "../requests/media/encode.js";
11
- import ServerSelect from "./components/server-select.js";
12
- import { useOperationContext } from "../ui/operation/context.js";
13
- import { useAuth } from "./auth.js";
14
- import { OAuthDialog, OAuthDialogContent, OAuthDialogTrigger } from "./components/oauth-dialog.js";
15
- import { dereferenceShallow } from "@fumadocs/api-docs/schema/dereference";
16
- import { Fragment, useEffect, useMemo, useRef, useState } from "react";
17
- import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
18
- import { ChevronDown, LoaderCircle, PlusIcon } from "lucide-react";
19
- import { useTranslations } from "@fuma-translate/react";
20
- import { buttonVariants } from "fumadocs-ui/components/ui/button";
21
- import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@fumadocs/api-docs/components/collapsible";
22
- import { SchemaProvider, anyFields, useResolvedSchema } from "@fumadocs/api-docs/components/playground/schema";
23
- import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@fumadocs/api-docs/components/select";
24
- import { labelVariants } from "@fumadocs/api-docs/components/input";
25
- import { StfProvider, useDataEngine, useFieldValue, useListener, useStf } from "@fumari/stf";
26
- import { joinURL, resolveServerUrl } from "@fumadocs/api-docs/utils/url";
27
- import { arrayStartsWith, objectGet, objectSet, stringifyFieldKey } from "@fumari/stf/lib/utils";
28
- import { FieldInput, FieldSet, JsonInput, ObjectInput } from "@fumadocs/api-docs/components/playground/inputs";
29
- import { useOnChange } from "fumadocs-core/utils/use-on-change";
30
- import { Spinner } from "@fumadocs/api-docs/components/spinner";
31
- //#region src/playground/client.tsx
32
- function PlaygroundClient({ route, method, operation, pathItem, writeOnly, readOnly, ...rest }) {
33
- const t = useTranslations({ note: "playground" });
34
- const ctx = useRenderContext();
35
- const { dereferenced } = ctx.schema;
36
- const { parameters, body } = useMemo(() => {
37
- const parameters = [];
38
- if (operation.parameters) for (const p of operation.parameters) parameters.push(dereferenceShallow(p));
39
- if (pathItem.parameters) for (const p of pathItem.parameters) parameters.push(dereferenceShallow(p));
40
- let body;
41
- if (operation.requestBody) {
42
- const content = dereferenceShallow(operation.requestBody).content;
43
- const mediaType = content ? getPreferredType(content) : void 0;
44
- if (content && mediaType) body = {
45
- mediaType,
46
- schema: dereferenceShallow(content[mediaType]).schema ?? true
47
- };
48
- }
49
- return {
50
- body,
51
- parameters
52
- };
53
- }, [operation, pathItem]);
54
- const securityEntries = useMemo(() => {
55
- const result = [];
56
- const security = operation.security ?? dereferenced.security ?? [];
57
- if (security.length === 0) return result;
58
- for (const map of security) {
59
- const list = [];
60
- for (const [key, scopes] of Object.entries(map)) list.push({
61
- id: key,
62
- scopes
63
- });
64
- if (list.length > 0) result.push(list);
65
- }
66
- return result;
67
- }, [dereferenced, operation.security]);
68
- const { example: exampleId, examples, setExampleData } = useOperationContext();
69
- const { server } = useServerContext();
70
- const { mediaAdapters, playground: { components: { ResultDisplay = DefaultResultDisplay, CollapsiblePanel = DefaultCollapsiblePanel } = {}, fetchOptions, renderBodyField } = {} } = useRenderContext();
71
- const defaultValues = useMemo(() => {
72
- const requestData = examples.find((example) => example.id === exampleId)?.data;
73
- return {
74
- path: requestData?.path ?? {},
75
- query: requestData?.query ?? {},
76
- header: requestData?.header ?? {},
77
- body: requestData?.body ?? {},
78
- cookie: requestData?.cookie ?? {}
79
- };
80
- }, [examples, exampleId]);
81
- const stf = useStf({ defaultValues });
82
- const { inputs, requirementId, setRequirementId, mapInputs, initAuthInputs } = useAuthInputs(stf.dataEngine, securityEntries);
83
- const testQuery = useQuery(async (input) => {
84
- const fetcher = await import("./fetcher.js").then((mod) => mod.createBrowserFetcher(mediaAdapters, {
85
- proxyUrl: ctx.proxyUrl,
86
- ...fetchOptions
87
- }));
88
- const encoded = encodeRequestData({
89
- ...mapInputs(input),
90
- method,
91
- bodyMediaType: body?.mediaType
92
- }, mediaAdapters, parameters);
93
- return fetcher.fetch(joinURL(new URL(server ? resolveServerUrl(server.url, server.variables) : "/", window.location.origin).href, pathnameFromRequest(route, encoded)), encoded);
94
- });
95
- const timerRef = useRef(null);
96
- const stfSync = useRef(false);
97
- function triggerExampleUpdate() {
98
- const data = {
99
- ...mapInputs(stf.dataEngine.getData()),
100
- method,
101
- bodyMediaType: body?.mediaType
102
- };
103
- setExampleData(data, encodeRequestData(data, mediaAdapters, parameters));
104
- }
105
- useListener({
106
- stf,
107
- onUpdate() {
108
- if (!stfSync.current) return;
109
- if (timerRef.current) window.clearTimeout(timerRef.current);
110
- timerRef.current = window.setTimeout(triggerExampleUpdate, 400);
111
- }
112
- });
113
- useEffect(() => {
114
- if (stf.dataEngine.getData() === defaultValues) return;
115
- stf.dataEngine.reset(defaultValues);
116
- }, [defaultValues]);
117
- useEffect(() => {
118
- const reset = initAuthInputs();
119
- triggerExampleUpdate();
120
- stfSync.current = true;
121
- return () => {
122
- stfSync.current = false;
123
- reset();
124
- };
125
- }, [defaultValues, inputs]);
126
- return /* @__PURE__ */ jsx(StfProvider, {
127
- value: stf,
128
- children: /* @__PURE__ */ jsx(SchemaProvider, {
129
- docRoot: dereferenced,
130
- writeOnly,
131
- readOnly,
132
- children: /* @__PURE__ */ jsxs("form", {
133
- ...rest,
134
- className: cn("not-prose flex flex-col rounded-xl border shadow-md overflow-hidden bg-fd-card text-fd-card-foreground", rest.className),
135
- onSubmit: (e) => {
136
- testQuery.start(stf.dataEngine.getData());
137
- e.preventDefault();
138
- },
139
- children: [
140
- /* @__PURE__ */ jsx(ServerSelect, { className: "border-b" }),
141
- /* @__PURE__ */ jsxs("div", {
142
- className: "flex flex-row items-center gap-2 text-sm p-3 not-last:pb-0",
143
- children: [
144
- /* @__PURE__ */ jsx(MethodLabel, { children: method }),
145
- /* @__PURE__ */ jsx(Route, {
146
- route,
147
- className: cn("flex-1", operation.deprecated && "line-through")
148
- }),
149
- /* @__PURE__ */ jsx("button", {
150
- type: "submit",
151
- className: cn(buttonVariants({
152
- color: "primary",
153
- size: "sm"
154
- }), "w-14 py-1.5"),
155
- disabled: testQuery.isLoading,
156
- children: testQuery.isLoading ? /* @__PURE__ */ jsx(LoaderCircle, { className: "size-4 animate-spin" }) : t("Send")
157
- })
158
- ]
159
- }),
160
- testQuery.data ? /* @__PURE__ */ jsx(ResultDisplay, {
161
- data: testQuery.data,
162
- reset: testQuery.reset
163
- }) : null,
164
- securityEntries.length > 0 && /* @__PURE__ */ jsx(SecurityRequirements, {
165
- securities: securityEntries,
166
- securityId: requirementId,
167
- setSecurityId: setRequirementId,
168
- children: inputs.map((input) => /* @__PURE__ */ jsx(Fragment, { children: input.children }, stringifyFieldKey(input.fieldName)))
169
- }),
170
- /* @__PURE__ */ jsx(ParametersForm, { parameters }),
171
- body && /* @__PURE__ */ jsx(CollapsiblePanel, {
172
- "data-type": "body",
173
- title: t("Body"),
174
- children: renderBodyField ? renderBodyField("body", body) : /* @__PURE__ */ jsx(BodyInput, { field: body.schema })
175
- })
176
- ]
177
- })
178
- })
179
- });
180
- }
181
- function SecurityRequirements({ securities, setSecurityId, securityId, children }) {
182
- const t = useTranslations({ note: "playground" });
183
- const { isLoading, error } = useAuth();
184
- const defaultOpen = isLoading || error != null;
185
- const [open, setOpen] = useState(defaultOpen);
186
- const { schema: { dereferenced, resolve }, playground: { components: { CollapsiblePanel = DefaultCollapsiblePanel } = {} } = {} } = useRenderContext();
187
- const schemes = dereferenced.components?.securitySchemes;
188
- useOnChange(defaultOpen, () => {
189
- if (defaultOpen) setOpen(true);
190
- });
191
- const items = securities.map((requirement, i) => {
192
- if (requirement.length === 1) {
193
- const scheme = resolve(schemes?.[requirement[0].id]);
194
- return {
195
- value: i,
196
- label: /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("p", {
197
- className: cn("font-mono font-medium", scheme?.deprecated && "text-fd-muted-foreground line-through"),
198
- children: requirement[0].id
199
- }), /* @__PURE__ */ jsx("p", {
200
- className: "text-fd-muted-foreground whitespace-pre-wrap",
201
- children: scheme?.description
202
- })] })
203
- };
204
- }
205
- return {
206
- value: i,
207
- label: /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("p", {
208
- className: "inline-flex items-center gap-1 font-mono font-medium",
209
- children: requirement.map((item, i) => /* @__PURE__ */ jsxs(Fragment, { children: [i > 0 && /* @__PURE__ */ jsx(PlusIcon, { className: "text-fd-muted-foreground size-3.5" }), /* @__PURE__ */ jsx("span", {
210
- className: cn(resolve(schemes?.[item.id])?.deprecated && "text-fd-muted-foreground line-through"),
211
- children: item.id
212
- })] }, i))
213
- }), /* @__PURE__ */ jsx("ul", {
214
- className: "text-fd-muted-foreground whitespace-pre-wrap list-disc list-inside",
215
- children: requirement.map((item, i) => /* @__PURE__ */ jsx("li", {
216
- className: "empty:hidden",
217
- children: resolve(schemes?.[item.id])?.description
218
- }, i))
219
- })] })
220
- };
221
- });
222
- return /* @__PURE__ */ jsxs(CollapsiblePanel, {
223
- title: /* @__PURE__ */ jsxs(Fragment$1, { children: [t("Authorization"), isLoading && /* @__PURE__ */ jsxs("span", {
224
- className: "border-s ps-2 inline-flex items-center gap-1.5 text-fd-muted-foreground text-xs font-mono",
225
- children: [
226
- /* @__PURE__ */ jsx(Spinner, {}),
227
- " ",
228
- t("Fetching token...")
229
- ]
230
- })] }),
231
- "data-type": "authorization",
232
- open,
233
- onOpenChange: setOpen,
234
- children: [
235
- error != null && /* @__PURE__ */ jsxs("div", {
236
- className: "p-2 border rounded-lg bg-fd-secondary",
237
- children: [/* @__PURE__ */ jsx("p", {
238
- className: "text-fd-muted-foreground font-medium mb-1",
239
- children: t("Failed to fetch token")
240
- }), /* @__PURE__ */ jsx("p", { children: String(error) })]
241
- }),
242
- /* @__PURE__ */ jsxs(Select, {
243
- items,
244
- value: securityId,
245
- onValueChange: (v) => v !== null && setSecurityId(v),
246
- children: [/* @__PURE__ */ jsx(SelectTrigger, { children: /* @__PURE__ */ jsx(SelectValue, {}) }), /* @__PURE__ */ jsx(SelectContent, { children: items.map(({ value, label }) => /* @__PURE__ */ jsx(SelectItem, {
247
- value,
248
- children: label
249
- }, value)) })]
250
- }),
251
- children
252
- ]
253
- });
254
- }
255
- const ParamTypes = [
256
- "path",
257
- "header",
258
- "cookie",
259
- "query"
260
- ];
261
- function ParameterItem({ type, parameters }) {
262
- const { renderParameterField } = useRenderContext().playground ?? {};
263
- return parameters.map((field) => {
264
- const fieldName = [type, field.name];
265
- if (renderParameterField) return renderParameterField(fieldName, field);
266
- const contentTypes = field.content && Object.keys(field.content);
267
- const schema = field.content && contentTypes && contentTypes.length > 0 ? field.content[contentTypes[0]].schema : field.schema;
268
- return /* @__PURE__ */ jsx(FieldSet, {
269
- name: field.name,
270
- fieldName,
271
- field: schema ?? anyFields,
272
- isRequired: field.required
273
- }, stringifyFieldKey(fieldName));
274
- });
275
- }
276
- function ParametersForm({ parameters }) {
277
- const { components: { CollapsiblePanel = DefaultCollapsiblePanel } = {} } = useRenderContext().playground ?? {};
278
- const t = useTranslations({ note: "playground" });
279
- const displayNames = {
280
- header: t("Header"),
281
- cookie: t("Cookies"),
282
- query: t("Query"),
283
- path: t("Path")
284
- };
285
- return ParamTypes.map((type) => {
286
- const items = parameters.filter((v) => v.in === type);
287
- if (items.length === 0) return;
288
- return /* @__PURE__ */ jsx(CollapsiblePanel, {
289
- "data-type": type,
290
- title: displayNames[type],
291
- children: /* @__PURE__ */ jsx(ParameterItem, {
292
- parameters: items,
293
- type
294
- })
295
- }, type);
296
- });
297
- }
298
- function BodyInput({ field: _field }) {
299
- const field = useResolvedSchema(_field);
300
- const [isJson, setIsJson] = useState(false);
301
- const t = useTranslations({ note: "playground" });
302
- if (field.format === "binary") return /* @__PURE__ */ jsx(FieldSet, {
303
- field,
304
- fieldName: ["body"],
305
- isRequired: true
306
- });
307
- if (isJson) return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("button", {
308
- className: cn(buttonVariants({
309
- color: "secondary",
310
- size: "sm",
311
- className: "w-fit font-mono p-2"
312
- })),
313
- onClick: () => setIsJson(false),
314
- type: "button",
315
- children: t("Close JSON Editor")
316
- }), /* @__PURE__ */ jsx(JsonInput, { fieldName: ["body"] })] });
317
- return /* @__PURE__ */ jsx(FieldSet, {
318
- field,
319
- fieldName: ["body"],
320
- collapsible: false,
321
- isRequired: true,
322
- name: /* @__PURE__ */ jsx("button", {
323
- type: "button",
324
- className: cn(buttonVariants({
325
- color: "secondary",
326
- size: "sm",
327
- className: "p-2"
328
- })),
329
- onClick: () => setIsJson(true),
330
- children: t("Open JSON Editor")
331
- })
332
- });
333
- }
334
- function useAuthInputs(engine, requirements) {
335
- const authCtx = useAuth();
336
- const storageKeys = useStorageKey();
337
- const t = useTranslations({ note: "playground" });
338
- const ctx = useRenderContext();
339
- const { resolve } = ctx.schema;
340
- const schemes = ctx.schema.dereferenced.components?.securitySchemes;
341
- const { transformAuthInputs } = ctx.playground ?? {};
342
- const [requirementId, setRequirementId] = useState(() => {
343
- if (!schemes || requirements.length === 0) return -1;
344
- const idx = requirements.findIndex((s) => s.every((item) => !resolve(schemes[item.id]).deprecated));
345
- return idx !== -1 ? idx : 0;
346
- });
347
- const requirement = requirementId === -1 ? null : requirements[requirementId];
348
- let inputs = useMemo(() => {
349
- if (!requirement || !schemes) return [];
350
- return requirement.map((item) => {
351
- const scheme = resolve(schemes?.[item.id]);
352
- if (scheme.type === "http" && scheme.scheme === "basic") {
353
- const fieldName = ["header", "Authorization"];
354
- return {
355
- fieldName,
356
- schemeId: item.id,
357
- storageKey: storageKeys.AuthField(item.id),
358
- defaultValue: {
359
- username: "",
360
- password: ""
361
- },
362
- mapOutput(out) {
363
- if (out && typeof out === "object") {
364
- const obj = out;
365
- return `Basic ${btoa(`${obj.username ?? ""}:${obj.password ?? ""}`)}`;
366
- }
367
- return out;
368
- },
369
- children: /* @__PURE__ */ jsx(ObjectInput, {
370
- field: {
371
- type: "object",
372
- properties: {
373
- username: { type: "string" },
374
- password: { type: "string" }
375
- }
376
- },
377
- fieldName
378
- })
379
- };
380
- }
381
- if (scheme.type === "oauth2") {
382
- const fieldName = ["header", "Authorization"];
383
- return {
384
- fieldName,
385
- schemeId: item.id,
386
- storageKey: storageKeys.AuthField(item.id),
387
- defaultValue: "Bearer ",
388
- children: /* @__PURE__ */ jsx(OAuth2Input, {
389
- fieldName,
390
- security: item
391
- })
392
- };
393
- }
394
- if (scheme.type === "http") {
395
- const fieldName = ["header", "Authorization"];
396
- return {
397
- fieldName,
398
- schemeId: item.id,
399
- storageKey: storageKeys.AuthField(item.id),
400
- defaultValue: "Bearer ",
401
- children: /* @__PURE__ */ jsx(FieldSet, {
402
- name: `${t("Authorization")} (${t("Header")})`,
403
- fieldName,
404
- field: { type: "string" }
405
- })
406
- };
407
- }
408
- if (scheme.type === "apiKey") {
409
- const fieldName = [scheme.in, scheme.name];
410
- return {
411
- fieldName,
412
- schemeId: item.id,
413
- defaultValue: "",
414
- storageKey: storageKeys.AuthField(item.id),
415
- children: /* @__PURE__ */ jsx(FieldSet, {
416
- fieldName,
417
- name: `${scheme.name} (${scheme.in})`,
418
- field: { type: "string" }
419
- })
420
- };
421
- }
422
- const fieldName = ["header", "Authorization"];
423
- return {
424
- fieldName,
425
- schemeId: item.id,
426
- defaultValue: "",
427
- storageKey: storageKeys.AuthField(item.id),
428
- children: /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(FieldSet, {
429
- name: `${t("Authorization")} (${t("Header")})`,
430
- fieldName,
431
- field: { type: "string" }
432
- }), /* @__PURE__ */ jsx("p", {
433
- className: "text-fd-muted-foreground text-xs",
434
- children: t("OpenID Connect is not supported at the moment, you can still set an access token here.")
435
- })] })
436
- };
437
- });
438
- }, [
439
- requirement,
440
- storageKeys,
441
- schemes,
442
- resolve,
443
- t
444
- ]);
445
- if (transformAuthInputs) inputs = transformAuthInputs(inputs);
446
- useListener({
447
- stf: engine,
448
- onUpdate(key) {
449
- for (const item of inputs) {
450
- if (!arrayStartsWith(item.fieldName, key)) continue;
451
- const value = engine.get(item.fieldName);
452
- if (value != null) localStorage.setItem(item.storageKey, JSON.stringify(value));
453
- }
454
- }
455
- });
456
- useOnChange(authCtx.updatedSchemeId, () => {
457
- const { updatedSchemeId } = authCtx;
458
- if (!updatedSchemeId) return;
459
- const { token } = authCtx.store[updatedSchemeId];
460
- const input = inputs.find((input) => input.schemeId === updatedSchemeId);
461
- if (input) {
462
- engine.update(input.fieldName, token);
463
- return;
464
- }
465
- const idx = requirements.findIndex((requirement) => requirement.some((item) => item.id === updatedSchemeId));
466
- if (idx !== -1) {
467
- localStorage.setItem(storageKeys.AuthField(updatedSchemeId), JSON.stringify(token));
468
- setRequirementId(idx);
469
- }
470
- });
471
- return {
472
- inputs,
473
- requirementId,
474
- setRequirementId,
475
- mapInputs(values) {
476
- const cloned = structuredClone(values);
477
- for (const item of inputs) {
478
- if (!item.mapOutput) continue;
479
- objectSet(cloned, item.fieldName, item.mapOutput(objectGet(cloned, item.fieldName)));
480
- }
481
- return cloned;
482
- },
483
- initAuthInputs() {
484
- for (const item of inputs) {
485
- const stored = localStorage.getItem(item.storageKey);
486
- if (stored) {
487
- const parsed = JSON.parse(stored);
488
- if (typeof parsed === typeof item.defaultValue) {
489
- engine.init(item.fieldName, parsed);
490
- continue;
491
- }
492
- }
493
- engine.init(item.fieldName, item.defaultValue);
494
- }
495
- return () => {
496
- for (const item of inputs) engine.delete(item.fieldName);
497
- };
498
- }
499
- };
500
- }
501
- function OAuth2Input({ fieldName, security }) {
502
- const [open, setOpen] = useState(false);
503
- const engine = useDataEngine();
504
- const t = useTranslations({ note: "playground" });
505
- return /* @__PURE__ */ jsxs("fieldset", {
506
- className: "flex flex-col gap-2",
507
- children: [/* @__PURE__ */ jsx("label", {
508
- htmlFor: stringifyFieldKey(fieldName),
509
- className: cn(labelVariants()),
510
- children: t("Access Token")
511
- }), /* @__PURE__ */ jsxs("div", {
512
- className: "flex gap-2",
513
- children: [/* @__PURE__ */ jsx(FieldInput, {
514
- fieldName,
515
- field: { type: "string" },
516
- className: "flex-1"
517
- }), /* @__PURE__ */ jsxs(OAuthDialog, {
518
- open,
519
- onOpenChange: setOpen,
520
- children: [/* @__PURE__ */ jsx(OAuthDialogTrigger, {
521
- type: "button",
522
- className: cn(buttonVariants({
523
- size: "sm",
524
- color: "secondary"
525
- })),
526
- children: t("Authorize")
527
- }), /* @__PURE__ */ jsx(OAuthDialogContent, {
528
- setOpen,
529
- schemeId: security.id,
530
- scopes: security.scopes,
531
- setToken: (token) => engine.update(["header", "Authorization"], token)
532
- })]
533
- })]
534
- })]
535
- });
536
- }
537
- function Route({ route, ...props }) {
538
- return /* @__PURE__ */ jsx("div", {
539
- ...props,
540
- className: cn("flex flex-row items-center gap-0.5 overflow-auto text-nowrap", props.className),
541
- children: route.split("/").map((part, index) => /* @__PURE__ */ jsxs(Fragment, { children: [index > 0 && /* @__PURE__ */ jsx("span", {
542
- className: "text-fd-muted-foreground",
543
- children: "/"
544
- }), part.startsWith("{") && part.endsWith("}") ? /* @__PURE__ */ jsx("code", {
545
- className: "bg-fd-primary/10 text-fd-primary",
546
- children: part
547
- }) : /* @__PURE__ */ jsx("code", {
548
- className: "text-fd-foreground",
549
- children: part
550
- })] }, index))
551
- });
552
- }
553
- function DefaultCollapsiblePanel({ title, children, ...props }) {
554
- return /* @__PURE__ */ jsxs(Collapsible, {
555
- ...props,
556
- className: cn("border-b last:border-b-0", props.className),
557
- children: [/* @__PURE__ */ jsxs(CollapsibleTrigger, {
558
- className: "group w-full flex items-center gap-2 p-3 text-sm font-medium",
559
- children: [title, /* @__PURE__ */ jsx(ChevronDown, { className: "ms-auto size-3.5 text-fd-muted-foreground group-data-[panel-open]:rotate-180" })]
560
- }), /* @__PURE__ */ jsx(CollapsibleContent, { children: /* @__PURE__ */ jsx("div", {
561
- className: "flex flex-col gap-3 p-3 pt-1",
562
- children
563
- }) })]
564
- });
565
- }
566
- const Custom = { useController(fieldName, options) {
567
- const [value, setValue] = useFieldValue(fieldName, options);
568
- return {
569
- value,
570
- setValue
571
- };
572
- } };
573
- //#endregion
574
- export { Custom, DefaultCollapsiblePanel, DefaultResultDisplay, PlaygroundClient as default };
@@ -1,17 +0,0 @@
1
- import { RenderContext, ServerObject } from "../../types.js";
2
- import { ReactNode } from "react";
3
- //#region src/ui/contexts/api.d.ts
4
- interface ServerContextType {
5
- servers?: ServerObject[];
6
- server: SelectedServer | null;
7
- setServer: (value: string) => void;
8
- setServerVariables: (value: Record<string, string>) => void;
9
- }
10
- export interface SelectedServer {
11
- url: string;
12
- name?: string;
13
- variables: Record<string, string>;
14
- }
15
- export declare function useRenderContext(): RenderContext;
16
- export declare function useServerContext(): ServerContextType;
17
- //#endregion