fumadocs-openapi 10.6.2 → 10.6.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/css/generated/shared.css +8 -17
- package/dist/generate-file.d.ts +2 -2
- package/dist/generate-file.d.ts.map +1 -1
- package/dist/generate-file.js.map +1 -1
- package/dist/playground/client.d.ts +15 -19
- package/dist/playground/client.d.ts.map +1 -1
- package/dist/playground/client.js +30 -18
- package/dist/playground/client.js.map +1 -1
- package/dist/playground/schema.js +14 -35
- package/dist/playground/schema.js.map +1 -1
- package/dist/server/create.d.ts +1 -1
- package/dist/server/create.js +1 -1
- package/dist/server/create.js.map +1 -1
- package/dist/server/source-api.d.ts +2 -2
- package/dist/server/source-api.d.ts.map +1 -1
- package/dist/server/source-api.js.map +1 -1
- package/dist/types.d.ts +4 -4
- package/dist/types.d.ts.map +1 -1
- package/dist/ui/base.d.ts +10 -9
- package/dist/ui/base.d.ts.map +1 -1
- package/dist/ui/base.js +22 -0
- package/dist/ui/base.js.map +1 -1
- package/dist/ui/components/{server-tab.js → select-tab.js} +11 -11
- package/dist/ui/components/select-tab.js.map +1 -0
- package/dist/ui/create-client.d.ts.map +1 -1
- package/dist/ui/create-client.js +18 -13
- package/dist/ui/create-client.js.map +1 -1
- package/dist/ui/operation/get-example-requests.js +2 -2
- package/dist/ui/operation/get-example-requests.js.map +1 -1
- package/dist/ui/operation/index.js +6 -7
- package/dist/ui/operation/index.js.map +1 -1
- package/dist/ui/operation/response-tabs.d.ts +1 -1
- package/dist/ui/schema/index.d.ts +1 -1
- package/dist/utils/deep-equal.js +8 -4
- package/dist/utils/deep-equal.js.map +1 -1
- package/dist/utils/document/dereference.d.ts +18 -0
- package/dist/utils/document/dereference.d.ts.map +1 -0
- package/dist/utils/document/dereference.js +21 -0
- package/dist/utils/document/dereference.js.map +1 -0
- package/dist/utils/document/process.d.ts +7 -0
- package/dist/utils/document/process.d.ts.map +1 -0
- package/dist/utils/{process-document.js → document/process.js} +5 -18
- package/dist/utils/document/process.js.map +1 -0
- package/dist/utils/is-plain-object.js +10 -0
- package/dist/utils/is-plain-object.js.map +1 -0
- package/dist/utils/pages/builder.d.ts +4 -4
- package/dist/utils/pages/builder.d.ts.map +1 -1
- package/dist/utils/pages/builder.js.map +1 -1
- package/dist/utils/pages/preset-auto.d.ts +2 -2
- package/dist/utils/pages/preset-auto.d.ts.map +1 -1
- package/dist/utils/pages/preset-auto.js.map +1 -1
- package/dist/utils/pages/to-text.js.map +1 -1
- package/dist/utils/remove-undefined.js +10 -8
- package/dist/utils/remove-undefined.js.map +1 -1
- package/dist/utils/schema/index.d.ts +7 -2
- package/dist/utils/schema/index.d.ts.map +1 -1
- package/dist/utils/schema/index.js +21 -2
- package/dist/utils/schema/index.js.map +1 -1
- package/dist/utils/schema/pick.js +46 -0
- package/dist/utils/schema/pick.js.map +1 -0
- package/dist/utils/schema/ref.js +37 -0
- package/dist/utils/schema/ref.js.map +1 -0
- package/dist/utils/schema/resolve-ref.js +4 -12
- package/dist/utils/schema/resolve-ref.js.map +1 -1
- package/dist/utils/schema/to-string.js.map +1 -1
- package/package.json +3 -4
- package/dist/playground/index.d.ts +0 -22
- package/dist/playground/index.d.ts.map +0 -1
- package/dist/playground/index.js +0 -118
- package/dist/playground/index.js.map +0 -1
- package/dist/ui/components/server-tab.js.map +0 -1
- package/dist/utils/process-document.d.ts +0 -18
- package/dist/utils/process-document.d.ts.map +0 -1
- package/dist/utils/process-document.js.map +0 -1
package/css/generated/shared.css
CHANGED
|
@@ -97,7 +97,6 @@
|
|
|
97
97
|
@source inline("binary");
|
|
98
98
|
@source inline("blue");
|
|
99
99
|
@source inline("body");
|
|
100
|
-
@source inline("bodyContent");
|
|
101
100
|
@source inline("bodyMediaType");
|
|
102
101
|
@source inline("bodyNode");
|
|
103
102
|
@source inline("bodyOfType");
|
|
@@ -171,7 +170,6 @@
|
|
|
171
170
|
@source inline("cookies");
|
|
172
171
|
@source inline("core");
|
|
173
172
|
@source inline("could");
|
|
174
|
-
@source inline("count");
|
|
175
173
|
@source inline("createAutoPreset");
|
|
176
174
|
@source inline("createContext");
|
|
177
175
|
@source inline("createMethod");
|
|
@@ -220,8 +218,7 @@
|
|
|
220
218
|
@source inline("definitions");
|
|
221
219
|
@source inline("deprecated");
|
|
222
220
|
@source inline("depth");
|
|
223
|
-
@source inline("
|
|
224
|
-
@source inline("dereferenceSync");
|
|
221
|
+
@source inline("dereferenceDocument");
|
|
225
222
|
@source inline("dereferenced");
|
|
226
223
|
@source inline("description");
|
|
227
224
|
@source inline("descriptionNode");
|
|
@@ -237,6 +234,7 @@
|
|
|
237
234
|
@source inline("div");
|
|
238
235
|
@source inline("divide-fd-border");
|
|
239
236
|
@source inline("divide-y");
|
|
237
|
+
@source inline("doc");
|
|
240
238
|
@source inline("document");
|
|
241
239
|
@source inline("doesn");
|
|
242
240
|
@source inline("domain");
|
|
@@ -250,6 +248,7 @@
|
|
|
250
248
|
@source inline("empty");
|
|
251
249
|
@source inline("empty:hidden");
|
|
252
250
|
@source inline("enabled");
|
|
251
|
+
@source inline("encodeInternalRef");
|
|
253
252
|
@source inline("encodeRequestData");
|
|
254
253
|
@source inline("encoded");
|
|
255
254
|
@source inline("end-2");
|
|
@@ -264,6 +263,7 @@
|
|
|
264
263
|
@source inline("error");
|
|
265
264
|
@source inline("eslint-disable");
|
|
266
265
|
@source inline("eslint-disable-next-line");
|
|
266
|
+
@source inline("eslint-plugin-react-hooks/rules-of-hooks");
|
|
267
267
|
@source inline("example");
|
|
268
268
|
@source inline("exampleId");
|
|
269
269
|
@source inline("exampleRequests");
|
|
@@ -354,6 +354,7 @@
|
|
|
354
354
|
@source inline("generated");
|
|
355
355
|
@source inline("generated/defined");
|
|
356
356
|
@source inline("generators");
|
|
357
|
+
@source inline("get");
|
|
357
358
|
@source inline("getAPIPageProps");
|
|
358
359
|
@source inline("getClientAPIPageProps");
|
|
359
360
|
@source inline("getExampleRequests");
|
|
@@ -449,10 +450,8 @@
|
|
|
449
450
|
@source inline("j");
|
|
450
451
|
@source inline("json");
|
|
451
452
|
@source inline("json-schema-typed");
|
|
452
|
-
@source inline("json-schema-typed/draft-2020-12");
|
|
453
453
|
@source inline("justify-between");
|
|
454
454
|
@source inline("justify-center");
|
|
455
|
-
@source inline("k");
|
|
456
455
|
@source inline("key");
|
|
457
456
|
@source inline("keyof");
|
|
458
457
|
@source inline("kind");
|
|
@@ -500,7 +499,6 @@
|
|
|
500
499
|
@source inline("mediaType");
|
|
501
500
|
@source inline("merge");
|
|
502
501
|
@source inline("mergeAllOf");
|
|
503
|
-
@source inline("merged");
|
|
504
502
|
@source inline("message");
|
|
505
503
|
@source inline("meta");
|
|
506
504
|
@source inline("metaData");
|
|
@@ -588,11 +586,11 @@
|
|
|
588
586
|
@source inline("out");
|
|
589
587
|
@source inline("outline");
|
|
590
588
|
@source inline("outline-none");
|
|
591
|
-
@source inline("output");
|
|
592
589
|
@source inline("overflow-auto");
|
|
593
590
|
@source inline("overflow-hidden");
|
|
594
591
|
@source inline("overrides");
|
|
595
592
|
@source inline("overview");
|
|
593
|
+
@source inline("oxlint-disable-next-line");
|
|
596
594
|
@source inline("p-1");
|
|
597
595
|
@source inline("p-1.5");
|
|
598
596
|
@source inline("p-2");
|
|
@@ -609,11 +607,11 @@
|
|
|
609
607
|
@source inline("parameters");
|
|
610
608
|
@source inline("params");
|
|
611
609
|
@source inline("parent");
|
|
610
|
+
@source inline("parseSecurities");
|
|
612
611
|
@source inline("parsed");
|
|
613
612
|
@source inline("parsedState");
|
|
614
613
|
@source inline("parts");
|
|
615
614
|
@source inline("pass");
|
|
616
|
-
@source inline("passed");
|
|
617
615
|
@source inline("password");
|
|
618
616
|
@source inline("path");
|
|
619
617
|
@source inline("pathItem");
|
|
@@ -633,6 +631,7 @@
|
|
|
633
631
|
@source inline("persist");
|
|
634
632
|
@source inline("persistent");
|
|
635
633
|
@source inline("pickExample");
|
|
634
|
+
@source inline("pickSchema");
|
|
636
635
|
@source inline("place");
|
|
637
636
|
@source inline("placeholder");
|
|
638
637
|
@source inline("placeholder:text-fd-muted-foreground");
|
|
@@ -681,7 +680,6 @@
|
|
|
681
680
|
@source inline("query");
|
|
682
681
|
@source inline("queryParameters");
|
|
683
682
|
@source inline("quiet");
|
|
684
|
-
@source inline("r");
|
|
685
683
|
@source inline("race");
|
|
686
684
|
@source inline("range");
|
|
687
685
|
@source inline("raw");
|
|
@@ -698,10 +696,8 @@
|
|
|
698
696
|
@source inline("ref");
|
|
699
697
|
@source inline("refCallback");
|
|
700
698
|
@source inline("reference");
|
|
701
|
-
@source inline("references");
|
|
702
699
|
@source inline("refs");
|
|
703
700
|
@source inline("registerDefault");
|
|
704
|
-
@source inline("registered");
|
|
705
701
|
@source inline("registry");
|
|
706
702
|
@source inline("rehype-react");
|
|
707
703
|
@source inline("relativePath");
|
|
@@ -743,9 +739,7 @@
|
|
|
743
739
|
@source inline("res");
|
|
744
740
|
@source inline("reset");
|
|
745
741
|
@source inline("resize-none");
|
|
746
|
-
@source inline("resolve");
|
|
747
742
|
@source inline("resolveMediaAdapter");
|
|
748
|
-
@source inline("resolveRefSync");
|
|
749
743
|
@source inline("resolveRequestData");
|
|
750
744
|
@source inline("resolved");
|
|
751
745
|
@source inline("resolvedTheme");
|
|
@@ -874,7 +868,6 @@
|
|
|
874
868
|
@source inline("so");
|
|
875
869
|
@source inline("spec");
|
|
876
870
|
@source inline("specify");
|
|
877
|
-
@source inline("stack");
|
|
878
871
|
@source inline("state");
|
|
879
872
|
@source inline("status");
|
|
880
873
|
@source inline("statusBadRequest");
|
|
@@ -909,7 +902,6 @@
|
|
|
909
902
|
@source inline("tab");
|
|
910
903
|
@source inline("tabs");
|
|
911
904
|
@source inline("tag");
|
|
912
|
-
@source inline("takenIds");
|
|
913
905
|
@source inline("testQuery");
|
|
914
906
|
@source inline("text");
|
|
915
907
|
@source inline("text-[0.8125rem]");
|
|
@@ -1031,7 +1023,6 @@
|
|
|
1031
1023
|
@source inline("variables");
|
|
1032
1024
|
@source inline("variant");
|
|
1033
1025
|
@source inline("variants");
|
|
1034
|
-
@source inline("ve");
|
|
1035
1026
|
@source inline("via");
|
|
1036
1027
|
@source inline("virtual");
|
|
1037
1028
|
@source inline("vite-rsc");
|
package/dist/generate-file.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { OpenAPIServer } from "./server/create.js";
|
|
|
2
2
|
import { OutputEntry } from "./utils/pages/builder.js";
|
|
3
3
|
import { SchemaToPagesOptions } from "./utils/pages/preset-auto.js";
|
|
4
4
|
import { DistributiveOmit } from "./types.js";
|
|
5
|
-
import {
|
|
5
|
+
import { DereferencedDocument } from "./utils/document/dereference.js";
|
|
6
6
|
import { PagesToTextOptions } from "./utils/pages/to-text.js";
|
|
7
7
|
|
|
8
8
|
//#region src/generate-file.d.ts
|
|
@@ -73,7 +73,7 @@ type Config = SchemaToPagesOptions & GenerateFilesConfig & {
|
|
|
73
73
|
interface BeforeWriteContext {
|
|
74
74
|
readonly generated: Record<string, OutputFile[]>;
|
|
75
75
|
readonly generatedEntries: Record<string, OutputEntry[]>;
|
|
76
|
-
readonly documents: Record<string,
|
|
76
|
+
readonly documents: Record<string, DereferencedDocument>;
|
|
77
77
|
}
|
|
78
78
|
declare function generateFiles(options: Config): Promise<void>;
|
|
79
79
|
declare function generateFilesOnly(options: DistributiveOmit<Config, 'output'>): Promise<OutputFile[]>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generate-file.d.ts","names":[],"sources":["../src/generate-file.ts"],"mappings":";;;;;;;;UAUiB,UAAA;EACf,IAAA;EACA,OAAA;AAAA;AAAA,UAGQ,WAAA;EACR,KAAA,EAAO,SAAA,OAAgB,GAAA,EAAK,kBAAA,KAAuB,SAAA;EALnD;;AAED;EAQC,GAAA,IACM,QAAA;IAEA,OAAA;IARC;;;IAYD,UAAA;EAAA;AAAA;AAAA,UAIE,SAAA;EAhBoB;EAkB5B,IAAA;EACA,KAAA;EACA,WAAA;EAdM;;;;;EAqBN,IAAA;AAAA;AAAA,UAGQ,mBAAA,SAA4B,kBAAA;EAdnB;;;EAkBjB,KAAA,EAAO,aAAA;EAPP;;;EAYA,MAAA;EAT4B;;;EAc5B,KAAA,GAAQ,WAAA;EAOS;;;;;EAAjB,IAAA,aAAiB,WAAA;EArBqC;;;EA0BtD,WAAA,IAAe,IAAA,EAAM,kBAAA,EAAoB,KAAA,EAAO,UAAA,cAAwB,OAAA;AAAA;AAAA,UAGhE,WAAA;EACR,UAAA;AAAA;AAAA,KAGU,MAAA,GAAS,oBAAA,GACnB,mBAAA;EARA;;;;;EAcE,KAAA;AAAA;AAAA,UAGM,kBAAA;EAAA,SACC,SAAA,EAAW,MAAA,SAAe,UAAA;EAAA,SAC1B,gBAAA,EAAkB,MAAA,SAAe,WAAA;EAAA,SACjC,SAAA,EAAW,MAAA,SAAe,
|
|
1
|
+
{"version":3,"file":"generate-file.d.ts","names":[],"sources":["../src/generate-file.ts"],"mappings":";;;;;;;;UAUiB,UAAA;EACf,IAAA;EACA,OAAA;AAAA;AAAA,UAGQ,WAAA;EACR,KAAA,EAAO,SAAA,OAAgB,GAAA,EAAK,kBAAA,KAAuB,SAAA;EALnD;;AAED;EAQC,GAAA,IACM,QAAA;IAEA,OAAA;IARC;;;IAYD,UAAA;EAAA;AAAA;AAAA,UAIE,SAAA;EAhBoB;EAkB5B,IAAA;EACA,KAAA;EACA,WAAA;EAdM;;;;;EAqBN,IAAA;AAAA;AAAA,UAGQ,mBAAA,SAA4B,kBAAA;EAdnB;;;EAkBjB,KAAA,EAAO,aAAA;EAPP;;;EAYA,MAAA;EAT4B;;;EAc5B,KAAA,GAAQ,WAAA;EAOS;;;;;EAAjB,IAAA,aAAiB,WAAA;EArBqC;;;EA0BtD,WAAA,IAAe,IAAA,EAAM,kBAAA,EAAoB,KAAA,EAAO,UAAA,cAAwB,OAAA;AAAA;AAAA,UAGhE,WAAA;EACR,UAAA;AAAA;AAAA,KAGU,MAAA,GAAS,oBAAA,GACnB,mBAAA;EARA;;;;;EAcE,KAAA;AAAA;AAAA,UAGM,kBAAA;EAAA,SACC,SAAA,EAAW,MAAA,SAAe,UAAA;EAAA,SAC1B,gBAAA,EAAkB,MAAA,SAAe,WAAA;EAAA,SACjC,SAAA,EAAW,MAAA,SAAe,oBAAA;AAAA;AAAA,iBAGf,aAAA,CAAc,OAAA,EAAS,MAAA,GAAS,OAAA;AAAA,iBA2BhC,iBAAA,CACpB,OAAA,EAAS,gBAAA,CAAiB,MAAA,cACzB,OAAA,CAAQ,UAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generate-file.js","names":["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, PathUtils } from 'fumadocs-core/source';\nimport { createAutoPreset, type SchemaToPagesOptions } from '@/utils/pages/preset-auto';\nimport { fromSchema, type OutputGroup, type OutputEntry } from '@/utils/pages/builder';\nimport type { DistributiveOmit } from './types';\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 /** output path of index page */\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 * - file paths (using forward slash).\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 * Generate `meta.json` files.\n *\n * Note: for flexibility, it's recommended to define them on your own.\n */\n meta?: boolean | MetaOptions;\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\ninterface MetaOptions {\n groupStyle?: 'folder' | 'separator';\n}\n\nexport type Config = SchemaToPagesOptions &\n GenerateFilesConfig & {\n /**\n * Re-generate when **schema files are changed**, ignores custom input functions & URLs.\n *\n * Note: it is recommended to configure & use `chokidar` on your own, this is only for simple cases.\n */\n watch?: boolean;\n };\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 if (options.watch) {\n const { watch } = await import('chokidar');\n const subOptions: Config = { ...options, watch: false };\n\n await generateFiles(subOptions);\n const targets = options.input._getWatchPaths();\n console.log(`[Fumadocs OpenAPI] watching ${targets.join(', ')}`);\n watch(targets, {\n ignoreInitial: true,\n }).on('all', () => generateFiles(subOptions));\n return;\n }\n\n const files = await generateFilesOnly(options);\n\n await Promise.all(\n files.map(async (file) => {\n const filePath = path.join(options.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: DistributiveOmit<Config, '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: OutputFile[] = [];\n\n generatedEntries[id] = entries;\n function scan(entry: OutputEntry) {\n if (entry.type === 'group') {\n for (const child of entry.entries) scan(child);\n return;\n }\n\n schemaFiles.push({\n path: entry.path,\n content: toText(entry, schema, options),\n });\n }\n\n for (const entry of entries) scan(entry);\n generated[id] = schemaFiles;\n files.push(...schemaFiles);\n }\n\n const context: BeforeWriteContext = {\n generated,\n generatedEntries,\n documents: schemas,\n };\n\n if (options.index) {\n files.push(...writeIndexFiles(context, options));\n }\n\n if (options.meta) {\n files.push(...generateMeta(context, options.meta === true ? {} : options.meta));\n }\n\n await options.beforeWrite?.call(context, files);\n return files;\n}\n\nfunction generateMeta(context: BeforeWriteContext, options: MetaOptions): OutputFile[] {\n const files: OutputFile[] = [];\n const { groupStyle = 'folder' } = options;\n\n function scan(entries: OutputEntry[], parent?: OutputGroup) {\n const pages: string[] = [];\n\n for (const entry of entries) {\n const relativePath = PathUtils.slash(\n parent ? path.relative(parent.path, entry.path) : entry.path,\n );\n\n if (entry.type === 'group') {\n scan(entry.entries, entry);\n\n if (groupStyle === 'folder') {\n pages.push(relativePath);\n } else {\n pages.push(`---${entry.info.title}---`, `...${relativePath}`);\n }\n } else {\n pages.push(relativePath.slice(0, -path.extname(entry.path).length));\n }\n }\n\n if (pages.length === 0) return;\n files.push({\n path: parent ? path.join(parent.path, 'meta.json') : 'meta.json',\n content: JSON.stringify(\n {\n title: parent?.info.title,\n description: parent?.info.description,\n pages,\n },\n null,\n 2,\n ),\n });\n }\n\n for (const entries of Object.values(context.generatedEntries)) {\n scan(entries);\n }\n\n return files;\n}\n\nfunction writeIndexFiles(\n context: BeforeWriteContext,\n options: SchemaToPagesOptions & Omit<GenerateFilesConfig, 'output'>,\n): OutputFile[] {\n const files: OutputFile[] = [];\n const { generatedEntries } = context;\n const pathToEntry = new Map<string, OutputEntry>();\n const { items, url } = options.index!;\n\n function indexEntry(entry: OutputEntry) {\n pathToEntry.set(PathUtils.slash(entry.path), entry);\n if (entry.type === 'group') {\n for (const child of entry.entries) {\n indexEntry(child);\n }\n }\n }\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 fileContent(index: IndexItem): string {\n const content: string[] = [];\n content.push('<Cards>');\n const outputEntries: 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 outputEntries.push(entry);\n }\n } else {\n const match = pathToEntry.get(item);\n if (!match) {\n throw new Error(\n `${item} does not exist on \"input\", available: ${Object.keys(generatedEntries).join(', ')}.`,\n );\n }\n\n outputEntries.push(match);\n }\n }\n\n for (const entry of outputEntries) {\n // cannot link to groups\n if (entry.type === 'group') continue;\n const descriptionAttr = entry.info.description\n ? `description=${JSON.stringify(entry.info.description)} `\n : '';\n content.push(\n `<Card href=\"${urlFn(entry.path)}\" title=${JSON.stringify(entry.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 list of Object.values(context.generatedEntries)) {\n for (const item of list) indexEntry(item);\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 return files;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"generate-file.js","names":["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 { DereferencedDocument } from '@/utils/document/dereference';\nimport type { OpenAPIServer } from '@/server';\nimport { createGetUrl, getSlugs, PathUtils } from 'fumadocs-core/source';\nimport { createAutoPreset, type SchemaToPagesOptions } from '@/utils/pages/preset-auto';\nimport { fromSchema, type OutputGroup, type OutputEntry } from '@/utils/pages/builder';\nimport type { DistributiveOmit } from './types';\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 /** output path of index page */\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 * - file paths (using forward slash).\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 * Generate `meta.json` files.\n *\n * Note: for flexibility, it's recommended to define them on your own.\n */\n meta?: boolean | MetaOptions;\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\ninterface MetaOptions {\n groupStyle?: 'folder' | 'separator';\n}\n\nexport type Config = SchemaToPagesOptions &\n GenerateFilesConfig & {\n /**\n * Re-generate when **schema files are changed**, ignores custom input functions & URLs.\n *\n * Note: it is recommended to configure & use `chokidar` on your own, this is only for simple cases.\n */\n watch?: boolean;\n };\n\ninterface BeforeWriteContext {\n readonly generated: Record<string, OutputFile[]>;\n readonly generatedEntries: Record<string, OutputEntry[]>;\n readonly documents: Record<string, DereferencedDocument>;\n}\n\nexport async function generateFiles(options: Config): Promise<void> {\n if (options.watch) {\n const { watch } = await import('chokidar');\n const subOptions: Config = { ...options, watch: false };\n\n await generateFiles(subOptions);\n const targets = options.input._getWatchPaths();\n console.log(`[Fumadocs OpenAPI] watching ${targets.join(', ')}`);\n watch(targets, {\n ignoreInitial: true,\n }).on('all', () => generateFiles(subOptions));\n return;\n }\n\n const files = await generateFilesOnly(options);\n\n await Promise.all(\n files.map(async (file) => {\n const filePath = path.join(options.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: DistributiveOmit<Config, '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: OutputFile[] = [];\n\n generatedEntries[id] = entries;\n function scan(entry: OutputEntry) {\n if (entry.type === 'group') {\n for (const child of entry.entries) scan(child);\n return;\n }\n\n schemaFiles.push({\n path: entry.path,\n content: toText(entry, schema, options),\n });\n }\n\n for (const entry of entries) scan(entry);\n generated[id] = schemaFiles;\n files.push(...schemaFiles);\n }\n\n const context: BeforeWriteContext = {\n generated,\n generatedEntries,\n documents: schemas,\n };\n\n if (options.index) {\n files.push(...writeIndexFiles(context, options));\n }\n\n if (options.meta) {\n files.push(...generateMeta(context, options.meta === true ? {} : options.meta));\n }\n\n await options.beforeWrite?.call(context, files);\n return files;\n}\n\nfunction generateMeta(context: BeforeWriteContext, options: MetaOptions): OutputFile[] {\n const files: OutputFile[] = [];\n const { groupStyle = 'folder' } = options;\n\n function scan(entries: OutputEntry[], parent?: OutputGroup) {\n const pages: string[] = [];\n\n for (const entry of entries) {\n const relativePath = PathUtils.slash(\n parent ? path.relative(parent.path, entry.path) : entry.path,\n );\n\n if (entry.type === 'group') {\n scan(entry.entries, entry);\n\n if (groupStyle === 'folder') {\n pages.push(relativePath);\n } else {\n pages.push(`---${entry.info.title}---`, `...${relativePath}`);\n }\n } else {\n pages.push(relativePath.slice(0, -path.extname(entry.path).length));\n }\n }\n\n if (pages.length === 0) return;\n files.push({\n path: parent ? path.join(parent.path, 'meta.json') : 'meta.json',\n content: JSON.stringify(\n {\n title: parent?.info.title,\n description: parent?.info.description,\n pages,\n },\n null,\n 2,\n ),\n });\n }\n\n for (const entries of Object.values(context.generatedEntries)) {\n scan(entries);\n }\n\n return files;\n}\n\nfunction writeIndexFiles(\n context: BeforeWriteContext,\n options: SchemaToPagesOptions & Omit<GenerateFilesConfig, 'output'>,\n): OutputFile[] {\n const files: OutputFile[] = [];\n const { generatedEntries } = context;\n const pathToEntry = new Map<string, OutputEntry>();\n const { items, url } = options.index!;\n\n function indexEntry(entry: OutputEntry) {\n pathToEntry.set(PathUtils.slash(entry.path), entry);\n if (entry.type === 'group') {\n for (const child of entry.entries) {\n indexEntry(child);\n }\n }\n }\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 fileContent(index: IndexItem): string {\n const content: string[] = [];\n content.push('<Cards>');\n const outputEntries: 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 outputEntries.push(entry);\n }\n } else {\n const match = pathToEntry.get(item);\n if (!match) {\n throw new Error(\n `${item} does not exist on \"input\", available: ${Object.keys(generatedEntries).join(', ')}.`,\n );\n }\n\n outputEntries.push(match);\n }\n }\n\n for (const entry of outputEntries) {\n // cannot link to groups\n if (entry.type === 'group') continue;\n const descriptionAttr = entry.info.description\n ? `description=${JSON.stringify(entry.info.description)} `\n : '';\n content.push(\n `<Card href=\"${urlFn(entry.path)}\" title=${JSON.stringify(entry.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 list of Object.values(context.generatedEntries)) {\n for (const item of list) indexEntry(item);\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 return files;\n}\n"],"mappings":";;;;;;;AA+FA,eAAsB,cAAc,SAAgC;AAClE,KAAI,QAAQ,OAAO;EACjB,MAAM,EAAE,UAAU,MAAM,OAAO;EAC/B,MAAM,aAAqB;GAAE,GAAG;GAAS,OAAO;GAAO;AAEvD,QAAM,cAAc,WAAW;EAC/B,MAAM,UAAU,QAAQ,MAAM,gBAAgB;AAC9C,UAAQ,IAAI,+BAA+B,QAAQ,KAAK,KAAK,GAAG;AAChE,QAAM,SAAS,EACb,eAAe,MAChB,CAAC,CAAC,GAAG,aAAa,cAAc,WAAW,CAAC;AAC7C;;CAGF,MAAM,QAAQ,MAAM,kBAAkB,QAAQ;AAE9C,OAAM,QAAQ,IACZ,MAAM,IAAI,OAAO,SAAS;EACxB,MAAM,WAAWA,OAAK,KAAK,QAAQ,QAAQ,KAAK,KAAK;AAErD,QAAM,MAAMA,OAAK,QAAQ,SAAS,EAAE,EAAE,WAAW,MAAM,CAAC;AACxD,QAAM,UAAU,UAAU,KAAK,QAAQ;AACvC,UAAQ,IAAI,cAAc,WAAW;GACrC,CACH;;AAGH,eAAsB,kBACpB,SACuB;CACvB,MAAM,UAAU,MAAM,QAAQ,MAAM,YAAY;CAEhD,MAAM,QAAsB,EAAE;CAC9B,MAAM,YAA0C,EAAE;CAClD,MAAM,mBAAkD,EAAE;CAE1D,MAAM,UAAU,OAAO,QAAQ,QAAQ;AACvC,KAAI,QAAQ,WAAW,EACrB,OAAM,IAAI,MAAM,wBAAwB;CAE1C,MAAM,SAAS,iBAAiB,QAAQ;AACxC,MAAK,MAAM,CAAC,IAAI,WAAW,SAAS;EAClC,MAAM,UAAU,WAAW,IAAI,QAAQ,OAAO;EAC9C,MAAM,cAA4B,EAAE;AAEpC,mBAAiB,MAAM;EACvB,SAAS,KAAK,OAAoB;AAChC,OAAI,MAAM,SAAS,SAAS;AAC1B,SAAK,MAAM,SAAS,MAAM,QAAS,MAAK,MAAM;AAC9C;;AAGF,eAAY,KAAK;IACf,MAAM,MAAM;IACZ,SAAS,OAAO,OAAO,QAAQ,QAAQ;IACxC,CAAC;;AAGJ,OAAK,MAAM,SAAS,QAAS,MAAK,MAAM;AACxC,YAAU,MAAM;AAChB,QAAM,KAAK,GAAG,YAAY;;CAG5B,MAAM,UAA8B;EAClC;EACA;EACA,WAAW;EACZ;AAED,KAAI,QAAQ,MACV,OAAM,KAAK,GAAG,gBAAgB,SAAS,QAAQ,CAAC;AAGlD,KAAI,QAAQ,KACV,OAAM,KAAK,GAAG,aAAa,SAAS,QAAQ,SAAS,OAAO,EAAE,GAAG,QAAQ,KAAK,CAAC;AAGjF,OAAM,QAAQ,aAAa,KAAK,SAAS,MAAM;AAC/C,QAAO;;AAGT,SAAS,aAAa,SAA6B,SAAoC;CACrF,MAAM,QAAsB,EAAE;CAC9B,MAAM,EAAE,aAAa,aAAa;CAElC,SAAS,KAAK,SAAwB,QAAsB;EAC1D,MAAM,QAAkB,EAAE;AAE1B,OAAK,MAAM,SAAS,SAAS;GAC3B,MAAM,eAAe,UAAU,MAC7B,SAASA,OAAK,SAAS,OAAO,MAAM,MAAM,KAAK,GAAG,MAAM,KACzD;AAED,OAAI,MAAM,SAAS,SAAS;AAC1B,SAAK,MAAM,SAAS,MAAM;AAE1B,QAAI,eAAe,SACjB,OAAM,KAAK,aAAa;QAExB,OAAM,KAAK,MAAM,MAAM,KAAK,MAAM,MAAM,MAAM,eAAe;SAG/D,OAAM,KAAK,aAAa,MAAM,GAAG,CAACA,OAAK,QAAQ,MAAM,KAAK,CAAC,OAAO,CAAC;;AAIvE,MAAI,MAAM,WAAW,EAAG;AACxB,QAAM,KAAK;GACT,MAAM,SAASA,OAAK,KAAK,OAAO,MAAM,YAAY,GAAG;GACrD,SAAS,KAAK,UACZ;IACE,OAAO,QAAQ,KAAK;IACpB,aAAa,QAAQ,KAAK;IAC1B;IACD,EACD,MACA,EACD;GACF,CAAC;;AAGJ,MAAK,MAAM,WAAW,OAAO,OAAO,QAAQ,iBAAiB,CAC3D,MAAK,QAAQ;AAGf,QAAO;;AAGT,SAAS,gBACP,SACA,SACc;CACd,MAAM,QAAsB,EAAE;CAC9B,MAAM,EAAE,qBAAqB;CAC7B,MAAM,8BAAc,IAAI,KAA0B;CAClD,MAAM,EAAE,OAAO,QAAQ,QAAQ;CAE/B,SAAS,WAAW,OAAoB;AACtC,cAAY,IAAI,UAAU,MAAM,MAAM,KAAK,EAAE,MAAM;AACnD,MAAI,MAAM,SAAS,QACjB,MAAK,MAAM,SAAS,MAAM,QACxB,YAAW,MAAM;;CAKvB,IAAI;AACJ,KAAI,OAAO,QAAQ,UAAU;EAC3B,MAAM,SAAS,aAAa,IAAI,QAAQ;AAExC,WAAS,SAAS,OAAO,SAASA,OAAK,SAAS,IAAI,YAAY,KAAK,CAAC,CAAC;OAEvE,SAAQ;CAGV,SAAS,YAAY,OAA0B;EAC7C,MAAM,UAAoB,EAAE;AAC5B,UAAQ,KAAK,UAAU;EACvB,MAAM,gBAA+B,EAAE;EACvC,MAAM,OAAO,MAAM,QAAQ,OAAO,KAAK,QAAQ,UAAU;AAEzD,OAAK,MAAM,QAAQ,KACjB,KAAI,iBAAiB,MACnB,MAAK,MAAM,SAAS,iBAAiB,MACnC,eAAc,KAAK,MAAM;OAEtB;GACL,MAAM,QAAQ,YAAY,IAAI,KAAK;AACnC,OAAI,CAAC,MACH,OAAM,IAAI,MACR,GAAG,KAAK,yCAAyC,OAAO,KAAK,iBAAiB,CAAC,KAAK,KAAK,CAAC,GAC3F;AAGH,iBAAc,KAAK,MAAM;;AAI7B,OAAK,MAAM,SAAS,eAAe;AAEjC,OAAI,MAAM,SAAS,QAAS;GAC5B,MAAM,kBAAkB,MAAM,KAAK,cAC/B,eAAe,KAAK,UAAU,MAAM,KAAK,YAAY,CAAC,KACtD;AACJ,WAAQ,KACN,eAAe,MAAM,MAAM,KAAK,CAAC,UAAU,KAAK,UAAU,MAAM,KAAK,MAAM,CAAC,GAAG,gBAAgB,IAChG;;AAGH,UAAQ,KAAK,WAAW;AACxB,SAAO,iBACL;GACE,OAAO,MAAM,SAAS;GACtB,aAAa,MAAM;GACpB,EACD,QAAQ,KAAK,KAAK,EAClB,QACD;;AAGH,MAAK,MAAM,QAAQ,OAAO,OAAO,QAAQ,iBAAiB,CACxD,MAAK,MAAM,QAAQ,KAAM,YAAW,KAAK;AAG3C,MAAK,MAAM,QAAQ,OAAO,UAAU,aAAa,MAAM,QAAQ,GAAG,MAChE,OAAM,KAAK;EACT,MAAMA,OAAK,QAAQ,KAAK,KAAK,CAAC,WAAW,IAAI,GAAG,KAAK,KAAK,QAAQ,KAAK;EACvE,SAAS,YAAY,KAAK;EAC3B,CAAC;AAGJ,QAAO"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { BrowserFetcherOptions, FetchResult } from "./fetcher.js";
|
|
2
|
-
import { SecurityEntry } from "./index.js";
|
|
3
|
-
import { ParsedSchema } from "../utils/schema/index.js";
|
|
4
2
|
import { SchemaScope } from "./schema.js";
|
|
5
|
-
import {
|
|
3
|
+
import { ProcessedDocument } from "../utils/document/process.js";
|
|
4
|
+
import { Document, HttpMethods, ParameterObject } from "../types.js";
|
|
5
|
+
import { ParsedSchema, SecurityEntry } from "../utils/schema/index.js";
|
|
6
6
|
import { ComponentProps, FC, ReactNode } from "react";
|
|
7
7
|
import * as _$react_jsx_runtime0 from "react/jsx-runtime";
|
|
8
8
|
import { Collapsible } from "fumadocs-ui/components/ui/collapsible";
|
|
@@ -18,17 +18,14 @@ interface FormValues extends Record<string, unknown> {
|
|
|
18
18
|
}
|
|
19
19
|
interface PlaygroundClientProps extends ComponentProps<'form'>, SchemaScope {
|
|
20
20
|
route: string;
|
|
21
|
-
method:
|
|
22
|
-
parameters?: ParameterObject[];
|
|
21
|
+
method: HttpMethods;
|
|
23
22
|
securities: SecurityEntry[][];
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
23
|
+
/** the OpenAPI document */
|
|
24
|
+
doc: {
|
|
25
|
+
bundled: Document;
|
|
26
|
+
} | {
|
|
27
|
+
processed: ProcessedDocument;
|
|
27
28
|
};
|
|
28
|
-
/**
|
|
29
|
-
* Resolver for $ref schemas you've passed
|
|
30
|
-
*/
|
|
31
|
-
references: Record<string, ParsedSchema>;
|
|
32
29
|
proxyUrl?: string;
|
|
33
30
|
}
|
|
34
31
|
interface ResultDisplayProps extends ComponentProps<'div'> {
|
|
@@ -68,18 +65,17 @@ interface PlaygroundClientOptions {
|
|
|
68
65
|
*
|
|
69
66
|
* @see renderParameterField for customisation tips
|
|
70
67
|
*/
|
|
71
|
-
renderBodyField?: (fieldName: 'body', info:
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
68
|
+
renderBodyField?: (fieldName: 'body', info: RequestBodyInfo) => ReactNode;
|
|
69
|
+
}
|
|
70
|
+
interface RequestBodyInfo {
|
|
71
|
+
schema: ParsedSchema;
|
|
72
|
+
mediaType: string;
|
|
75
73
|
}
|
|
76
74
|
declare function PlaygroundClient({
|
|
77
75
|
route,
|
|
78
76
|
method,
|
|
79
77
|
securities,
|
|
80
|
-
|
|
81
|
-
body,
|
|
82
|
-
references,
|
|
78
|
+
doc,
|
|
83
79
|
proxyUrl,
|
|
84
80
|
writeOnly,
|
|
85
81
|
readOnly,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","names":[],"sources":["../../src/playground/client.tsx"],"mappings":";;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"client.d.ts","names":[],"sources":["../../src/playground/client.tsx"],"mappings":";;;;;;;;;;;UA8DiB,UAAA,SAAmB,MAAA;EAClC,IAAA,EAAM,MAAA;EACN,KAAA,EAAO,MAAA;EACP,MAAA,EAAQ,MAAA;EACR,MAAA,EAAQ,MAAA;EACR,IAAA;AAAA;AAAA,UAGe,qBAAA,SAA8B,cAAA,UAAwB,WAAA;EACrE,KAAA;EACA,MAAA,EAAQ,WAAA;EACR,UAAA,EAAY,aAAA;EAX4B;EAaxC,GAAA;IAEM,OAAA,EAAS,QAAA;EAAA;IAGT,SAAA,EAAW,iBAAA;EAAA;EAEjB,QAAA;AAAA;AAAA,UAGe,kBAAA,SAA2B,cAAA;EAC1C,IAAA,EAAM,WAAA;EACN,KAAA;AAAA;AAAA,UAGe,qBAAA,SAA8B,IAAA,CAAK,cAAA,QAAsB,WAAA;EACxE,WAAA,6BAAwC,SAAA;EACxC,KAAA,EAAO,SAAA;AAAA;AAAA,UAGQ,uBAAA;EAvBP;;;EA2BR,mBAAA,IAAuB,MAAA,EAAQ,SAAA,OAAgB,SAAA;EAE/C,YAAA,GAAe,qBAAA;EA/BsD;;;;EAqCrE,cAAA;EAEA,UAAA;IACE,aAAA,GAAgB,EAAA,CAAG,kBAAA;IACnB,gBAAA,GAAmB,EAAA,CAAG,qBAAA;EAAA;EAtCZ;;;;;;;;EAiDZ,oBAAA,IAAwB,SAAA,EAAW,QAAA,EAAU,KAAA,EAAO,eAAA,KAAoB,SAAA;EArCzD;;;;;EA4Cf,eAAA,IAAmB,SAAA,UAAmB,IAAA,EAAM,eAAA,KAAoB,SAAA;AAAA;AAAA,UAGxD,eAAA;EACR,MAAA,EAAQ,YAAA;EACR,SAAA;AAAA;AAAA,iBAgBsB,gBAAA,CAAA;EACtB,KAAA;EACA,MAAA;EACA,UAAA;EACA,GAAA;EACA,QAAA;EACA,SAAA;EACA,QAAA;EAAA,GACG;AAAA,GACF,qBAAA,GAAqB,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,cA8PlB,UAAA;AAAA,KACD,SAAA,WAAoB,UAAA;AAAA,UAwGR,SAAA;EACf,SAAA,EAAW,QAAA;EACX,YAAA;EAEA,QAAA,GAAW,aAAA;EACX,QAAA,EAAU,SAAA;EAEV,SAAA,IAAa,MAAA;AAAA;AAAA,iBA8MC,oBAAA,CAAA;EAAuB,IAAA;EAAM,KAAA;EAAA,GAAU;AAAA,GAAQ,kBAAA,GAAkB,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,iBAoCjE,uBAAA,CAAA;EAA0B,KAAA;EAAO,QAAA;EAAA,GAAa;AAAA,GAAS,qBAAA,GAAqB,oBAAA,CAAA,GAAA,CAAA,OAAA;AAAA,cAc/E,MAAA;2BAEE,QAAA,EAAQ,OAAA;IAEjB,YAAA;EAAA"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { joinURL, resolveRequestData, resolveServerUrl, withBase } from "../utils/url.js";
|
|
3
|
+
import { getPreferredType } from "../utils/schema/index.js";
|
|
3
4
|
import { useStorageKey } from "../ui/client/storage-key.js";
|
|
4
5
|
import { useApiContext, useServerContext } from "../ui/contexts/api.js";
|
|
5
6
|
import { getStatusInfo } from "./status-info.js";
|
|
@@ -16,6 +17,7 @@ import { FieldInput, FieldSet, JsonInput, ObjectInput } from "./components/input
|
|
|
16
17
|
import { ClientCodeBlock } from "../ui/components/codeblock.js";
|
|
17
18
|
import { useOperationContext } from "../ui/operation/client.js";
|
|
18
19
|
import { OauthDialog, OauthDialogTrigger } from "./components/oauth-dialog.js";
|
|
20
|
+
import { dereferenceDocument } from "../utils/document/dereference.js";
|
|
19
21
|
import { Fragment, useEffect, useMemo, useRef, useState } from "react";
|
|
20
22
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
21
23
|
import { ChevronDown, LoaderCircle } from "lucide-react";
|
|
@@ -24,12 +26,24 @@ import { buttonVariants } from "fumadocs-ui/components/ui/button";
|
|
|
24
26
|
import { StfProvider, useDataEngine, useFieldValue, useListener, useStf } from "@fumari/stf";
|
|
25
27
|
import { objectGet, objectSet, stringifyFieldKey } from "@fumari/stf/lib/utils";
|
|
26
28
|
//#region src/playground/client.tsx
|
|
27
|
-
function
|
|
29
|
+
function getBodyInfo(operation) {
|
|
30
|
+
const content = operation.requestBody?.content;
|
|
31
|
+
if (!content) return;
|
|
32
|
+
const mediaType = getPreferredType(content);
|
|
33
|
+
if (mediaType) return {
|
|
34
|
+
mediaType,
|
|
35
|
+
schema: content[mediaType].schema ?? true
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
function PlaygroundClient({ route, method, securities, doc, proxyUrl, writeOnly, readOnly, ...rest }) {
|
|
28
39
|
const t = useTranslations();
|
|
40
|
+
const schema = "processed" in doc ? doc.processed : useMemo(() => dereferenceDocument(doc.bundled), [doc.bundled]);
|
|
41
|
+
const operation = schema.dereferenced.paths[route][method];
|
|
42
|
+
const body = getBodyInfo(operation);
|
|
29
43
|
const { example: exampleId, examples, setExampleData } = useOperationContext();
|
|
30
44
|
const { server } = useServerContext();
|
|
31
45
|
const storageKeys = useStorageKey();
|
|
32
|
-
const { mediaAdapters, client: { playground: { components: { ResultDisplay = DefaultResultDisplay } = {}, requestTimeout, fetchOptions = { requestTimeout }, transformAuthInputs } = {} } } = useApiContext();
|
|
46
|
+
const { mediaAdapters, client: { playground: { components: { ResultDisplay = DefaultResultDisplay, CollapsiblePanel = DefaultCollapsiblePanel } = {}, requestTimeout, fetchOptions = { requestTimeout }, transformAuthInputs, renderBodyField } = {} } } = useApiContext();
|
|
33
47
|
const [securityId, setSecurityId] = useState(() => {
|
|
34
48
|
const idx = securities.findIndex((s) => s.every((entry) => !entry.deprecated));
|
|
35
49
|
return idx === -1 ? 0 : idx;
|
|
@@ -55,7 +69,7 @@ function PlaygroundClient({ route, method = "GET", securities, parameters = [],
|
|
|
55
69
|
...mapInputs(input),
|
|
56
70
|
method,
|
|
57
71
|
bodyMediaType: body?.mediaType
|
|
58
|
-
}, mediaAdapters, parameters);
|
|
72
|
+
}, mediaAdapters, operation.parameters);
|
|
59
73
|
return fetcher.fetch(joinURL(withBase(server ? resolveServerUrl(server.url, server.variables) : "/", window.location.origin), resolveRequestData(route, encoded)), encoded);
|
|
60
74
|
});
|
|
61
75
|
const timerRef = useRef(null);
|
|
@@ -74,7 +88,7 @@ function PlaygroundClient({ route, method = "GET", securities, parameters = [],
|
|
|
74
88
|
method,
|
|
75
89
|
bodyMediaType: body?.mediaType
|
|
76
90
|
};
|
|
77
|
-
setExampleData(data, encodeRequestData(data, mediaAdapters, parameters));
|
|
91
|
+
setExampleData(data, encodeRequestData(data, mediaAdapters, operation.parameters));
|
|
78
92
|
}, timerRef.current ? 400 : 0);
|
|
79
93
|
}
|
|
80
94
|
});
|
|
@@ -88,7 +102,7 @@ function PlaygroundClient({ route, method = "GET", securities, parameters = [],
|
|
|
88
102
|
return /* @__PURE__ */ jsx(StfProvider, {
|
|
89
103
|
value: stf,
|
|
90
104
|
children: /* @__PURE__ */ jsx(SchemaProvider, {
|
|
91
|
-
|
|
105
|
+
schema,
|
|
92
106
|
writeOnly,
|
|
93
107
|
readOnly,
|
|
94
108
|
children: /* @__PURE__ */ jsxs("form", {
|
|
@@ -129,9 +143,11 @@ function PlaygroundClient({ route, method = "GET", securities, parameters = [],
|
|
|
129
143
|
setSecurityId,
|
|
130
144
|
children: inputs.map((input) => /* @__PURE__ */ jsx(Fragment, { children: input.children }, stringifyFieldKey(input.fieldName)))
|
|
131
145
|
}),
|
|
132
|
-
/* @__PURE__ */ jsx(
|
|
133
|
-
|
|
134
|
-
|
|
146
|
+
/* @__PURE__ */ jsx(ParametersForm, { parameters: operation.parameters }),
|
|
147
|
+
body && /* @__PURE__ */ jsx(CollapsiblePanel, {
|
|
148
|
+
"data-type": "body",
|
|
149
|
+
title: t.body,
|
|
150
|
+
children: renderBodyField ? renderBodyField("body", body) : /* @__PURE__ */ jsx(BodyInput, { field: body.schema })
|
|
135
151
|
})
|
|
136
152
|
]
|
|
137
153
|
})
|
|
@@ -189,7 +205,7 @@ const ParamTypes = [
|
|
|
189
205
|
"cookie",
|
|
190
206
|
"query"
|
|
191
207
|
];
|
|
192
|
-
function
|
|
208
|
+
function ParameterItem({ type, parameters }) {
|
|
193
209
|
const { renderParameterField } = useApiContext().client.playground ?? {};
|
|
194
210
|
return parameters.map((field) => {
|
|
195
211
|
const fieldName = [type, field.name];
|
|
@@ -204,8 +220,8 @@ function FormBodyItem({ type, parameters }) {
|
|
|
204
220
|
}, stringifyFieldKey(fieldName));
|
|
205
221
|
});
|
|
206
222
|
}
|
|
207
|
-
function
|
|
208
|
-
const {
|
|
223
|
+
function ParametersForm({ parameters = [] }) {
|
|
224
|
+
const { components: { CollapsiblePanel = DefaultCollapsiblePanel } = {} } = useApiContext().client.playground ?? {};
|
|
209
225
|
const t = useTranslations();
|
|
210
226
|
const displayNames = {
|
|
211
227
|
header: t.header,
|
|
@@ -213,22 +229,18 @@ function FormBody({ parameters = [], body }) {
|
|
|
213
229
|
query: t.query,
|
|
214
230
|
path: t.path
|
|
215
231
|
};
|
|
216
|
-
return
|
|
232
|
+
return ParamTypes.map((type) => {
|
|
217
233
|
const items = parameters.filter((v) => v.in === type);
|
|
218
234
|
if (items.length === 0) return;
|
|
219
235
|
return /* @__PURE__ */ jsx(CollapsiblePanel, {
|
|
220
236
|
"data-type": type,
|
|
221
237
|
title: displayNames[type],
|
|
222
|
-
children: /* @__PURE__ */ jsx(
|
|
238
|
+
children: /* @__PURE__ */ jsx(ParameterItem, {
|
|
223
239
|
parameters: items,
|
|
224
240
|
type
|
|
225
241
|
})
|
|
226
242
|
}, type);
|
|
227
|
-
})
|
|
228
|
-
"data-type": "body",
|
|
229
|
-
title: t.body,
|
|
230
|
-
children: renderBodyField ? renderBodyField("body", body) : /* @__PURE__ */ jsx(BodyInput, { field: body.schema })
|
|
231
|
-
})] });
|
|
243
|
+
});
|
|
232
244
|
}
|
|
233
245
|
function BodyInput({ field: _field }) {
|
|
234
246
|
const field = useResolvedSchema(_field);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","names":[],"sources":["../../src/playground/client.tsx"],"sourcesContent":["'use client';\nimport {\n type FC,\n Fragment,\n type ReactNode,\n useEffect,\n useMemo,\n useState,\n type ComponentProps,\n useRef,\n} from 'react';\nimport { useApiContext, useServerContext } from '@/ui/contexts/api';\nimport type { BrowserFetcherOptions, FetchResult } from '@/playground/fetcher';\nimport type { SecurityEntry } from '@/playground/index';\nimport { getStatusInfo } from './status-info';\nimport { joinURL, resolveRequestData, resolveServerUrl, withBase } from '@/utils/url';\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 { 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 { anyFields, 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 {\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';\nimport type { ParameterObject } from '@/types';\nimport { ClientCodeBlock } from '@/ui/components/codeblock';\nimport { useTranslations } from '@/ui/client/i18n';\nimport { useOperationContext } from '@/ui/operation/client';\nimport { OauthDialog, OauthDialogTrigger } from './components/oauth-dialog';\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?: ParameterObject[];\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 ResultDisplayProps extends ComponentProps<'div'> {\n data: FetchResult;\n reset: () => void;\n}\n\nexport interface CollapsiblePanelProps extends Omit<ComponentProps<typeof Collapsible>, 'title'> {\n 'data-type': 'authorization' | 'body' | ParamType;\n title: ReactNode;\n}\n\nexport interface PlaygroundClientOptions {\n /**\n * transform fields for auth-specific parameters (e.g. header)\n */\n transformAuthInputs?: (fields: AuthField[]) => AuthField[];\n\n fetchOptions?: BrowserFetcherOptions;\n\n /**\n * Request timeout in seconds (default: 10s)\n * @deprecated use `fetchOptions.requestTimeout` instead.\n */\n requestTimeout?: number;\n\n components?: {\n ResultDisplay?: FC<ResultDisplayProps>;\n CollapsiblePanel?: FC<CollapsiblePanelProps>;\n };\n\n /**\n * render the parameter 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: ParameterObject) => 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\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 t = useTranslations();\n const { example: exampleId, examples, setExampleData } = useOperationContext();\n const { server } = useServerContext();\n const storageKeys = useStorageKey();\n const {\n mediaAdapters,\n client: {\n playground: {\n components: { ResultDisplay = DefaultResultDisplay } = {},\n requestTimeout,\n fetchOptions = { requestTimeout },\n transformAuthInputs,\n } = {},\n },\n } = useApiContext();\n const [securityId, setSecurityId] = useState(() => {\n const idx = securities.findIndex((s) => s.every((entry) => !entry.deprecated));\n return idx === -1 ? 0 : idx;\n });\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 fetcher = await import('./fetcher').then((mod) =>\n mod.createBrowserFetcher(mediaAdapters, { proxyUrl, ...fetchOptions }),\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 server ? resolveServerUrl(server.url, server.variables) : '/',\n window.location.origin,\n ),\n resolveRequestData(route, encoded),\n ),\n encoded,\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 // same object reference = unchanged\n if (stf.dataEngine.getData() === defaultValues) return;\n\n stf.dataEngine.reset(defaultValues);\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 className=\"border-b\" />\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\" /> : t.send}\n </button>\n </div>\n {testQuery.data ? <ResultDisplay data={testQuery.data} reset={testQuery.reset} /> : null}\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 </form>\n </SchemaProvider>\n </StfProvider>\n );\n}\n\nfunction SecurityTabsSelectItem({ security }: { security: SecurityEntry[] }) {\n return (\n <div className=\"flex flex-col gap-2 max-w-[600px]\">\n {security.map((item) => (\n <div key={item.id}>\n <p\n className={cn(\n 'font-mono font-medium',\n item.deprecated && 'text-fd-muted-foreground line-through',\n )}\n >\n {item.id}\n </p>\n <p className=\"text-fd-muted-foreground whitespace-pre-wrap\">{item.description}</p>\n </div>\n ))}\n </div>\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 const t = useTranslations();\n const { CollapsiblePanel = DefaultCollapsiblePanel } =\n useApiContext().client.playground?.components ?? {};\n\n const result = (\n <CollapsiblePanel title={t.authorization} data-type=\"authorization\">\n <Select value={securityId.toString()} onValueChange={(v) => setSecurityId(Number(v))}>\n <SelectTrigger>\n <SelectValue>\n <SecurityTabsSelectItem security={securities[securityId]} />\n </SelectValue>\n </SelectTrigger>\n <SelectContent>\n {securities.map((security, i) => (\n <SelectItem key={i} value={i.toString()}>\n <SecurityTabsSelectItem security={security} />\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;\ntype ParamType = (typeof ParamTypes)[number];\n\nfunction FormBodyItem({ type, parameters }: { type: ParamType; parameters: ParameterObject[] }) {\n const { renderParameterField } = useApiContext().client.playground ?? {};\n\n return parameters.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\n return (\n <FieldSet\n key={stringifyFieldKey(fieldName)}\n name={field.name}\n fieldName={fieldName}\n field={(schema ?? anyFields) as ParsedSchema}\n isRequired={field.required}\n />\n );\n });\n}\n\nfunction FormBody({ parameters = [], body }: Pick<PlaygroundClientProps, 'parameters' | 'body'>) {\n const { renderBodyField, components: { CollapsiblePanel = DefaultCollapsiblePanel } = {} } =\n useApiContext().client.playground ?? {};\n const t = useTranslations();\n const displayNames = {\n header: t.header,\n cookie: t.cookies,\n query: t.query,\n path: t.path,\n };\n\n return (\n <>\n {ParamTypes.map((type) => {\n const items = parameters.filter((v) => v.in === type);\n if (items.length === 0) return;\n\n return (\n <CollapsiblePanel key={type} data-type={type} title={displayNames[type]}>\n <FormBodyItem parameters={items} type={type} />\n </CollapsiblePanel>\n );\n })}\n {body && (\n <CollapsiblePanel data-type=\"body\" title={t.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 const t = useTranslations();\n\n if (field.format === 'binary') return <FieldSet field={field} fieldName={['body']} isRequired />;\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 {t.closeJsonEditor}\n </button>\n <JsonInput fieldName={['body']} />\n </>\n );\n\n return (\n <FieldSet\n field={field}\n fieldName={['body']}\n collapsible={false}\n isRequired\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 {t.openJsonEditor}\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 t = useTranslations();\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 const obj = out as Record<string, unknown>;\n return `Basic ${btoa(`${obj.username ?? ''}:${obj.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 }}\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 {t.accessToken}\n </label>\n <div className=\"flex gap-2\">\n <FieldInput\n fieldName={fieldName}\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 {t.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={`${t.authorization} (${t.header})`}\n fieldName={fieldName}\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 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={`${t.authorization} (${t.header})`}\n fieldName={fieldName}\n field={{\n type: 'string',\n }}\n />\n <p className=\"text-fd-muted-foreground text-xs\">{t.openIdUnsupported}</p>\n </>\n ),\n });\n }\n }\n\n return transform ? transform(result) : result;\n }, [securities, transform, t]);\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\nexport function DefaultResultDisplay({ data, reset, ...rest }: ResultDisplayProps) {\n const t = useTranslations();\n const statusInfo = useMemo(() => getStatusInfo(data.status, t), [data.status, t]);\n\n return (\n <div\n {...rest}\n className={cn(\n 'flex flex-col gap-3 mt-2 px-3 py-2 border-y bg-fd-secondary text-fd-secondary-foreground',\n rest.className,\n )}\n >\n <div className=\"flex justify-between items-center\">\n <div className=\"inline-flex items-center gap-1.5 text-sm font-medium\">\n <statusInfo.icon className={cn('size-4', statusInfo.color)} />\n {statusInfo.description}\n </div>\n <button\n type=\"button\"\n className={cn(buttonVariants({ size: 'sm', variant: 'outline' }))}\n onClick={() => reset()}\n >\n {t.close}\n </button>\n </div>\n <p className=\"text-sm text-fd-muted-foreground\">{data.status}</p>\n {data.data !== undefined && (\n <ClientCodeBlock\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 />\n )}\n </div>\n );\n}\n\nexport function DefaultCollapsiblePanel({ title, children, ...props }: CollapsiblePanelProps) {\n return (\n <Collapsible {...props} className={cn('border-b last:border-b-0', props.className)}>\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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"}
|
|
1
|
+
{"version":3,"file":"client.js","names":[],"sources":["../../src/playground/client.tsx"],"sourcesContent":["'use client';\nimport {\n type FC,\n Fragment,\n type ReactNode,\n useEffect,\n useMemo,\n useState,\n type ComponentProps,\n useRef,\n} from 'react';\nimport { useApiContext, useServerContext } from '@/ui/contexts/api';\nimport type { BrowserFetcherOptions, FetchResult } from '@/playground/fetcher';\nimport { getStatusInfo } from './status-info';\nimport { joinURL, resolveRequestData, resolveServerUrl, withBase } from '@/utils/url';\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 { 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 { anyFields, 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 {\n getPreferredType,\n type SecurityEntry,\n type NoReference,\n type ParsedSchema,\n} from '@/utils/schema';\nimport ServerSelect from './components/server-select';\nimport { useStorageKey } from '@/ui/client/storage-key';\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';\nimport type { Document, HttpMethods, OperationObject, ParameterObject } from '@/types';\nimport { ClientCodeBlock } from '@/ui/components/codeblock';\nimport { useTranslations } from '@/ui/client/i18n';\nimport { useOperationContext } from '@/ui/operation/client';\nimport { OauthDialog, OauthDialogTrigger } from './components/oauth-dialog';\nimport { dereferenceDocument } from '@/utils/document/dereference';\nimport type { ProcessedDocument } from '@/utils/document/process';\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: HttpMethods;\n securities: SecurityEntry[][];\n /** the OpenAPI document */\n doc:\n | {\n bundled: Document;\n }\n | {\n processed: ProcessedDocument;\n };\n proxyUrl?: string;\n}\n\nexport interface ResultDisplayProps extends ComponentProps<'div'> {\n data: FetchResult;\n reset: () => void;\n}\n\nexport interface CollapsiblePanelProps extends Omit<ComponentProps<typeof Collapsible>, 'title'> {\n 'data-type': 'authorization' | 'body' | ParamType;\n title: ReactNode;\n}\n\nexport interface PlaygroundClientOptions {\n /**\n * transform fields for auth-specific parameters (e.g. header)\n */\n transformAuthInputs?: (fields: AuthField[]) => AuthField[];\n\n fetchOptions?: BrowserFetcherOptions;\n\n /**\n * Request timeout in seconds (default: 10s)\n * @deprecated use `fetchOptions.requestTimeout` instead.\n */\n requestTimeout?: number;\n\n components?: {\n ResultDisplay?: FC<ResultDisplayProps>;\n CollapsiblePanel?: FC<CollapsiblePanelProps>;\n };\n\n /**\n * render the parameter 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: ParameterObject) => ReactNode;\n\n /**\n * render the input for API endpoint body.\n *\n * @see renderParameterField for customisation tips\n */\n renderBodyField?: (fieldName: 'body', info: RequestBodyInfo) => ReactNode;\n}\n\ninterface RequestBodyInfo {\n schema: ParsedSchema;\n mediaType: string;\n}\n\nfunction getBodyInfo(operation: NoReference<OperationObject>): RequestBodyInfo | undefined {\n const content = operation.requestBody?.content;\n if (!content) return;\n const mediaType = getPreferredType(content);\n\n if (mediaType) {\n return {\n mediaType,\n schema: content[mediaType].schema ?? true,\n };\n }\n}\n\nexport default function PlaygroundClient({\n route,\n method,\n securities,\n doc,\n proxyUrl,\n writeOnly,\n readOnly,\n ...rest\n}: PlaygroundClientProps) {\n const t = useTranslations();\n const schema =\n 'processed' in doc\n ? doc.processed\n : // oxlint-disable-next-line eslint-plugin-react-hooks/rules-of-hooks -- assume unchanged\n useMemo(() => dereferenceDocument(doc.bundled), [doc.bundled]);\n const operation: NoReference<OperationObject> = schema.dereferenced.paths![route]![method]!;\n const body = getBodyInfo(operation);\n\n const { example: exampleId, examples, setExampleData } = useOperationContext();\n const { server } = useServerContext();\n const storageKeys = useStorageKey();\n const {\n mediaAdapters,\n client: {\n playground: {\n components: {\n ResultDisplay = DefaultResultDisplay,\n CollapsiblePanel = DefaultCollapsiblePanel,\n } = {},\n requestTimeout,\n fetchOptions = { requestTimeout },\n transformAuthInputs,\n renderBodyField,\n } = {},\n },\n } = useApiContext();\n const [securityId, setSecurityId] = useState(() => {\n const idx = securities.findIndex((s) => s.every((entry) => !entry.deprecated));\n return idx === -1 ? 0 : idx;\n });\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 fetcher = await import('./fetcher').then((mod) =>\n mod.createBrowserFetcher(mediaAdapters, { proxyUrl, ...fetchOptions }),\n );\n\n const encoded = encodeRequestData(\n { ...mapInputs(input), method, bodyMediaType: body?.mediaType },\n mediaAdapters,\n operation.parameters,\n );\n return fetcher.fetch(\n joinURL(\n withBase(\n server ? resolveServerUrl(server.url, server.variables) : '/',\n window.location.origin,\n ),\n resolveRequestData(route, encoded),\n ),\n encoded,\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, operation.parameters));\n },\n timerRef.current ? 400 : 0,\n );\n },\n });\n\n useEffect(() => {\n // same object reference = unchanged\n if (stf.dataEngine.getData() === defaultValues) return;\n\n stf.dataEngine.reset(defaultValues);\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 schema={schema} 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 className=\"border-b\" />\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\" /> : t.send}\n </button>\n </div>\n {testQuery.data ? <ResultDisplay data={testQuery.data} reset={testQuery.reset} /> : null}\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 <ParametersForm parameters={operation.parameters} />\n {body && (\n <CollapsiblePanel data-type=\"body\" title={t.body}>\n {renderBodyField ? renderBodyField('body', body) : <BodyInput field={body.schema} />}\n </CollapsiblePanel>\n )}\n </form>\n </SchemaProvider>\n </StfProvider>\n );\n}\n\nfunction SecurityTabsSelectItem({ security }: { security: SecurityEntry[] }) {\n return (\n <div className=\"flex flex-col gap-2 max-w-[600px]\">\n {security.map((item) => (\n <div key={item.id}>\n <p\n className={cn(\n 'font-mono font-medium',\n item.deprecated && 'text-fd-muted-foreground line-through',\n )}\n >\n {item.id}\n </p>\n <p className=\"text-fd-muted-foreground whitespace-pre-wrap\">{item.description}</p>\n </div>\n ))}\n </div>\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 const t = useTranslations();\n const { CollapsiblePanel = DefaultCollapsiblePanel } =\n useApiContext().client.playground?.components ?? {};\n\n const result = (\n <CollapsiblePanel title={t.authorization} data-type=\"authorization\">\n <Select value={securityId.toString()} onValueChange={(v) => setSecurityId(Number(v))}>\n <SelectTrigger>\n <SelectValue>\n <SecurityTabsSelectItem security={securities[securityId]} />\n </SelectValue>\n </SelectTrigger>\n <SelectContent>\n {securities.map((security, i) => (\n <SelectItem key={i} value={i.toString()}>\n <SecurityTabsSelectItem security={security} />\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;\ntype ParamType = (typeof ParamTypes)[number];\n\nfunction ParameterItem({ type, parameters }: { type: ParamType; parameters: ParameterObject[] }) {\n const { renderParameterField } = useApiContext().client.playground ?? {};\n\n return parameters.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\n return (\n <FieldSet\n key={stringifyFieldKey(fieldName)}\n name={field.name}\n fieldName={fieldName}\n field={(schema ?? anyFields) as ParsedSchema}\n isRequired={field.required}\n />\n );\n });\n}\n\nfunction ParametersForm({ parameters = [] }: { parameters?: ParameterObject[] }) {\n const { components: { CollapsiblePanel = DefaultCollapsiblePanel } = {} } =\n useApiContext().client.playground ?? {};\n const t = useTranslations();\n const displayNames = {\n header: t.header,\n cookie: t.cookies,\n query: t.query,\n path: t.path,\n };\n\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 key={type} data-type={type} title={displayNames[type]}>\n <ParameterItem parameters={items} type={type} />\n </CollapsiblePanel>\n );\n });\n}\n\nfunction BodyInput({ field: _field }: { field: ParsedSchema }) {\n const field = useResolvedSchema(_field);\n const [isJson, setIsJson] = useState(false);\n const t = useTranslations();\n\n if (field.format === 'binary') return <FieldSet field={field} fieldName={['body']} isRequired />;\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 {t.closeJsonEditor}\n </button>\n <JsonInput fieldName={['body']} />\n </>\n );\n\n return (\n <FieldSet\n field={field}\n fieldName={['body']}\n collapsible={false}\n isRequired\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 {t.openJsonEditor}\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 t = useTranslations();\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 const obj = out as Record<string, unknown>;\n return `Basic ${btoa(`${obj.username ?? ''}:${obj.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 }}\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 {t.accessToken}\n </label>\n <div className=\"flex gap-2\">\n <FieldInput\n fieldName={fieldName}\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 {t.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={`${t.authorization} (${t.header})`}\n fieldName={fieldName}\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 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={`${t.authorization} (${t.header})`}\n fieldName={fieldName}\n field={{\n type: 'string',\n }}\n />\n <p className=\"text-fd-muted-foreground text-xs\">{t.openIdUnsupported}</p>\n </>\n ),\n });\n }\n }\n\n return transform ? transform(result) : result;\n }, [securities, transform, t]);\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\nexport function DefaultResultDisplay({ data, reset, ...rest }: ResultDisplayProps) {\n const t = useTranslations();\n const statusInfo = useMemo(() => getStatusInfo(data.status, t), [data.status, t]);\n\n return (\n <div\n {...rest}\n className={cn(\n 'flex flex-col gap-3 mt-2 px-3 py-2 border-y bg-fd-secondary text-fd-secondary-foreground',\n rest.className,\n )}\n >\n <div className=\"flex justify-between items-center\">\n <div className=\"inline-flex items-center gap-1.5 text-sm font-medium\">\n <statusInfo.icon className={cn('size-4', statusInfo.color)} />\n {statusInfo.description}\n </div>\n <button\n type=\"button\"\n className={cn(buttonVariants({ size: 'sm', variant: 'outline' }))}\n onClick={() => reset()}\n >\n {t.close}\n </button>\n </div>\n <p className=\"text-sm text-fd-muted-foreground\">{data.status}</p>\n {data.data !== undefined && (\n <ClientCodeBlock\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 />\n )}\n </div>\n );\n}\n\nexport function DefaultCollapsiblePanel({ title, children, ...props }: CollapsiblePanelProps) {\n return (\n <Collapsible {...props} className={cn('border-b last:border-b-0', props.className)}>\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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"}
|