fumadocs-openapi 10.2.4 → 10.2.5

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 (50) hide show
  1. package/dist/generate-file.js.map +1 -1
  2. package/dist/playground/client.d.ts +11 -12
  3. package/dist/playground/client.d.ts.map +1 -1
  4. package/dist/playground/client.js +70 -74
  5. package/dist/playground/client.js.map +1 -1
  6. package/dist/playground/components/inputs.js +198 -187
  7. package/dist/playground/components/inputs.js.map +1 -1
  8. package/dist/playground/components/oauth-dialog.js +2 -2
  9. package/dist/playground/components/server-select.js +24 -25
  10. package/dist/playground/components/server-select.js.map +1 -1
  11. package/dist/playground/fetcher.js.map +1 -1
  12. package/dist/playground/index.js.map +1 -1
  13. package/dist/playground/schema.d.ts +1 -0
  14. package/dist/playground/schema.d.ts.map +1 -1
  15. package/dist/playground/schema.js +10 -12
  16. package/dist/playground/schema.js.map +1 -1
  17. package/dist/playground/status-info.js.map +1 -1
  18. package/dist/requests/generators/csharp.js.map +1 -1
  19. package/dist/requests/generators/curl.js.map +1 -1
  20. package/dist/requests/generators/go.js.map +1 -1
  21. package/dist/requests/generators/index.js.map +1 -1
  22. package/dist/requests/generators/java.js.map +1 -1
  23. package/dist/requests/generators/javascript.js.map +1 -1
  24. package/dist/requests/generators/python.js.map +1 -1
  25. package/dist/requests/media/adapter.js.map +1 -1
  26. package/dist/requests/media/encode.js.map +1 -1
  27. package/dist/requests/media/resolve-adapter.js +4 -0
  28. package/dist/requests/media/resolve-adapter.js.map +1 -1
  29. package/dist/server/create.js.map +1 -1
  30. package/dist/server/proxy.js.map +1 -1
  31. package/dist/server/source-api.js.map +1 -1
  32. package/dist/ui/api-page.js.map +1 -1
  33. package/dist/ui/contexts/api.js.map +1 -1
  34. package/dist/ui/operation/index.js.map +1 -1
  35. package/dist/ui/operation/request-tabs.js.map +1 -1
  36. package/dist/ui/operation/response-tabs.js.map +1 -1
  37. package/dist/ui/operation/usage-tabs/client.js.map +1 -1
  38. package/dist/ui/operation/usage-tabs/index.js.map +1 -1
  39. package/dist/ui/schema/client.d.ts.map +1 -1
  40. package/dist/ui/schema/client.js +120 -114
  41. package/dist/ui/schema/client.js.map +1 -1
  42. package/dist/ui/schema/index.js +1 -1
  43. package/dist/ui/schema/index.js.map +1 -1
  44. package/dist/utils/id-to-title.js.map +1 -1
  45. package/dist/utils/merge-schema.js.map +1 -1
  46. package/dist/utils/pages/builder.js.map +1 -1
  47. package/dist/utils/pages/preset-auto.js.map +1 -1
  48. package/dist/utils/pages/to-static-data.js.map +1 -1
  49. package/dist/utils/pages/to-text.js.map +1 -1
  50. package/package.json +13 -12
@@ -1 +1 @@
1
- {"version":3,"file":"generate-file.js","names":["files: OutputFile[]","generated: Record<string, OutputFile[]>","generatedEntries: Record<string, OutputEntry[]>","entries","file: OutputFile","context: BeforeWriteContext","urlFn: (path: string) => string","path","content: string[]"],"sources":["../src/generate-file.ts"],"sourcesContent":["import { mkdir, writeFile } from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { generateDocument, type PagesToTextOptions, toText } from './utils/pages/to-text';\nimport type { ProcessedDocument } from '@/utils/process-document';\nimport type { OpenAPIServer } from '@/server';\nimport { createGetUrl, getSlugs } from 'fumadocs-core/source';\nimport { createAutoPreset, type SchemaToPagesOptions } from '@/utils/pages/preset-auto';\nimport { fromSchema, type OutputEntry } from '@/utils/pages/builder';\n\nexport interface OutputFile {\n path: string;\n content: string;\n}\n\ninterface IndexConfig {\n items: IndexItem[] | ((ctx: BeforeWriteContext) => IndexItem[]);\n\n /**\n * Generate URLs for cards\n */\n url:\n | ((filePath: string) => string)\n | {\n baseUrl: string;\n /**\n * Base content directory\n */\n contentDir: string;\n };\n}\n\ninterface IndexItem {\n path: string;\n title?: string;\n description?: string;\n\n /**\n * Specify linked pages:\n * - items in `inputs` to include all generated pages of a specific schema.\n * - specific Markdown/MDX files.\n */\n only?: string[];\n}\n\ninterface GenerateFilesConfig extends PagesToTextOptions {\n /**\n * the OpenAPI server object\n */\n input: OpenAPIServer;\n\n /**\n * Output directory\n */\n output: string;\n\n /**\n * Generate index files with cards linking to generated pages.\n */\n index?: IndexConfig;\n\n /**\n * Can add/change/remove output files before writing to file system\n **/\n beforeWrite?: (this: BeforeWriteContext, files: OutputFile[]) => void | Promise<void>;\n}\n\nexport type Config = SchemaToPagesOptions & GenerateFilesConfig;\n\ninterface BeforeWriteContext {\n readonly generated: Record<string, OutputFile[]>;\n readonly generatedEntries: Record<string, OutputEntry[]>;\n readonly documents: Record<string, ProcessedDocument>;\n}\n\nexport async function generateFiles(options: Config): Promise<void> {\n const files = await generateFilesOnly(options);\n const { output } = options;\n\n await Promise.all(\n files.map(async (file) => {\n const filePath = path.join(output, file.path);\n\n await mkdir(path.dirname(filePath), { recursive: true });\n await writeFile(filePath, file.content);\n console.log(`Generated: ${filePath}`);\n }),\n );\n}\n\nexport async function generateFilesOnly(\n options: SchemaToPagesOptions & Omit<GenerateFilesConfig, 'output'>,\n): Promise<OutputFile[]> {\n const schemas = await options.input.getSchemas();\n\n const files: OutputFile[] = [];\n const generated: Record<string, OutputFile[]> = {};\n const generatedEntries: Record<string, OutputEntry[]> = {};\n\n const entries = Object.entries(schemas);\n if (entries.length === 0) {\n throw new Error('No input files found.');\n }\n const preset = createAutoPreset(options);\n for (const [id, schema] of entries) {\n const entries = fromSchema(id, schema, preset);\n const schemaFiles = (generated[id] ??= []);\n\n generatedEntries[id] = entries;\n for (const entry of entries) {\n const file: OutputFile = {\n path: entry.path,\n content: toText(entry, schema, options),\n };\n\n schemaFiles.push(file);\n files.push(file);\n }\n }\n\n const context: BeforeWriteContext = {\n generated,\n generatedEntries,\n documents: schemas,\n };\n\n if (options.index) {\n writeIndexFiles(files, context, options);\n }\n\n await options.beforeWrite?.call(context, files);\n return files;\n}\n\nfunction writeIndexFiles(\n files: OutputFile[],\n context: BeforeWriteContext,\n options: SchemaToPagesOptions & Omit<GenerateFilesConfig, 'output'>,\n) {\n const { generatedEntries } = context;\n const { items, url } = options.index!;\n\n let urlFn: (path: string) => string;\n if (typeof url === 'object') {\n const getUrl = createGetUrl(url.baseUrl);\n\n urlFn = (file) => getUrl(getSlugs(path.relative(url.contentDir, file)));\n } else {\n urlFn = url;\n }\n\n function findEntryByPath(path: string) {\n for (const entries of Object.values(generatedEntries)) {\n const match = entries.find((entry) => entry.path === path);\n\n if (match) return match;\n }\n }\n\n function fileContent(index: IndexItem): string {\n const content: string[] = [];\n content.push('<Cards>');\n const pathToEntry = new Map<string, OutputEntry>();\n const only = index.only ?? Object.keys(context.generated);\n\n for (const item of only) {\n if (generatedEntries[item]) {\n for (const entry of generatedEntries[item]) {\n pathToEntry.set(entry.path, entry);\n }\n } else {\n const match = findEntryByPath(item);\n if (!match) {\n throw new Error(\n `${item} does not exist on \"input\", available: ${Object.keys(generatedEntries).join(', ')}.`,\n );\n }\n\n pathToEntry.set(match.path, match);\n }\n }\n\n for (const file of pathToEntry.values()) {\n const descriptionAttr = file.info.description\n ? `description=${JSON.stringify(file.info.description)} `\n : '';\n content.push(\n `<Card href=\"${urlFn(file.path)}\" title=${JSON.stringify(file.info.title)} ${descriptionAttr}/>`,\n );\n }\n\n content.push('</Cards>');\n return generateDocument(\n {\n title: index.title ?? 'Overview',\n description: index.description,\n },\n content.join('\\n'),\n options,\n );\n }\n\n for (const item of typeof items === 'function' ? items(context) : items) {\n files.push({\n path: path.extname(item.path).length === 0 ? `${item.path}.mdx` : item.path,\n content: fileContent(item),\n });\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"generate-file.js","names":["entries","path"],"sources":["../src/generate-file.ts"],"sourcesContent":["import { mkdir, writeFile } from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { generateDocument, type PagesToTextOptions, toText } from './utils/pages/to-text';\nimport type { ProcessedDocument } from '@/utils/process-document';\nimport type { OpenAPIServer } from '@/server';\nimport { createGetUrl, getSlugs } from 'fumadocs-core/source';\nimport { createAutoPreset, type SchemaToPagesOptions } from '@/utils/pages/preset-auto';\nimport { fromSchema, type OutputEntry } from '@/utils/pages/builder';\n\nexport interface OutputFile {\n path: string;\n content: string;\n}\n\ninterface IndexConfig {\n items: IndexItem[] | ((ctx: BeforeWriteContext) => IndexItem[]);\n\n /**\n * Generate URLs for cards\n */\n url:\n | ((filePath: string) => string)\n | {\n baseUrl: string;\n /**\n * Base content directory\n */\n contentDir: string;\n };\n}\n\ninterface IndexItem {\n path: string;\n title?: string;\n description?: string;\n\n /**\n * Specify linked pages:\n * - items in `inputs` to include all generated pages of a specific schema.\n * - specific Markdown/MDX files.\n */\n only?: string[];\n}\n\ninterface GenerateFilesConfig extends PagesToTextOptions {\n /**\n * the OpenAPI server object\n */\n input: OpenAPIServer;\n\n /**\n * Output directory\n */\n output: string;\n\n /**\n * Generate index files with cards linking to generated pages.\n */\n index?: IndexConfig;\n\n /**\n * Can add/change/remove output files before writing to file system\n **/\n beforeWrite?: (this: BeforeWriteContext, files: OutputFile[]) => void | Promise<void>;\n}\n\nexport type Config = SchemaToPagesOptions & GenerateFilesConfig;\n\ninterface BeforeWriteContext {\n readonly generated: Record<string, OutputFile[]>;\n readonly generatedEntries: Record<string, OutputEntry[]>;\n readonly documents: Record<string, ProcessedDocument>;\n}\n\nexport async function generateFiles(options: Config): Promise<void> {\n const files = await generateFilesOnly(options);\n const { output } = options;\n\n await Promise.all(\n files.map(async (file) => {\n const filePath = path.join(output, file.path);\n\n await mkdir(path.dirname(filePath), { recursive: true });\n await writeFile(filePath, file.content);\n console.log(`Generated: ${filePath}`);\n }),\n );\n}\n\nexport async function generateFilesOnly(\n options: SchemaToPagesOptions & Omit<GenerateFilesConfig, 'output'>,\n): Promise<OutputFile[]> {\n const schemas = await options.input.getSchemas();\n\n const files: OutputFile[] = [];\n const generated: Record<string, OutputFile[]> = {};\n const generatedEntries: Record<string, OutputEntry[]> = {};\n\n const entries = Object.entries(schemas);\n if (entries.length === 0) {\n throw new Error('No input files found.');\n }\n const preset = createAutoPreset(options);\n for (const [id, schema] of entries) {\n const entries = fromSchema(id, schema, preset);\n const schemaFiles = (generated[id] ??= []);\n\n generatedEntries[id] = entries;\n for (const entry of entries) {\n const file: OutputFile = {\n path: entry.path,\n content: toText(entry, schema, options),\n };\n\n schemaFiles.push(file);\n files.push(file);\n }\n }\n\n const context: BeforeWriteContext = {\n generated,\n generatedEntries,\n documents: schemas,\n };\n\n if (options.index) {\n writeIndexFiles(files, context, options);\n }\n\n await options.beforeWrite?.call(context, files);\n return files;\n}\n\nfunction writeIndexFiles(\n files: OutputFile[],\n context: BeforeWriteContext,\n options: SchemaToPagesOptions & Omit<GenerateFilesConfig, 'output'>,\n) {\n const { generatedEntries } = context;\n const { items, url } = options.index!;\n\n let urlFn: (path: string) => string;\n if (typeof url === 'object') {\n const getUrl = createGetUrl(url.baseUrl);\n\n urlFn = (file) => getUrl(getSlugs(path.relative(url.contentDir, file)));\n } else {\n urlFn = url;\n }\n\n function findEntryByPath(path: string) {\n for (const entries of Object.values(generatedEntries)) {\n const match = entries.find((entry) => entry.path === path);\n\n if (match) return match;\n }\n }\n\n function fileContent(index: IndexItem): string {\n const content: string[] = [];\n content.push('<Cards>');\n const pathToEntry = new Map<string, OutputEntry>();\n const only = index.only ?? Object.keys(context.generated);\n\n for (const item of only) {\n if (generatedEntries[item]) {\n for (const entry of generatedEntries[item]) {\n pathToEntry.set(entry.path, entry);\n }\n } else {\n const match = findEntryByPath(item);\n if (!match) {\n throw new Error(\n `${item} does not exist on \"input\", available: ${Object.keys(generatedEntries).join(', ')}.`,\n );\n }\n\n pathToEntry.set(match.path, match);\n }\n }\n\n for (const file of pathToEntry.values()) {\n const descriptionAttr = file.info.description\n ? `description=${JSON.stringify(file.info.description)} `\n : '';\n content.push(\n `<Card href=\"${urlFn(file.path)}\" title=${JSON.stringify(file.info.title)} ${descriptionAttr}/>`,\n );\n }\n\n content.push('</Cards>');\n return generateDocument(\n {\n title: index.title ?? 'Overview',\n description: index.description,\n },\n content.join('\\n'),\n options,\n );\n }\n\n for (const item of typeof items === 'function' ? items(context) : items) {\n files.push({\n path: path.extname(item.path).length === 0 ? `${item.path}.mdx` : item.path,\n content: fileContent(item),\n });\n }\n}\n"],"mappings":"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"}
@@ -1,23 +1,18 @@
1
1
  import { ParsedSchema } from "../utils/schema.js";
2
- import { RequestData } from "../requests/types.js";
3
2
  import { FetchResult } from "./fetcher.js";
4
3
  import { ParameterField, SecurityEntry } from "./index.js";
5
4
  import { SchemaScope } from "./schema.js";
6
5
  import { ComponentProps, FC, ReactNode } from "react";
7
- import { FieldPath, UseControllerProps, UseControllerReturn } from "react-hook-form";
8
6
  import * as react_jsx_runtime0 from "react/jsx-runtime";
7
+ import { FieldKey } from "@fumari/stf";
9
8
 
10
9
  //#region src/playground/client.d.ts
11
- interface FormValues {
10
+ interface FormValues extends Record<string, unknown> {
12
11
  path: Record<string, unknown>;
13
12
  query: Record<string, unknown>;
14
13
  header: Record<string, unknown>;
15
14
  cookie: Record<string, unknown>;
16
15
  body: unknown;
17
- /**
18
- * Store the cached encoded request data, do not modify it.
19
- */
20
- _encoded?: RequestData;
21
16
  }
22
17
  interface PlaygroundClientProps extends ComponentProps<'form'>, SchemaScope {
23
18
  route: string;
@@ -51,13 +46,12 @@ interface PlaygroundClientOptions {
51
46
  /**
52
47
  * render the paremeter inputs of API endpoint.
53
48
  *
54
- * It uses `react-hook-form`, you can use either:
55
- * - the library itself, with types from `fumadocs-openapi/playground/client`.
49
+ * for updating values, use:
56
50
  * - the `Custom.useController()` from `fumadocs-openapi/playground/client`.
57
51
  *
58
52
  * Recommended types packages: `json-schema-typed`, `openapi-types`.
59
53
  */
60
- renderParameterField?: (fieldName: FieldPath<FormValues>, param: ParameterField) => ReactNode;
54
+ renderParameterField?: (fieldName: FieldKey, param: ParameterField) => ReactNode;
61
55
  /**
62
56
  * render the input for API endpoint body.
63
57
  *
@@ -81,14 +75,19 @@ declare function PlaygroundClient({
81
75
  ...rest
82
76
  }: PlaygroundClientProps): react_jsx_runtime0.JSX.Element;
83
77
  interface AuthField {
84
- fieldName: string;
78
+ fieldName: FieldKey;
85
79
  defaultValue: unknown;
86
80
  original?: SecurityEntry;
87
81
  children: ReactNode;
88
82
  mapOutput?: (values: unknown) => unknown;
89
83
  }
90
84
  declare const Custom: {
91
- useController<TName extends FieldPath<FormValues> = "path" | "query" | "header" | "cookie" | "body" | "_encoded" | `path.${string}` | `query.${string}` | `header.${string}` | `cookie.${string}` | "_encoded.path" | "_encoded.query" | "_encoded.header" | "_encoded.cookie" | "_encoded.body" | `_encoded.path.${string}` | `_encoded.query.${string}` | `_encoded.header.${string}` | `_encoded.cookie.${string}` | "_encoded.method" | "_encoded.bodyMediaType", TTransformedValues = FormValues>(props: UseControllerProps<FormValues, TName, TTransformedValues>): UseControllerReturn<FormValues, TName>;
85
+ useController(fieldName: FieldKey, options?: {
86
+ defaultValue?: unknown;
87
+ }): {
88
+ value: unknown;
89
+ setValue: (newValue: unknown) => boolean;
90
+ };
92
91
  };
93
92
  //#endregion
94
93
  export { AuthField, Custom, FormValues, PlaygroundClientOptions, PlaygroundClientProps, PlaygroundClient as default };
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","names":[],"sources":["../../src/playground/client.tsx"],"sourcesContent":[],"mappings":";;;;;;;;;;UAoDiB,UAAA;QACT;SACC;EAFQ,MAAA,EAGP,MAHiB,CAAA,MAAA,EAAA,OAAA,CAAA;EACnB,MAAA,EAGE,MAHF,CAAA,MAAA,EAAA,OAAA,CAAA;EACC,IAAA,EAAA,OAAA;EACC;;;EAOc,QAAA,CAAA,EAAX,WAAW;AAGxB;AAGe,UAHE,qBAAA,SAA8B,cAGhC,CAAA,MAAA,CAAA,EAHwD,WAGxD,CAAA;EACD,KAAA,EAAA,MAAA;EAEF,MAAA,EAAA,MAAA;EAMiB,UAAA,CAAA,EATd,cASc,EAAA;EAAf,UAAA,EARA,aAQA,EAAA,EAAA;EAZiC,IAAA,CAAA,EAAA;IAAwB,MAAA,EAM3D,YAN2D;IAAW,SAAA,EAAA,MAAA;EAgBjE,CAAA;EAIgB;;;EAQd,UAAA,EAhBL,MAgBK,CAAA,MAAA,EAhBU,YAgBV,CAAA;EADJ,QAAA,CAAA,EAAA,MAAA;;AAasB,UAxBpB,uBAAA,CAwBoB;EAA8B;;;EAa5D,mBAAA,CAAA,EAAA,CAAA,MAAA,EAjC0B,SAiC1B,EAAA,EAAA,GAjC0C,SAiC1C,EAAA;EAAS;AACf;;EAeC,cAAA,CAAA,EAAA,MAAA;EACA,UAAA,CAAA,EA3Ca,OA2Cb,CAAA;IACA,aAAA,EA3CiB,EA2CjB,CAAA;MACA,IAAA,EA5C4B,WA4C5B;IACA,CAAA,CAAA;EACA,CAAA,CAAA;EACA;;;;;AA6VF;AA8QA;;;EAGsB,oBAAA,CAAA,EAAA,CAAA,SAAA,EAjpBe,SAipBf,CAjpByB,UAipBzB,CAAA,EAAA,KAAA,EAjpB6C,cAipB7C,EAAA,GAjpBgE,SAipBhE;EAEQ;;;;;EACO,eAAA,CAAA,EAAA,CAAA,SAAA,EAAA,MAAA,EAAA,IAAA,EAAA;IAAhC,MAAA,EA1oBS,YA0oBT;IAAmB,SAAA,EAAA,MAAA;QAvoBjB;;iBAciB,gBAAA;;;;;;;;;;;GAWrB,wBAAqB,kBAAA,CAAA,GAAA,CAAA;UA0VP,SAAA;;;aAIJ;YACD;;;cAyQC;8BAEK,UAAU,qbACN,mBAEX,mBAAmB,YAAY,OAAO,sBAC5C,oBAAoB,YAAY"}
1
+ {"version":3,"file":"client.d.ts","names":[],"sources":["../../src/playground/client.tsx"],"sourcesContent":[],"mappings":";;;;;;;;;UAsDiB,UAAA,SAAmB;QAC5B;SACC;EAFQ,MAAA,EAGP,MAHkB,CAAA,MAAA,EAAA,OAAA,CAAA;EACpB,MAAA,EAGE,MAHF,CAAA,MAAA,EAAA,OAAA,CAAA;EACC,IAAA,EAAA,OAAA;;AAEC,UAIO,qBAAA,SAA8B,cAJrC,CAAA,MAAA,CAAA,EAI6D,WAJ7D,CAAA;EAJ0B,KAAA,EAAA,MAAA;EAAM,MAAA,EAAA,MAAA;EAQzB,UAAA,CAAA,EAGF,cAHwB,EAAA;EAGxB,UAAA,EACD,aADC,EAAA,EAAA;EACD,IAAA,CAAA,EAAA;IAEF,MAAA,EAAA,YAAA;IAMiB,SAAA,EAAA,MAAA;EAAf,CAAA;EAZiC;;;EAgB9B,UAAA,EAJH,MAIG,CAAA,MAAA,EAJY,YAIW,CAAA;EAIP,QAAA,CAAA,EAAA,MAAA;;AAQH,UAZb,uBAAA,CAYa;EAAX;;;EAWmC,mBAAA,CAAA,EAAA,CAAA,MAAA,EAnBrB,SAmBqB,EAAA,EAAA,GAnBL,SAmBK,EAAA;EAAmB;;;EAazD,cAAA,CAAA,EAAA,MAAA;EAcQ,UAAA,CAAA,EAvCT,OAuCyB,CAAA;IACtC,aAAA,EAvCiB,EAuCjB,CAAA;MACA,IAAA,EAxC4B,WAwC5B;IACA,CAAA,CAAA;EACA,CAAA,CAAA;EACA;;;;;;;;EA0Ue,oBAAS,CAAA,EAAA,CAAA,SAAA,EA1WW,QA0WX,EAAA,KAAA,EA1W4B,cA0W5B,EAAA,GA1W+C,SA0W/C;EACb;;;;AAiRb;;YAlnBc;;QAGP;;iBAciB,gBAAA;;;;;;;;;;;GAWrB,wBAAqB,kBAAA,CAAA,GAAA,CAAA;UAoUP,SAAA;aACJ;;aAGA;YACD;;;cA6QC;2BAEE"}
@@ -3,24 +3,25 @@
3
3
  import { joinURL, resolveRequestData, resolveServerUrl, withBase } from "../utils/url.js";
4
4
  import { useStorageKey } from "../ui/client/storage-key.js";
5
5
  import { useApiContext } from "../ui/contexts/api.js";
6
- import { cn } from "../utils/cn.js";
7
- import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "../ui/components/select.js";
8
- import { labelVariants } from "../ui/components/input.js";
9
- import { SchemaProvider, useResolvedSchema } from "./schema.js";
10
- import { FieldInput, FieldSet, JsonInput, ObjectInput } from "./components/inputs.js";
11
6
  import { getStatusInfo } from "./status-info.js";
7
+ import { cn } from "../utils/cn.js";
12
8
  import { MethodLabel } from "../ui/components/method-label.js";
13
9
  import { useQuery } from "../utils/use-query.js";
14
10
  import { encodeRequestData } from "../requests/media/encode.js";
11
+ import { SchemaProvider, useResolvedSchema } from "./schema.js";
12
+ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "../ui/components/select.js";
13
+ import { labelVariants } from "../ui/components/input.js";
15
14
  import ServerSelect from "./components/server-select.js";
16
15
  import { useExampleRequests } from "../ui/operation/usage-tabs/client.js";
17
- import { Fragment, lazy, useEffect, useEffectEvent, useMemo, useState } from "react";
18
- import { FormProvider, get, set, useController, useForm, useFormContext } from "react-hook-form";
16
+ import { FieldInput, FieldSet, JsonInput, ObjectInput } from "./components/inputs.js";
17
+ import { Fragment, lazy, useEffect, useMemo, useRef, useState } from "react";
19
18
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
20
19
  import { ChevronDown, LoaderCircle, X } from "lucide-react";
21
- import { buttonVariants } from "fumadocs-ui/components/ui/button";
22
20
  import { DynamicCodeBlock } from "fumadocs-ui/components/dynamic-codeblock";
23
21
  import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "fumadocs-ui/components/ui/collapsible";
22
+ import { buttonVariants } from "fumadocs-ui/components/ui/button";
23
+ import { StfProvider, useDataEngine, useFieldValue, useListener, useStf } from "@fumari/stf";
24
+ import { objectGet, objectSet, stringifyFieldKey } from "@fumari/stf/lib/utils";
24
25
 
25
26
  //#region src/playground/client.tsx
26
27
  const OauthDialog = lazy(() => import("./components/oauth-dialog.js").then((mod) => ({ default: mod.OauthDialog })));
@@ -28,7 +29,6 @@ const OauthDialogTrigger = lazy(() => import("./components/oauth-dialog.js").the
28
29
  function PlaygroundClient({ route, method = "GET", securities, parameters = [], body, references, proxyUrl, writeOnly, readOnly, ...rest }) {
29
30
  const { example: exampleId, examples, setExampleData } = useExampleRequests();
30
31
  const storageKeys = useStorageKey();
31
- const fieldInfoMap = useMemo(() => /* @__PURE__ */ new Map(), []);
32
32
  const { mediaAdapters, serverRef, client: { playground: { components: { ResultDisplay = DefaultResultDisplay } = {}, requestTimeout = 10, transformAuthInputs } = {} } } = useApiContext();
33
33
  const [securityId, setSecurityId] = useState(0);
34
34
  const { inputs, mapInputs, initAuthValues } = useAuthInputs(securities[securityId], transformAuthInputs);
@@ -42,72 +42,61 @@ function PlaygroundClient({ route, method = "GET", securities, parameters = [],
42
42
  cookie: requestData?.cookie ?? {}
43
43
  };
44
44
  }, [examples, exampleId]);
45
- const form = useForm({ defaultValues });
45
+ const stf = useStf({ defaultValues });
46
46
  const testQuery = useQuery(async (input) => {
47
47
  const targetServer = serverRef.current;
48
48
  const fetcher = await import("./fetcher.js").then((mod) => mod.createBrowserFetcher(mediaAdapters, requestTimeout));
49
- input._encoded ??= encodeRequestData({
49
+ const encoded = encodeRequestData({
50
50
  ...mapInputs(input),
51
51
  method,
52
52
  bodyMediaType: body?.mediaType
53
53
  }, mediaAdapters, parameters);
54
- return fetcher.fetch(joinURL(withBase(targetServer ? resolveServerUrl(targetServer.url, targetServer.variables) : "/", window.location.origin), resolveRequestData(route, input._encoded)), {
54
+ return fetcher.fetch(joinURL(withBase(targetServer ? resolveServerUrl(targetServer.url, targetServer.variables) : "/", window.location.origin), resolveRequestData(route, encoded)), {
55
55
  proxyUrl,
56
- ...input._encoded
56
+ ...encoded
57
57
  });
58
58
  });
59
- const onUpdateDebounced = useEffectEvent((values) => {
60
- for (const item of inputs) {
61
- const value = get(values, item.fieldName);
62
- if (value) localStorage.setItem(storageKeys.AuthField(item), JSON.stringify(value));
59
+ const timerRef = useRef(null);
60
+ useListener({
61
+ stf,
62
+ onUpdate() {
63
+ if (timerRef.current) window.clearTimeout(timerRef.current);
64
+ timerRef.current = window.setTimeout(() => {
65
+ const values = stf.dataEngine.getData();
66
+ for (const item of inputs) {
67
+ const value = stf.dataEngine.get(item.fieldName);
68
+ if (value) localStorage.setItem(storageKeys.AuthField(item), JSON.stringify(value));
69
+ }
70
+ const data = {
71
+ ...mapInputs(values),
72
+ method,
73
+ bodyMediaType: body?.mediaType
74
+ };
75
+ setExampleData(data, encodeRequestData(data, mediaAdapters, parameters));
76
+ }, timerRef.current ? 400 : 0);
63
77
  }
64
- const data = {
65
- ...mapInputs(values),
66
- method,
67
- bodyMediaType: body?.mediaType
68
- };
69
- values._encoded ??= encodeRequestData(data, mediaAdapters, parameters);
70
- setExampleData(data, values._encoded);
71
78
  });
72
79
  useEffect(() => {
73
- let timer = null;
74
- const subscription = form.subscribe({
75
- formState: { values: true },
76
- callback({ values }) {
77
- delete values._encoded;
78
- if (timer) window.clearTimeout(timer);
79
- timer = window.setTimeout(() => onUpdateDebounced(values), timer ? 400 : 0);
80
- }
81
- });
82
- return () => subscription();
83
- }, []);
84
- useEffect(() => {
85
- form.reset(initAuthValues(defaultValues));
86
- return () => fieldInfoMap.clear();
87
- }, [defaultValues]);
88
- useEffect(() => {
89
- form.reset((values) => initAuthValues(values));
90
80
  return () => {
91
- form.reset((values) => {
92
- for (const item of inputs) set(values, item.fieldName, void 0);
93
- return values;
94
- });
81
+ stf.dataEngine.reset(defaultValues);
95
82
  };
96
- }, [inputs]);
97
- const onSubmit = form.handleSubmit((value) => {
98
- testQuery.start(mapInputs(value));
99
- });
100
- return /* @__PURE__ */ jsx(FormProvider, {
101
- ...form,
83
+ }, [defaultValues]);
84
+ useEffect(() => {
85
+ return initAuthValues(stf);
86
+ }, [defaultValues, inputs]);
87
+ return /* @__PURE__ */ jsx(StfProvider, {
88
+ value: stf,
102
89
  children: /* @__PURE__ */ jsx(SchemaProvider, {
103
- fieldInfoMap,
104
90
  references,
105
91
  writeOnly,
106
92
  readOnly,
107
93
  children: /* @__PURE__ */ jsxs("form", {
108
94
  ...rest,
109
95
  className: cn("not-prose flex flex-col rounded-xl border shadow-md overflow-hidden bg-fd-card text-fd-card-foreground", rest.className),
110
- onSubmit,
96
+ onSubmit: (e) => {
97
+ testQuery.start(mapInputs(stf.dataEngine.getData()));
98
+ e.preventDefault();
99
+ },
111
100
  children: [
112
101
  /* @__PURE__ */ jsx(ServerSelect, {}),
113
102
  /* @__PURE__ */ jsxs("div", {
@@ -133,7 +122,7 @@ function PlaygroundClient({ route, method = "GET", securities, parameters = [],
133
122
  securities,
134
123
  securityId,
135
124
  setSecurityId,
136
- children: inputs.map((input) => /* @__PURE__ */ jsx(Fragment, { children: input.children }, input.fieldName))
125
+ children: inputs.map((input) => /* @__PURE__ */ jsx(Fragment, { children: input.children }, stringifyFieldKey(input.fieldName)))
137
126
  }),
138
127
  /* @__PURE__ */ jsx(FormBody, {
139
128
  body,
@@ -150,7 +139,7 @@ function PlaygroundClient({ route, method = "GET", securities, parameters = [],
150
139
  }
151
140
  function SecurityTabs({ securities, setSecurityId, securityId, children }) {
152
141
  const [open, setOpen] = useState(false);
153
- const form = useFormContext();
142
+ const engine = useDataEngine();
154
143
  const result = /* @__PURE__ */ jsxs(CollapsiblePanel, {
155
144
  title: "Authorization",
156
145
  children: [/* @__PURE__ */ jsxs(Select, {
@@ -181,7 +170,7 @@ function SecurityTabs({ securities, setSecurityId, securityId, children }) {
181
170
  setOpen(v);
182
171
  if (v) setSecurityId(i);
183
172
  },
184
- setToken: (token) => form.setValue("header.Authorization", token),
173
+ setToken: (token) => engine.update(["header", "Authorization"], token),
185
174
  children: result
186
175
  });
187
176
  }
@@ -207,7 +196,7 @@ function FormBody({ parameters = [], body }) {
207
196
  path: "Path"
208
197
  }[type],
209
198
  children: items.map((field) => {
210
- const fieldName = `${type}.${field.name}`;
199
+ const fieldName = [type, field.name];
211
200
  if (renderParameterField) return renderParameterField(fieldName, field);
212
201
  const contentTypes = field.content && Object.keys(field.content);
213
202
  const schema = field.content && contentTypes && contentTypes.length > 0 ? field.content[contentTypes[0]].schema : field.schema;
@@ -215,7 +204,7 @@ function FormBody({ parameters = [], body }) {
215
204
  name: field.name,
216
205
  fieldName,
217
206
  field: schema
218
- }, fieldName);
207
+ }, stringifyFieldKey(fieldName));
219
208
  })
220
209
  }, type);
221
210
  });
@@ -229,7 +218,7 @@ function BodyInput({ field: _field }) {
229
218
  const [isJson, setIsJson] = useState(false);
230
219
  if (field.format === "binary") return /* @__PURE__ */ jsx(FieldSet, {
231
220
  field,
232
- fieldName: "body"
221
+ fieldName: ["body"]
233
222
  });
234
223
  if (isJson) return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("button", {
235
224
  className: cn(buttonVariants({
@@ -240,10 +229,10 @@ function BodyInput({ field: _field }) {
240
229
  onClick: () => setIsJson(false),
241
230
  type: "button",
242
231
  children: "Close JSON Editor"
243
- }), /* @__PURE__ */ jsx(JsonInput, { fieldName: "body" })] });
232
+ }), /* @__PURE__ */ jsx(JsonInput, { fieldName: ["body"] })] });
244
233
  return /* @__PURE__ */ jsx(FieldSet, {
245
234
  field,
246
- fieldName: "body",
235
+ fieldName: ["body"],
247
236
  collapsible: false,
248
237
  name: /* @__PURE__ */ jsx("button", {
249
238
  type: "button",
@@ -263,7 +252,7 @@ function useAuthInputs(securities, transform) {
263
252
  const result = [];
264
253
  if (!securities) return result;
265
254
  for (const security of securities) if (security.type === "http" && security.scheme === "basic") {
266
- const fieldName = `header.Authorization`;
255
+ const fieldName = ["header", "Authorization"];
267
256
  result.push({
268
257
  fieldName,
269
258
  original: security,
@@ -288,7 +277,7 @@ function useAuthInputs(securities, transform) {
288
277
  })
289
278
  });
290
279
  } else if (security.type === "oauth2") {
291
- const fieldName = "header.Authorization";
280
+ const fieldName = ["header", "Authorization"];
292
281
  result.push({
293
282
  fieldName,
294
283
  original: security,
@@ -296,7 +285,7 @@ function useAuthInputs(securities, transform) {
296
285
  children: /* @__PURE__ */ jsxs("fieldset", {
297
286
  className: "flex flex-col gap-2",
298
287
  children: [/* @__PURE__ */ jsx("label", {
299
- htmlFor: fieldName,
288
+ htmlFor: stringifyFieldKey(fieldName),
300
289
  className: cn(labelVariants()),
301
290
  children: "Access Token"
302
291
  }), /* @__PURE__ */ jsxs("div", {
@@ -318,7 +307,7 @@ function useAuthInputs(securities, transform) {
318
307
  })
319
308
  });
320
309
  } else if (security.type === "http") {
321
- const fieldName = "header.Authorization";
310
+ const fieldName = ["header", "Authorization"];
322
311
  result.push({
323
312
  fieldName,
324
313
  original: security,
@@ -331,7 +320,7 @@ function useAuthInputs(securities, transform) {
331
320
  })
332
321
  });
333
322
  } else if (security.type === "apiKey") {
334
- const fieldName = `${security.in}.${security.name}`;
323
+ const fieldName = [security.in, security.name];
335
324
  result.push({
336
325
  fieldName,
337
326
  defaultValue: "",
@@ -344,7 +333,7 @@ function useAuthInputs(securities, transform) {
344
333
  })
345
334
  });
346
335
  } else {
347
- const fieldName = "header.Authorization";
336
+ const fieldName = ["header", "Authorization"];
348
337
  result.push({
349
338
  fieldName,
350
339
  defaultValue: "",
@@ -366,23 +355,26 @@ function useAuthInputs(securities, transform) {
366
355
  const cloned = structuredClone(values);
367
356
  for (const item of inputs) {
368
357
  if (!item.mapOutput) continue;
369
- set(cloned, item.fieldName, item.mapOutput(get(cloned, item.fieldName)));
358
+ objectSet(cloned, item.fieldName, item.mapOutput(objectGet(cloned, item.fieldName)));
370
359
  }
371
360
  return cloned;
372
361
  };
373
- const initAuthValues = (values) => {
362
+ const initAuthValues = (stf) => {
363
+ const { dataEngine } = stf;
374
364
  for (const item of inputs) {
375
365
  const stored = localStorage.getItem(storageKeys.AuthField(item));
376
366
  if (stored) {
377
367
  const parsed = JSON.parse(stored);
378
368
  if (typeof parsed === typeof item.defaultValue) {
379
- set(values, item.fieldName, parsed);
369
+ dataEngine.init(item.fieldName, parsed);
380
370
  continue;
381
371
  }
382
372
  }
383
- set(values, item.fieldName, item.defaultValue);
373
+ dataEngine.init(item.fieldName, item.defaultValue);
384
374
  }
385
- return values;
375
+ return () => {
376
+ for (const item of inputs) stf.dataEngine.delete(item.fieldName);
377
+ };
386
378
  };
387
379
  return {
388
380
  inputs,
@@ -450,8 +442,12 @@ function CollapsiblePanel({ title, children, ...props }) {
450
442
  }) })]
451
443
  });
452
444
  }
453
- const Custom = { useController(props) {
454
- return useController(props);
445
+ const Custom = { useController(fieldName, options) {
446
+ const [value, setValue] = useFieldValue(fieldName, options);
447
+ return {
448
+ value,
449
+ setValue
450
+ };
455
451
  } };
456
452
 
457
453
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","names":["defaultValues: FormValues","timer: number | null","result: AuthField[]"],"sources":["../../src/playground/client.tsx"],"sourcesContent":["'use client';\nimport {\n type FC,\n Fragment,\n lazy,\n type ReactNode,\n useEffect,\n useMemo,\n useState,\n useEffectEvent,\n type ComponentProps,\n} from 'react';\nimport type { FieldPath, UseControllerProps, UseControllerReturn } from 'react-hook-form';\nimport { FormProvider, get, set, useController, useForm, useFormContext } from 'react-hook-form';\nimport { useApiContext } from '@/ui/contexts/api';\nimport type { FetchResult } from '@/playground/fetcher';\nimport { FieldInput, FieldSet, JsonInput, ObjectInput } from './components/inputs';\nimport type { ParameterField, SecurityEntry } from '@/playground/index';\nimport { getStatusInfo } from './status-info';\nimport { joinURL, resolveRequestData, resolveServerUrl, withBase } from '@/utils/url';\nimport { DynamicCodeBlock } from 'fumadocs-ui/components/dynamic-codeblock';\nimport { MethodLabel } from '@/ui/components/method-label';\nimport { useQuery } from '@/utils/use-query';\nimport {\n Collapsible,\n CollapsibleContent,\n CollapsibleTrigger,\n} from 'fumadocs-ui/components/ui/collapsible';\nimport { X, ChevronDown, LoaderCircle } from 'lucide-react';\nimport { encodeRequestData } from '@/requests/media/encode';\nimport { buttonVariants } from 'fumadocs-ui/components/ui/button';\nimport { cn } from '@/utils/cn';\nimport {\n type FieldInfo,\n SchemaProvider,\n SchemaScope,\n useResolvedSchema,\n} from '@/playground/schema';\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@/ui/components/select';\nimport { labelVariants } from '@/ui/components/input';\nimport type { ParsedSchema } from '@/utils/schema';\nimport type { RequestData } from '@/requests/types';\nimport ServerSelect from './components/server-select';\nimport { useStorageKey } from '@/ui/client/storage-key';\nimport { useExampleRequests } from '@/ui/operation/usage-tabs/client';\n\nexport interface FormValues {\n path: Record<string, unknown>;\n query: Record<string, unknown>;\n header: Record<string, unknown>;\n cookie: Record<string, unknown>;\n body: unknown;\n\n /**\n * Store the cached encoded request data, do not modify it.\n */\n _encoded?: RequestData;\n}\n\nexport interface PlaygroundClientProps extends ComponentProps<'form'>, SchemaScope {\n route: string;\n method: string;\n parameters?: ParameterField[];\n securities: SecurityEntry[][];\n body?: {\n schema: ParsedSchema;\n mediaType: string;\n };\n /**\n * Resolver for $ref schemas you've passed\n */\n references: Record<string, ParsedSchema>;\n proxyUrl?: string;\n}\n\nexport interface PlaygroundClientOptions {\n /**\n * transform fields for auth-specific parameters (e.g. header)\n */\n transformAuthInputs?: (fields: AuthField[]) => AuthField[];\n\n /**\n * Request timeout in seconds (default: 10s)\n */\n requestTimeout?: number;\n\n components?: Partial<{\n ResultDisplay: FC<{ data: FetchResult }>;\n }>;\n\n /**\n * render the paremeter inputs of API endpoint.\n *\n * It uses `react-hook-form`, you can use either:\n * - the library itself, with types from `fumadocs-openapi/playground/client`.\n * - the `Custom.useController()` from `fumadocs-openapi/playground/client`.\n *\n * Recommended types packages: `json-schema-typed`, `openapi-types`.\n */\n renderParameterField?: (fieldName: FieldPath<FormValues>, param: ParameterField) => ReactNode;\n\n /**\n * render the input for API endpoint body.\n *\n * @see renderParameterField for customisation tips\n */\n renderBodyField?: (\n fieldName: 'body',\n info: {\n schema: ParsedSchema;\n mediaType: string;\n },\n ) => ReactNode;\n}\n\nconst OauthDialog = lazy(() =>\n import('./components/oauth-dialog').then((mod) => ({\n default: mod.OauthDialog,\n })),\n);\nconst OauthDialogTrigger = lazy(() =>\n import('./components/oauth-dialog').then((mod) => ({\n default: mod.OauthDialogTrigger,\n })),\n);\n\nexport default function PlaygroundClient({\n route,\n method = 'GET',\n securities,\n parameters = [],\n body,\n references,\n proxyUrl,\n writeOnly,\n readOnly,\n ...rest\n}: PlaygroundClientProps) {\n const { example: exampleId, examples, setExampleData } = useExampleRequests();\n const storageKeys = useStorageKey();\n const fieldInfoMap = useMemo(() => new Map<string, FieldInfo>(), []);\n const {\n mediaAdapters,\n serverRef,\n client: {\n playground: {\n components: { ResultDisplay = DefaultResultDisplay } = {},\n requestTimeout = 10,\n transformAuthInputs,\n } = {},\n },\n } = useApiContext();\n const [securityId, setSecurityId] = useState(0);\n const { inputs, mapInputs, initAuthValues } = useAuthInputs(\n securities[securityId],\n transformAuthInputs,\n );\n\n const defaultValues: FormValues = useMemo(() => {\n const requestData = examples.find((example) => example.id === exampleId)?.data;\n\n return {\n path: requestData?.path ?? {},\n query: requestData?.query ?? {},\n header: requestData?.header ?? {},\n body: requestData?.body ?? {},\n cookie: requestData?.cookie ?? {},\n };\n }, [examples, exampleId]);\n\n const form = useForm<FormValues>({\n defaultValues,\n });\n\n const testQuery = useQuery(async (input: FormValues) => {\n const targetServer = serverRef.current;\n const fetcher = await import('./fetcher').then((mod) =>\n mod.createBrowserFetcher(mediaAdapters, requestTimeout),\n );\n\n input._encoded ??= encodeRequestData(\n { ...mapInputs(input), method, bodyMediaType: body?.mediaType },\n mediaAdapters,\n parameters,\n );\n\n return fetcher.fetch(\n joinURL(\n withBase(\n targetServer ? resolveServerUrl(targetServer.url, targetServer.variables) : '/',\n window.location.origin,\n ),\n resolveRequestData(route, input._encoded),\n ),\n {\n proxyUrl,\n ...input._encoded,\n },\n );\n });\n\n const onUpdateDebounced = useEffectEvent((values: FormValues) => {\n for (const item of inputs) {\n const value = get(values, item.fieldName);\n\n if (value) {\n localStorage.setItem(storageKeys.AuthField(item), JSON.stringify(value));\n }\n }\n\n const data = {\n ...mapInputs(values),\n method,\n bodyMediaType: body?.mediaType,\n };\n values._encoded ??= encodeRequestData(data, mediaAdapters, parameters);\n setExampleData(data, values._encoded);\n });\n\n useEffect(() => {\n let timer: number | null = null;\n\n const subscription = form.subscribe({\n formState: {\n values: true,\n },\n callback({ values }) {\n // remove cached encoded request data\n delete values._encoded;\n\n if (timer) window.clearTimeout(timer);\n timer = window.setTimeout(() => onUpdateDebounced(values), timer ? 400 : 0);\n },\n });\n\n return () => subscription();\n // eslint-disable-next-line react-hooks/exhaustive-deps -- mounted once only\n }, []);\n\n useEffect(() => {\n form.reset(initAuthValues(defaultValues));\n\n return () => fieldInfoMap.clear();\n // eslint-disable-next-line react-hooks/exhaustive-deps -- ignore other parts\n }, [defaultValues]);\n\n useEffect(() => {\n form.reset((values) => initAuthValues(values));\n\n return () => {\n form.reset((values) => {\n for (const item of inputs) {\n set(values, item.fieldName, undefined);\n }\n\n return values;\n });\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps -- ignore other parts\n }, [inputs]);\n\n const onSubmit = form.handleSubmit((value) => {\n testQuery.start(mapInputs(value));\n });\n\n return (\n <FormProvider {...form}>\n <SchemaProvider\n fieldInfoMap={fieldInfoMap}\n references={references}\n writeOnly={writeOnly}\n readOnly={readOnly}\n >\n <form\n {...rest}\n className={cn(\n 'not-prose flex flex-col rounded-xl border shadow-md overflow-hidden bg-fd-card text-fd-card-foreground',\n rest.className,\n )}\n onSubmit={onSubmit}\n >\n <ServerSelect />\n <div className=\"flex flex-row items-center gap-2 text-sm p-3 not-last:pb-0\">\n <MethodLabel>{method}</MethodLabel>\n <Route route={route} className=\"flex-1\" />\n <button\n type=\"submit\"\n className={cn(buttonVariants({ color: 'primary', size: 'sm' }), 'w-14 py-1.5')}\n disabled={testQuery.isLoading}\n >\n {testQuery.isLoading ? <LoaderCircle className=\"size-4 animate-spin\" /> : 'Send'}\n </button>\n </div>\n\n {securities.length > 0 && (\n <SecurityTabs\n securities={securities}\n securityId={securityId}\n setSecurityId={setSecurityId}\n >\n {inputs.map((input) => (\n <Fragment key={input.fieldName}>{input.children}</Fragment>\n ))}\n </SecurityTabs>\n )}\n <FormBody body={body} parameters={parameters} />\n {testQuery.data ? <ResultDisplay data={testQuery.data} reset={testQuery.reset} /> : null}\n </form>\n </SchemaProvider>\n </FormProvider>\n );\n}\n\nfunction SecurityTabs({\n securities,\n setSecurityId,\n securityId,\n children,\n}: {\n securities: SecurityEntry[][];\n securityId: number;\n setSecurityId: (value: number) => void;\n children: ReactNode;\n}) {\n const [open, setOpen] = useState(false);\n const form = useFormContext();\n\n const result = (\n <CollapsiblePanel title=\"Authorization\">\n <Select value={securityId.toString()} onValueChange={(v) => setSecurityId(Number(v))}>\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {securities.map((security, i) => (\n <SelectItem key={i} value={i.toString()}>\n {security.map((item) => (\n <div key={item.id} className=\"max-w-[600px]\">\n <p className=\"font-mono font-medium\">{item.id}</p>\n <p className=\"text-fd-muted-foreground whitespace-pre-wrap\">{item.description}</p>\n </div>\n ))}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n {children}\n </CollapsiblePanel>\n );\n\n for (let i = 0; i < securities.length; i++) {\n const security = securities[i];\n\n for (const item of security) {\n if (item.type === 'oauth2') {\n return (\n <OauthDialog\n scheme={item}\n scopes={item.scopes}\n open={open}\n setOpen={(v) => {\n setOpen(v);\n if (v) {\n setSecurityId(i);\n }\n }}\n setToken={(token) => form.setValue('header.Authorization', token)}\n >\n {result}\n </OauthDialog>\n );\n }\n }\n }\n\n return result;\n}\n\nconst ParamTypes = ['path', 'header', 'cookie', 'query'] as const;\n\nfunction FormBody({ parameters = [], body }: Pick<PlaygroundClientProps, 'parameters' | 'body'>) {\n const { renderParameterField, renderBodyField } = useApiContext().client.playground ?? {};\n const panels = useMemo(() => {\n return ParamTypes.map((type) => {\n const items = parameters.filter((v) => v.in === type);\n if (items.length === 0) return;\n\n return (\n <CollapsiblePanel\n key={type}\n title={\n {\n header: 'Header',\n cookie: 'Cookies',\n query: 'Query',\n path: 'Path',\n }[type]\n }\n >\n {items.map((field) => {\n const fieldName = `${type}.${field.name}` as const;\n if (renderParameterField) {\n return renderParameterField(fieldName, field);\n }\n\n const contentTypes = field.content && Object.keys(field.content);\n const schema = (\n field.content && contentTypes && contentTypes.length > 0\n ? field.content[contentTypes[0]].schema\n : field.schema\n ) as ParsedSchema;\n\n return (\n <FieldSet key={fieldName} name={field.name} fieldName={fieldName} field={schema} />\n );\n })}\n </CollapsiblePanel>\n );\n });\n }, [parameters, renderParameterField]);\n\n return (\n <>\n {panels}\n {body && (\n <CollapsiblePanel title=\"Body\">\n {renderBodyField ? renderBodyField('body', body) : <BodyInput field={body.schema} />}\n </CollapsiblePanel>\n )}\n </>\n );\n}\n\nfunction BodyInput({ field: _field }: { field: ParsedSchema }) {\n const field = useResolvedSchema(_field);\n const [isJson, setIsJson] = useState(false);\n\n if (field.format === 'binary') return <FieldSet field={field} fieldName=\"body\" />;\n\n if (isJson)\n return (\n <>\n <button\n className={cn(\n buttonVariants({\n color: 'secondary',\n size: 'sm',\n className: 'w-fit font-mono p-2',\n }),\n )}\n onClick={() => setIsJson(false)}\n type=\"button\"\n >\n Close JSON Editor\n </button>\n <JsonInput fieldName=\"body\" />\n </>\n );\n\n return (\n <FieldSet\n field={field}\n fieldName=\"body\"\n collapsible={false}\n name={\n <button\n type=\"button\"\n className={cn(\n buttonVariants({\n color: 'secondary',\n size: 'sm',\n className: 'p-2',\n }),\n )}\n onClick={() => setIsJson(true)}\n >\n Open JSON Editor\n </button>\n }\n />\n );\n}\n\nexport interface AuthField {\n fieldName: string;\n defaultValue: unknown;\n\n original?: SecurityEntry;\n children: ReactNode;\n\n mapOutput?: (values: unknown) => unknown;\n}\n\nfunction useAuthInputs(\n securities?: SecurityEntry[],\n transform?: (fields: AuthField[]) => AuthField[],\n) {\n const storageKeys = useStorageKey();\n const inputs = useMemo(() => {\n const result: AuthField[] = [];\n if (!securities) return result;\n\n for (const security of securities) {\n if (security.type === 'http' && security.scheme === 'basic') {\n const fieldName = `header.Authorization`;\n\n result.push({\n fieldName,\n original: security,\n defaultValue: {\n username: '',\n password: '',\n },\n mapOutput(out) {\n if (out && typeof out === 'object') {\n return `Basic ${btoa(`${'username' in out ? out.username : ''}:${'password' in out ? out.password : ''}`)}`;\n }\n\n return out;\n },\n children: (\n <ObjectInput\n field={{\n type: 'object',\n properties: {\n username: {\n type: 'string',\n },\n password: {\n type: 'string',\n },\n },\n required: ['username', 'password'],\n }}\n fieldName={fieldName}\n />\n ),\n });\n } else if (security.type === 'oauth2') {\n const fieldName = 'header.Authorization';\n\n result.push({\n fieldName: fieldName,\n original: security,\n defaultValue: 'Bearer ',\n children: (\n <fieldset className=\"flex flex-col gap-2\">\n <label htmlFor={fieldName} className={cn(labelVariants())}>\n Access Token\n </label>\n <div className=\"flex gap-2\">\n <FieldInput\n fieldName={fieldName}\n isRequired\n field={{\n type: 'string',\n }}\n className=\"flex-1\"\n />\n\n <OauthDialogTrigger\n type=\"button\"\n className={cn(\n buttonVariants({\n size: 'sm',\n color: 'secondary',\n }),\n )}\n >\n Authorize\n </OauthDialogTrigger>\n </div>\n </fieldset>\n ),\n });\n } else if (security.type === 'http') {\n const fieldName = 'header.Authorization';\n\n result.push({\n fieldName: fieldName,\n original: security,\n defaultValue: 'Bearer ',\n children: (\n <FieldSet\n name=\"Authorization (header)\"\n fieldName={fieldName}\n isRequired\n field={{\n type: 'string',\n }}\n />\n ),\n });\n } else if (security.type === 'apiKey') {\n const fieldName = `${security.in}.${security.name}`;\n\n result.push({\n fieldName,\n defaultValue: '',\n original: security,\n children: (\n <FieldSet\n fieldName={fieldName}\n name={`${security.name} (${security.in})`}\n isRequired\n field={{\n type: 'string',\n }}\n />\n ),\n });\n } else {\n const fieldName = 'header.Authorization';\n\n result.push({\n fieldName,\n defaultValue: '',\n original: security,\n children: (\n <>\n <FieldSet\n name=\"Authorization (header)\"\n isRequired\n fieldName={fieldName}\n field={{\n type: 'string',\n }}\n />\n <p className=\"text-fd-muted-foreground text-xs\">\n OpenID Connect is not supported at the moment, you can still set an access token\n here.\n </p>\n </>\n ),\n });\n }\n }\n\n return transform ? transform(result) : result;\n }, [securities, transform]);\n\n const mapInputs = (values: FormValues) => {\n const cloned = structuredClone(values);\n\n for (const item of inputs) {\n if (!item.mapOutput) continue;\n\n set(cloned, item.fieldName, item.mapOutput(get(cloned, item.fieldName)));\n }\n\n return cloned;\n };\n\n const initAuthValues = (values: FormValues) => {\n for (const item of inputs) {\n const stored = localStorage.getItem(storageKeys.AuthField(item));\n\n if (stored) {\n const parsed = JSON.parse(stored);\n if (typeof parsed === typeof item.defaultValue) {\n set(values, item.fieldName, parsed);\n continue;\n }\n }\n\n set(values, item.fieldName, item.defaultValue);\n }\n\n return values;\n };\n\n return { inputs, mapInputs, initAuthValues };\n}\n\nfunction Route({ route, ...props }: ComponentProps<'div'> & { route: string }) {\n return (\n <div\n {...props}\n className={cn(\n 'flex flex-row items-center gap-0.5 overflow-auto text-nowrap',\n props.className,\n )}\n >\n {route.split('/').map((part, index) => (\n <Fragment key={index}>\n {index > 0 && <span className=\"text-fd-muted-foreground\">/</span>}\n {part.startsWith('{') && part.endsWith('}') ? (\n <code className=\"bg-fd-primary/10 text-fd-primary\">{part}</code>\n ) : (\n <code className=\"text-fd-foreground\">{part}</code>\n )}\n </Fragment>\n ))}\n </div>\n );\n}\n\nfunction DefaultResultDisplay({ data, reset }: { data: FetchResult; reset: () => void }) {\n const statusInfo = useMemo(() => getStatusInfo(data.status), [data.status]);\n const { shikiOptions } = useApiContext();\n\n return (\n <div className=\"flex flex-col gap-3 p-3\">\n <div className=\"flex justify-between items-center\">\n <div className=\"inline-flex items-center gap-1.5 text-sm font-medium text-fd-foreground\">\n <statusInfo.icon className={cn('size-4', statusInfo.color)} />\n {statusInfo.description}\n </div>\n <button\n type=\"button\"\n className={cn(\n buttonVariants({ size: 'icon-xs' }),\n 'p-0 text-fd-muted-foreground hover:text-fd-accent-foreground [&_svg]:size-3.5',\n )}\n onClick={() => reset()}\n aria-label=\"Dismiss response\"\n >\n <X />\n </button>\n </div>\n <p className=\"text-sm text-fd-muted-foreground\">{data.status}</p>\n {data.data !== undefined && (\n <DynamicCodeBlock\n lang={typeof data.data === 'string' && data.data.length > 50000 ? 'text' : data.type}\n code={typeof data.data === 'string' ? data.data : JSON.stringify(data.data, null, 2)}\n options={shikiOptions}\n />\n )}\n </div>\n );\n}\n\nfunction CollapsiblePanel({\n title,\n children,\n ...props\n}: Omit<ComponentProps<'div'>, 'title'> & {\n title: ReactNode;\n}) {\n return (\n <Collapsible {...props} className=\"border-b last:border-b-0\">\n <CollapsibleTrigger className=\"group w-full flex items-center gap-2 p-3 text-sm font-medium\">\n {title}\n <ChevronDown className=\"ms-auto size-3.5 text-fd-muted-foreground group-data-[state=open]:rotate-180\" />\n </CollapsibleTrigger>\n <CollapsibleContent>\n <div className=\"flex flex-col gap-3 p-3 pt-1\">{children}</div>\n </CollapsibleContent>\n </Collapsible>\n );\n}\n\n// exports for customisations\nexport const Custom = {\n useController<\n TName extends FieldPath<FormValues> = FieldPath<FormValues>,\n TTransformedValues = FormValues,\n >(\n props: UseControllerProps<FormValues, TName, TTransformedValues>,\n ): UseControllerReturn<FormValues, TName> {\n return useController<FormValues, TName, TTransformedValues>(props);\n },\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"client.js","names":[],"sources":["../../src/playground/client.tsx"],"sourcesContent":["'use client';\nimport {\n type FC,\n Fragment,\n lazy,\n type ReactNode,\n useEffect,\n useMemo,\n useState,\n type ComponentProps,\n useRef,\n} from 'react';\nimport { useApiContext } from '@/ui/contexts/api';\nimport type { FetchResult } from '@/playground/fetcher';\nimport type { ParameterField, SecurityEntry } from '@/playground/index';\nimport { getStatusInfo } from './status-info';\nimport { joinURL, resolveRequestData, resolveServerUrl, withBase } from '@/utils/url';\nimport { DynamicCodeBlock } from 'fumadocs-ui/components/dynamic-codeblock';\nimport { MethodLabel } from '@/ui/components/method-label';\nimport { useQuery } from '@/utils/use-query';\nimport {\n Collapsible,\n CollapsibleContent,\n CollapsibleTrigger,\n} from 'fumadocs-ui/components/ui/collapsible';\nimport { X, ChevronDown, LoaderCircle } from 'lucide-react';\nimport { encodeRequestData } from '@/requests/media/encode';\nimport { buttonVariants } from 'fumadocs-ui/components/ui/button';\nimport { cn } from '@/utils/cn';\nimport { SchemaProvider, SchemaScope, useResolvedSchema } from '@/playground/schema';\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@/ui/components/select';\nimport { labelVariants } from '@/ui/components/input';\nimport type { ParsedSchema } from '@/utils/schema';\nimport ServerSelect from './components/server-select';\nimport { useStorageKey } from '@/ui/client/storage-key';\nimport { useExampleRequests } from '@/ui/operation/usage-tabs/client';\nimport {\n FieldKey,\n Stf,\n StfProvider,\n useDataEngine,\n useFieldValue,\n useListener,\n useStf,\n} from '@fumari/stf';\nimport { objectGet, objectSet, stringifyFieldKey } from '@fumari/stf/lib/utils';\nimport { FieldInput, FieldSet, JsonInput, ObjectInput } from './components/inputs';\n\nexport interface FormValues extends Record<string, unknown> {\n path: Record<string, unknown>;\n query: Record<string, unknown>;\n header: Record<string, unknown>;\n cookie: Record<string, unknown>;\n body: unknown;\n}\n\nexport interface PlaygroundClientProps extends ComponentProps<'form'>, SchemaScope {\n route: string;\n method: string;\n parameters?: ParameterField[];\n securities: SecurityEntry[][];\n body?: {\n schema: ParsedSchema;\n mediaType: string;\n };\n /**\n * Resolver for $ref schemas you've passed\n */\n references: Record<string, ParsedSchema>;\n proxyUrl?: string;\n}\n\nexport interface PlaygroundClientOptions {\n /**\n * transform fields for auth-specific parameters (e.g. header)\n */\n transformAuthInputs?: (fields: AuthField[]) => AuthField[];\n\n /**\n * Request timeout in seconds (default: 10s)\n */\n requestTimeout?: number;\n\n components?: Partial<{\n ResultDisplay: FC<{ data: FetchResult }>;\n }>;\n\n /**\n * render the paremeter inputs of API endpoint.\n *\n * for updating values, use:\n * - the `Custom.useController()` from `fumadocs-openapi/playground/client`.\n *\n * Recommended types packages: `json-schema-typed`, `openapi-types`.\n */\n renderParameterField?: (fieldName: FieldKey, param: ParameterField) => ReactNode;\n\n /**\n * render the input for API endpoint body.\n *\n * @see renderParameterField for customisation tips\n */\n renderBodyField?: (\n fieldName: 'body',\n info: {\n schema: ParsedSchema;\n mediaType: string;\n },\n ) => ReactNode;\n}\n\nconst OauthDialog = lazy(() =>\n import('./components/oauth-dialog').then((mod) => ({\n default: mod.OauthDialog,\n })),\n);\nconst OauthDialogTrigger = lazy(() =>\n import('./components/oauth-dialog').then((mod) => ({\n default: mod.OauthDialogTrigger,\n })),\n);\n\nexport default function PlaygroundClient({\n route,\n method = 'GET',\n securities,\n parameters = [],\n body,\n references,\n proxyUrl,\n writeOnly,\n readOnly,\n ...rest\n}: PlaygroundClientProps) {\n const { example: exampleId, examples, setExampleData } = useExampleRequests();\n const storageKeys = useStorageKey();\n const {\n mediaAdapters,\n serverRef,\n client: {\n playground: {\n components: { ResultDisplay = DefaultResultDisplay } = {},\n requestTimeout = 10,\n transformAuthInputs,\n } = {},\n },\n } = useApiContext();\n const [securityId, setSecurityId] = useState(0);\n const { inputs, mapInputs, initAuthValues } = useAuthInputs(\n securities[securityId],\n transformAuthInputs,\n );\n\n const defaultValues: FormValues = useMemo(() => {\n const requestData = examples.find((example) => example.id === exampleId)?.data;\n\n return {\n path: requestData?.path ?? {},\n query: requestData?.query ?? {},\n header: requestData?.header ?? {},\n body: requestData?.body ?? {},\n cookie: requestData?.cookie ?? {},\n };\n }, [examples, exampleId]);\n\n const stf = useStf({\n // it is fine to modify `defaultValues` in place\n // because we already try to persist the form values via `setExampleData`.\n defaultValues,\n });\n\n const testQuery = useQuery(async (input: FormValues) => {\n const targetServer = serverRef.current;\n const fetcher = await import('./fetcher').then((mod) =>\n mod.createBrowserFetcher(mediaAdapters, requestTimeout),\n );\n const encoded = encodeRequestData(\n { ...mapInputs(input), method, bodyMediaType: body?.mediaType },\n mediaAdapters,\n parameters,\n );\n return fetcher.fetch(\n joinURL(\n withBase(\n targetServer ? resolveServerUrl(targetServer.url, targetServer.variables) : '/',\n window.location.origin,\n ),\n resolveRequestData(route, encoded),\n ),\n {\n proxyUrl,\n ...encoded,\n },\n );\n });\n\n const timerRef = useRef<number | null>(null);\n useListener({\n stf,\n onUpdate() {\n if (timerRef.current) window.clearTimeout(timerRef.current);\n timerRef.current = window.setTimeout(\n () => {\n const values = stf.dataEngine.getData() as FormValues;\n for (const item of inputs) {\n const value = stf.dataEngine.get(item.fieldName);\n\n if (value) {\n localStorage.setItem(storageKeys.AuthField(item), JSON.stringify(value));\n }\n }\n\n const data = {\n ...mapInputs(values),\n method,\n bodyMediaType: body?.mediaType,\n };\n setExampleData(data, encodeRequestData(data, mediaAdapters, parameters));\n },\n timerRef.current ? 400 : 0,\n );\n },\n });\n\n useEffect(() => {\n return () => {\n stf.dataEngine.reset(defaultValues);\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps -- ignore other parts\n }, [defaultValues]);\n\n useEffect(() => {\n return initAuthValues(stf);\n // eslint-disable-next-line react-hooks/exhaustive-deps -- ignore other parts\n }, [defaultValues, inputs]);\n\n return (\n <StfProvider value={stf}>\n <SchemaProvider references={references} writeOnly={writeOnly} readOnly={readOnly}>\n <form\n {...rest}\n className={cn(\n 'not-prose flex flex-col rounded-xl border shadow-md overflow-hidden bg-fd-card text-fd-card-foreground',\n rest.className,\n )}\n onSubmit={(e) => {\n testQuery.start(mapInputs(stf.dataEngine.getData() as FormValues));\n e.preventDefault();\n }}\n >\n <ServerSelect />\n <div className=\"flex flex-row items-center gap-2 text-sm p-3 not-last:pb-0\">\n <MethodLabel>{method}</MethodLabel>\n <Route route={route} className=\"flex-1\" />\n <button\n type=\"submit\"\n className={cn(buttonVariants({ color: 'primary', size: 'sm' }), 'w-14 py-1.5')}\n disabled={testQuery.isLoading}\n >\n {testQuery.isLoading ? <LoaderCircle className=\"size-4 animate-spin\" /> : 'Send'}\n </button>\n </div>\n\n {securities.length > 0 && (\n <SecurityTabs\n securities={securities}\n securityId={securityId}\n setSecurityId={setSecurityId}\n >\n {inputs.map((input) => (\n <Fragment key={stringifyFieldKey(input.fieldName)}>{input.children}</Fragment>\n ))}\n </SecurityTabs>\n )}\n <FormBody body={body} parameters={parameters} />\n {testQuery.data ? <ResultDisplay data={testQuery.data} reset={testQuery.reset} /> : null}\n </form>\n </SchemaProvider>\n </StfProvider>\n );\n}\n\nfunction SecurityTabs({\n securities,\n setSecurityId,\n securityId,\n children,\n}: {\n securities: SecurityEntry[][];\n securityId: number;\n setSecurityId: (value: number) => void;\n children: ReactNode;\n}) {\n const [open, setOpen] = useState(false);\n const engine = useDataEngine();\n\n const result = (\n <CollapsiblePanel title=\"Authorization\">\n <Select value={securityId.toString()} onValueChange={(v) => setSecurityId(Number(v))}>\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {securities.map((security, i) => (\n <SelectItem key={i} value={i.toString()}>\n {security.map((item) => (\n <div key={item.id} className=\"max-w-[600px]\">\n <p className=\"font-mono font-medium\">{item.id}</p>\n <p className=\"text-fd-muted-foreground whitespace-pre-wrap\">{item.description}</p>\n </div>\n ))}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n {children}\n </CollapsiblePanel>\n );\n\n for (let i = 0; i < securities.length; i++) {\n const security = securities[i];\n\n for (const item of security) {\n if (item.type === 'oauth2') {\n return (\n <OauthDialog\n scheme={item}\n scopes={item.scopes}\n open={open}\n setOpen={(v) => {\n setOpen(v);\n if (v) {\n setSecurityId(i);\n }\n }}\n setToken={(token) => engine.update(['header', 'Authorization'], token)}\n >\n {result}\n </OauthDialog>\n );\n }\n }\n }\n\n return result;\n}\n\nconst ParamTypes = ['path', 'header', 'cookie', 'query'] as const;\n\nfunction FormBody({ parameters = [], body }: Pick<PlaygroundClientProps, 'parameters' | 'body'>) {\n const { renderParameterField, renderBodyField } = useApiContext().client.playground ?? {};\n const panels = useMemo(() => {\n return ParamTypes.map((type) => {\n const items = parameters.filter((v) => v.in === type);\n if (items.length === 0) return;\n\n return (\n <CollapsiblePanel\n key={type}\n title={\n {\n header: 'Header',\n cookie: 'Cookies',\n query: 'Query',\n path: 'Path',\n }[type]\n }\n >\n {items.map((field) => {\n const fieldName: FieldKey = [type, field.name];\n if (renderParameterField) {\n return renderParameterField(fieldName, field);\n }\n\n const contentTypes = field.content && Object.keys(field.content);\n const schema = (\n field.content && contentTypes && contentTypes.length > 0\n ? field.content[contentTypes[0]].schema\n : field.schema\n ) as ParsedSchema;\n\n return (\n <FieldSet\n key={stringifyFieldKey(fieldName)}\n name={field.name}\n fieldName={fieldName}\n field={schema}\n />\n );\n })}\n </CollapsiblePanel>\n );\n });\n }, [parameters, renderParameterField]);\n\n return (\n <>\n {panels}\n {body && (\n <CollapsiblePanel title=\"Body\">\n {renderBodyField ? renderBodyField('body', body) : <BodyInput field={body.schema} />}\n </CollapsiblePanel>\n )}\n </>\n );\n}\n\nfunction BodyInput({ field: _field }: { field: ParsedSchema }) {\n const field = useResolvedSchema(_field);\n const [isJson, setIsJson] = useState(false);\n\n if (field.format === 'binary') return <FieldSet field={field} fieldName={['body']} />;\n\n if (isJson)\n return (\n <>\n <button\n className={cn(\n buttonVariants({\n color: 'secondary',\n size: 'sm',\n className: 'w-fit font-mono p-2',\n }),\n )}\n onClick={() => setIsJson(false)}\n type=\"button\"\n >\n Close JSON Editor\n </button>\n <JsonInput fieldName={['body']} />\n </>\n );\n\n return (\n <FieldSet\n field={field}\n fieldName={['body']}\n collapsible={false}\n name={\n <button\n type=\"button\"\n className={cn(\n buttonVariants({\n color: 'secondary',\n size: 'sm',\n className: 'p-2',\n }),\n )}\n onClick={() => setIsJson(true)}\n >\n Open JSON Editor\n </button>\n }\n />\n );\n}\n\nexport interface AuthField {\n fieldName: FieldKey;\n defaultValue: unknown;\n\n original?: SecurityEntry;\n children: ReactNode;\n\n mapOutput?: (values: unknown) => unknown;\n}\n\nfunction useAuthInputs(\n securities?: SecurityEntry[],\n transform?: (fields: AuthField[]) => AuthField[],\n) {\n const storageKeys = useStorageKey();\n const inputs = useMemo(() => {\n const result: AuthField[] = [];\n if (!securities) return result;\n\n for (const security of securities) {\n if (security.type === 'http' && security.scheme === 'basic') {\n const fieldName: FieldKey = ['header', 'Authorization'];\n\n result.push({\n fieldName,\n original: security,\n defaultValue: {\n username: '',\n password: '',\n },\n mapOutput(out) {\n if (out && typeof out === 'object') {\n return `Basic ${btoa(`${'username' in out ? out.username : ''}:${'password' in out ? out.password : ''}`)}`;\n }\n\n return out;\n },\n children: (\n <ObjectInput\n field={{\n type: 'object',\n properties: {\n username: {\n type: 'string',\n },\n password: {\n type: 'string',\n },\n },\n required: ['username', 'password'],\n }}\n fieldName={fieldName}\n />\n ),\n });\n } else if (security.type === 'oauth2') {\n const fieldName: FieldKey = ['header', 'Authorization'];\n\n result.push({\n fieldName,\n original: security,\n defaultValue: 'Bearer ',\n children: (\n <fieldset className=\"flex flex-col gap-2\">\n <label htmlFor={stringifyFieldKey(fieldName)} className={cn(labelVariants())}>\n Access Token\n </label>\n <div className=\"flex gap-2\">\n <FieldInput\n fieldName={fieldName}\n isRequired\n field={{\n type: 'string',\n }}\n className=\"flex-1\"\n />\n\n <OauthDialogTrigger\n type=\"button\"\n className={cn(\n buttonVariants({\n size: 'sm',\n color: 'secondary',\n }),\n )}\n >\n Authorize\n </OauthDialogTrigger>\n </div>\n </fieldset>\n ),\n });\n } else if (security.type === 'http') {\n const fieldName: FieldKey = ['header', 'Authorization'];\n\n result.push({\n fieldName,\n original: security,\n defaultValue: 'Bearer ',\n children: (\n <FieldSet\n name=\"Authorization (header)\"\n fieldName={fieldName}\n isRequired\n field={{\n type: 'string',\n }}\n />\n ),\n });\n } else if (security.type === 'apiKey') {\n const fieldName: FieldKey = [security.in, security.name];\n\n result.push({\n fieldName,\n defaultValue: '',\n original: security,\n children: (\n <FieldSet\n fieldName={fieldName}\n name={`${security.name} (${security.in})`}\n isRequired\n field={{\n type: 'string',\n }}\n />\n ),\n });\n } else {\n const fieldName: FieldKey = ['header', 'Authorization'];\n\n result.push({\n fieldName,\n defaultValue: '',\n original: security,\n children: (\n <>\n <FieldSet\n name=\"Authorization (header)\"\n isRequired\n fieldName={fieldName}\n field={{\n type: 'string',\n }}\n />\n <p className=\"text-fd-muted-foreground text-xs\">\n OpenID Connect is not supported at the moment, you can still set an access token\n here.\n </p>\n </>\n ),\n });\n }\n }\n\n return transform ? transform(result) : result;\n }, [securities, transform]);\n\n const mapInputs = (values: FormValues) => {\n const cloned = structuredClone(values);\n\n for (const item of inputs) {\n if (!item.mapOutput) continue;\n objectSet(cloned, item.fieldName, item.mapOutput(objectGet(cloned, item.fieldName)));\n }\n\n return cloned;\n };\n\n const initAuthValues = (stf: Stf) => {\n const { dataEngine } = stf;\n for (const item of inputs) {\n const stored = localStorage.getItem(storageKeys.AuthField(item));\n\n if (stored) {\n const parsed = JSON.parse(stored);\n if (typeof parsed === typeof item.defaultValue) {\n dataEngine.init(item.fieldName, parsed);\n continue;\n }\n }\n\n dataEngine.init(item.fieldName, item.defaultValue);\n }\n\n // reset\n return () => {\n for (const item of inputs) {\n stf.dataEngine.delete(item.fieldName);\n }\n };\n };\n\n return { inputs, mapInputs, initAuthValues };\n}\n\nfunction Route({ route, ...props }: ComponentProps<'div'> & { route: string }) {\n return (\n <div\n {...props}\n className={cn(\n 'flex flex-row items-center gap-0.5 overflow-auto text-nowrap',\n props.className,\n )}\n >\n {route.split('/').map((part, index) => (\n <Fragment key={index}>\n {index > 0 && <span className=\"text-fd-muted-foreground\">/</span>}\n {part.startsWith('{') && part.endsWith('}') ? (\n <code className=\"bg-fd-primary/10 text-fd-primary\">{part}</code>\n ) : (\n <code className=\"text-fd-foreground\">{part}</code>\n )}\n </Fragment>\n ))}\n </div>\n );\n}\n\nfunction DefaultResultDisplay({ data, reset }: { data: FetchResult; reset: () => void }) {\n const statusInfo = useMemo(() => getStatusInfo(data.status), [data.status]);\n const { shikiOptions } = useApiContext();\n\n return (\n <div className=\"flex flex-col gap-3 p-3\">\n <div className=\"flex justify-between items-center\">\n <div className=\"inline-flex items-center gap-1.5 text-sm font-medium text-fd-foreground\">\n <statusInfo.icon className={cn('size-4', statusInfo.color)} />\n {statusInfo.description}\n </div>\n <button\n type=\"button\"\n className={cn(\n buttonVariants({ size: 'icon-xs' }),\n 'p-0 text-fd-muted-foreground hover:text-fd-accent-foreground [&_svg]:size-3.5',\n )}\n onClick={() => reset()}\n aria-label=\"Dismiss response\"\n >\n <X />\n </button>\n </div>\n <p className=\"text-sm text-fd-muted-foreground\">{data.status}</p>\n {data.data !== undefined && (\n <DynamicCodeBlock\n lang={typeof data.data === 'string' && data.data.length > 50000 ? 'text' : data.type}\n code={typeof data.data === 'string' ? data.data : JSON.stringify(data.data, null, 2)}\n options={shikiOptions}\n />\n )}\n </div>\n );\n}\n\nfunction CollapsiblePanel({\n title,\n children,\n ...props\n}: Omit<ComponentProps<'div'>, 'title'> & {\n title: ReactNode;\n}) {\n return (\n <Collapsible {...props} className=\"border-b last:border-b-0\">\n <CollapsibleTrigger className=\"group w-full flex items-center gap-2 p-3 text-sm font-medium\">\n {title}\n <ChevronDown className=\"ms-auto size-3.5 text-fd-muted-foreground group-data-[state=open]:rotate-180\" />\n </CollapsibleTrigger>\n <CollapsibleContent>\n <div className=\"flex flex-col gap-3 p-3 pt-1\">{children}</div>\n </CollapsibleContent>\n </Collapsible>\n );\n}\n\nexport const Custom = {\n useController(\n fieldName: FieldKey,\n options?: {\n defaultValue?: unknown;\n },\n ) {\n const [value, setValue] = useFieldValue(fieldName, options);\n return {\n value,\n setValue,\n };\n },\n};\n"],"mappings":"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"}