fumadocs-openapi 8.1.3 → 8.1.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.
Files changed (47) hide show
  1. package/dist/generate-file.d.ts.map +1 -1
  2. package/dist/generate-file.js +40 -23
  3. package/dist/playground/client.d.ts +5 -16
  4. package/dist/playground/client.d.ts.map +1 -1
  5. package/dist/playground/client.js +39 -44
  6. package/dist/playground/get-default-values.d.ts +2 -2
  7. package/dist/playground/get-default-values.d.ts.map +1 -1
  8. package/dist/playground/get-default-values.js +21 -22
  9. package/dist/playground/index.d.ts +4 -38
  10. package/dist/playground/index.d.ts.map +1 -1
  11. package/dist/playground/index.js +43 -139
  12. package/dist/playground/inputs.d.ts +11 -13
  13. package/dist/playground/inputs.d.ts.map +1 -1
  14. package/dist/playground/inputs.js +72 -129
  15. package/dist/playground/schema.d.ts +38 -0
  16. package/dist/playground/schema.d.ts.map +1 -0
  17. package/dist/playground/schema.js +93 -0
  18. package/dist/render/operation/get-request-data.d.ts +1 -2
  19. package/dist/render/operation/get-request-data.d.ts.map +1 -1
  20. package/dist/render/operation/get-request-data.js +2 -2
  21. package/dist/render/operation/index.d.ts.map +1 -1
  22. package/dist/render/operation/index.js +5 -5
  23. package/dist/render/schema.d.ts +3 -3
  24. package/dist/render/schema.d.ts.map +1 -1
  25. package/dist/render/schema.js +70 -100
  26. package/dist/ui/client.d.ts +3 -0
  27. package/dist/ui/client.d.ts.map +1 -1
  28. package/dist/ui/client.js +15 -0
  29. package/dist/ui/components/dialog.d.ts.map +1 -1
  30. package/dist/ui/components/dialog.js +4 -3
  31. package/dist/ui/components/select.js +1 -1
  32. package/dist/ui/index.js +1 -1
  33. package/dist/ui/server-select.d.ts +2 -7
  34. package/dist/ui/server-select.d.ts.map +1 -1
  35. package/dist/ui/server-select.js +52 -19
  36. package/dist/utils/combine-schema.d.ts.map +1 -1
  37. package/dist/utils/combine-schema.js +12 -2
  38. package/dist/utils/schema-to-string.d.ts +3 -0
  39. package/dist/utils/schema-to-string.d.ts.map +1 -0
  40. package/dist/utils/schema-to-string.js +62 -0
  41. package/dist/utils/schema.d.ts +9 -4
  42. package/dist/utils/schema.d.ts.map +1 -1
  43. package/dist/utils/schema.js +2 -0
  44. package/package.json +6 -5
  45. package/dist/playground/resolve.d.ts +0 -6
  46. package/dist/playground/resolve.d.ts.map +0 -1
  47. package/dist/playground/resolve.js +0 -14
@@ -1 +1 @@
1
- {"version":3,"file":"generate-file.d.ts","sourceRoot":"","sources":["../src/generate-file.ts"],"names":[],"mappings":"AAGA,OAAO,EAEL,KAAK,eAAe,EAIrB,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,MAAO,SAAQ,eAAe;IAC7C;;OAEG;IACH,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC;IAEzB;;OAEG;IACH,MAAM,EAAE,MAAM,CAAC;IAEf;;;;;;OAMG;IACH,GAAG,CAAC,EAAE,KAAK,GAAG,MAAM,GAAG,WAAW,CAAC;IAEnC;;OAEG;IACH,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,KAAK,EAAE,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IAEtD;;;;;OAKG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IAExB;;;;OAIG;IACH,OAAO,CAAC,EAAE,KAAK,GAAG,OAAO,GAAG,MAAM,CAAC;CACpC;AAED,wBAAsB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA+HlE"}
1
+ {"version":3,"file":"generate-file.d.ts","sourceRoot":"","sources":["../src/generate-file.ts"],"names":[],"mappings":"AAGA,OAAO,EAEL,KAAK,eAAe,EAIrB,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,MAAO,SAAQ,eAAe;IAC7C;;OAEG;IACH,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC;IAEzB;;OAEG;IACH,MAAM,EAAE,MAAM,CAAC;IAEf;;;;;;OAMG;IACH,GAAG,CAAC,EAAE,KAAK,GAAG,MAAM,GAAG,WAAW,CAAC;IAEnC;;OAEG;IACH,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,KAAK,EAAE,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IAEtD;;;;;OAKG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IAExB;;;;OAIG;IACH,OAAO,CAAC,EAAE,KAAK,GAAG,OAAO,GAAG,MAAM,CAAC;CACpC;AAED,wBAAsB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAmJlE"}
@@ -1,10 +1,9 @@
1
1
  import { mkdir, writeFile } from 'node:fs/promises';
2
- import { dirname, join, parse } from 'node:path';
2
+ import * as path from 'node:path';
3
3
  import fg from 'fast-glob';
4
4
  import { generateAll, generatePages, generateTags, } from './generate.js';
5
5
  export async function generateFiles(options) {
6
6
  const { input, output, name: nameFn, per = 'operation', groupBy = 'none', cwd = process.cwd(), } = options;
7
- const outputDir = join(cwd, output);
8
7
  const urlInputs = [];
9
8
  const fileInputs = [];
10
9
  for (const v of typeof input === 'string' ? [input] : input) {
@@ -28,7 +27,7 @@ export async function generateFiles(options) {
28
27
  file = getFilename(result.pathItem.summary);
29
28
  }
30
29
  else if (result.type === 'operation') {
31
- file = join(getOutputPathFromRoute(result.item.path), result.item.method.toLowerCase());
30
+ file = path.join(getOutputPathFromRoute(result.item.path), result.item.method.toLowerCase());
32
31
  }
33
32
  else {
34
33
  file = getFilename(result.item.name);
@@ -41,11 +40,11 @@ export async function generateFiles(options) {
41
40
  tags = ['unknown'];
42
41
  }
43
42
  for (const tag of tags) {
44
- outPaths.push(join(outputDir, getFilename(tag), `${file}.mdx`));
43
+ outPaths.push(path.join(getFilename(tag), `${file}.mdx`));
45
44
  }
46
45
  }
47
46
  else {
48
- outPaths.push(join(outputDir, `${file}.mdx`));
47
+ outPaths.push(`${file}.mdx`);
49
48
  }
50
49
  return outPaths;
51
50
  }
@@ -58,28 +57,41 @@ export async function generateFiles(options) {
58
57
  console.log(`Generated Meta: ${file}`);
59
58
  }
60
59
  async function generateFromDocument(pathOrUrl) {
60
+ const outputDir = path.join(cwd, output);
61
61
  if (per === 'file') {
62
- let filename = isUrl(pathOrUrl) ? 'index' : parse(pathOrUrl).name;
62
+ let filename = isUrl(pathOrUrl)
63
+ ? 'index'
64
+ : path.basename(pathOrUrl, path.extname(pathOrUrl));
63
65
  if (nameFn)
64
66
  filename = nameFn('file', filename);
65
- const outPath = join(outputDir, `${filename}.mdx`);
67
+ const outPath = path.join(outputDir, `${filename}.mdx`);
66
68
  const result = await generateAll(pathOrUrl, options);
67
69
  await write(outPath, result);
68
70
  console.log(`Generated: ${outPath}`);
69
71
  }
70
72
  if (per === 'operation') {
71
73
  const results = await generatePages(pathOrUrl, options);
74
+ const mapping = new Map();
72
75
  for (const result of results) {
73
76
  const outputPaths = getOutputPaths(result);
74
- await Promise.all(outputPaths.map(async (outPath) => {
75
- await write(outPath, result.content);
76
- if (groupBy === 'route' && result.pathItem.summary) {
77
- await writeMetafile(join(dirname(outPath), 'meta.json'), {
78
- title: result.pathItem.summary,
79
- });
80
- }
81
- }));
82
- console.log(`Generated: ${outputPaths.join(', ')}`);
77
+ for (const outputPath of outputPaths) {
78
+ mapping.set(outputPath, result);
79
+ }
80
+ }
81
+ for (const [key, output] of mapping.entries()) {
82
+ let outputPath = key;
83
+ const isSharedDir = Array.from(mapping.keys()).some((item) => item !== outputPath &&
84
+ path.dirname(item) === path.dirname(outputPath));
85
+ if (!isSharedDir && path.dirname(outputPath).length > 0) {
86
+ outputPath = path.join(path.dirname(outputPath) + '.mdx');
87
+ }
88
+ await write(path.join(outputDir, outputPath), output.content);
89
+ if (groupBy === 'route' && output.pathItem.summary) {
90
+ await writeMetafile(path.join(outputDir, path.dirname(outputPath), 'meta.json'), {
91
+ title: output.pathItem.summary,
92
+ });
93
+ }
94
+ console.log(`Generated: ${outputPath}`);
83
95
  }
84
96
  }
85
97
  if (per === 'tag') {
@@ -87,7 +99,7 @@ export async function generateFiles(options) {
87
99
  for (const result of results) {
88
100
  let tagName = result.tag;
89
101
  tagName = nameFn?.('tag', tagName) ?? getFilename(tagName);
90
- const outPath = join(outputDir, `${tagName}.mdx`);
102
+ const outPath = path.join(outputDir, `${tagName}.mdx`);
91
103
  await write(outPath, result.content);
92
104
  console.log(`Generated: ${outPath}`);
93
105
  }
@@ -100,15 +112,20 @@ function isUrl(input) {
100
112
  }
101
113
  function getOutputPathFromRoute(path) {
102
114
  return (path
103
- .replaceAll('.', '/')
115
+ .toLowerCase()
116
+ .replaceAll('.', '-')
104
117
  .split('/')
105
- .filter((v) => !v.startsWith('{') && !v.endsWith('}'))
106
- .at(-1) ?? '');
118
+ .map((v) => {
119
+ if (v.startsWith('{') && v.endsWith('}'))
120
+ return v.slice(1, -1);
121
+ return v;
122
+ })
123
+ .join('/') ?? '');
107
124
  }
108
125
  function getFilename(s) {
109
126
  return s.replace(/\s+/g, '-').toLowerCase();
110
127
  }
111
- async function write(path, content) {
112
- await mkdir(dirname(path), { recursive: true });
113
- await writeFile(path, content);
128
+ async function write(file, content) {
129
+ await mkdir(path.dirname(file), { recursive: true });
130
+ await writeFile(file, content);
114
131
  }
@@ -1,7 +1,7 @@
1
- import { type FC, type HTMLAttributes, type ReactElement, type RefObject } from 'react';
1
+ import { type FC, type HTMLAttributes, type ReactElement } from 'react';
2
2
  import type { ControllerFieldState, ControllerRenderProps, FieldPath, UseFormStateReturn } from 'react-hook-form';
3
3
  import type { FetchResult } from '../playground/fetcher.js';
4
- import type { ParameterField, ReferenceSchema, RequestSchema } from '../playground/index.js';
4
+ import type { ParameterField, RequestSchema } from '../playground/index.js';
5
5
  import type { Security } from '../utils/get-security.js';
6
6
  interface FormValues {
7
7
  authorization: string | {
@@ -32,11 +32,12 @@ export type ClientProps = HTMLAttributes<HTMLFormElement> & {
32
32
  persistentId: string;
33
33
  };
34
34
  parameters?: ParameterField[];
35
- body?: RequestSchema & {
35
+ body?: {
36
+ schema: RequestSchema;
36
37
  mediaType: string;
37
38
  };
38
39
  /**
39
- * Resolver for reference schemas you've passed
40
+ * Resolver for $ref schemas you've passed
40
41
  */
41
42
  references: Record<string, RequestSchema>;
42
43
  proxyUrl?: string;
@@ -51,18 +52,6 @@ export type ClientProps = HTMLAttributes<HTMLFormElement> & {
51
52
  }>;
52
53
  }>;
53
54
  };
54
- interface SchemaContextType {
55
- references: Record<string, RequestSchema>;
56
- dynamic: RefObject<Map<string, DynamicField>>;
57
- }
58
- export type DynamicField = {
59
- type: 'object';
60
- properties: string[];
61
- } | {
62
- type: 'field';
63
- schema: RequestSchema | ReferenceSchema;
64
- };
65
- export declare function useSchemaContext(): SchemaContextType;
66
55
  export default function Client({ route, method, authorization, parameters, body, fields, references, proxyUrl, components: { ResultDisplay }, ...rest }: ClientProps): import("react/jsx-runtime").JSX.Element;
67
56
  export {};
68
57
  //# sourceMappingURL=client.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/playground/client.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/playground/client.tsx"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,EAAE,EAEP,KAAK,cAAc,EAEnB,KAAK,YAAY,EAKlB,MAAM,OAAO,CAAC;AACf,OAAO,KAAK,EACV,oBAAoB,EACpB,qBAAqB,EACrB,SAAS,EACT,kBAAkB,EACnB,MAAM,iBAAiB,CAAC;AAQzB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAExD,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAYxE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAYrD,UAAU,UAAU;IAClB,aAAa,EACT,MAAM,GACN;QACE,QAAQ,EAAE,MAAM,CAAC;QACjB,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC;IACN,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,IAAI,EAAE,OAAO,CAAC;CACf;AAED,MAAM,WAAW,WAAW,CAAC,KAAK,SAAS,SAAS,CAAC,UAAU,CAAC,EAAE,IAAI;IACpE,MAAM,EAAE,CAAC,KAAK,EAAE;QACd;;WAEG;QACH,IAAI,EAAE,IAAI,CAAC;QACX,KAAK,EAAE,qBAAqB,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;QAChD,UAAU,EAAE,oBAAoB,CAAC;QACjC,SAAS,EAAE,kBAAkB,CAAC,UAAU,CAAC,CAAC;KAC3C,KAAK,YAAY,CAAC;CACpB;AAED,MAAM,MAAM,WAAW,GAAG,cAAc,CAAC,eAAe,CAAC,GAAG;IAC1D,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,CAAC,EAAE,QAAQ,GAAG;QACzB,YAAY,EAAE,MAAM,CAAC;KACtB,CAAC;IACF,UAAU,CAAC,EAAE,cAAc,EAAE,CAAC;IAC9B,IAAI,CAAC,EAAE;QACL,MAAM,EAAE,aAAa,CAAC;QACtB,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;IACF;;OAEG;IACH,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IAC1C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,MAAM,CAAC,EAAE;QACP,SAAS,CAAC,EAAE,WAAW,CACrB,GAAG,cAAc,CAAC,IAAI,CAAC,IAAI,MAAM,EAAE,EACnC,cAAc,CACf,CAAC;QACF,IAAI,CAAC,EAAE,WAAW,CAAC,eAAe,EAAE,aAAa,CAAC,CAAC;QACnD,IAAI,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;KAC3C,CAAC;IAEF,UAAU,CAAC,EAAE,OAAO,CAAC;QACnB,aAAa,EAAE,EAAE,CAAC;YAAE,IAAI,EAAE,WAAW,CAAA;SAAE,CAAC,CAAC;KAC1C,CAAC,CAAC;CACJ,CAAC;AAoBF,MAAM,CAAC,OAAO,UAAU,MAAM,CAAC,EAC7B,KAAK,EACL,MAAc,EACd,aAAa,EACb,UAAU,EACV,IAAI,EACJ,MAAM,EACN,UAAU,EACV,QAAQ,EACR,UAAU,EAAE,EAAE,aAAoC,EAAO,EACzD,GAAG,IAAI,EACR,EAAE,WAAW,2CAiHb"}
@@ -1,30 +1,21 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
- import { createContext, Fragment, useContext, useEffect, useMemo, useRef, useState, } from 'react';
3
+ import { Fragment, lazy, useEffect, useMemo, useState, } from 'react';
4
4
  import { Controller, FormProvider, useForm, useFormContext, } from 'react-hook-form';
5
5
  import { useApiContext, useServerSelectContext } from '../ui/contexts/api.js';
6
- import { FieldSet, JsonInput, ObjectInput } from './inputs.js';
6
+ import { FieldSet, JsonInput } from './inputs.js';
7
7
  import { getStatusInfo } from './status-info.js';
8
8
  import { getUrl } from '../utils/server-url.js';
9
9
  import { DynamicCodeBlock } from 'fumadocs-ui/components/dynamic-codeblock';
10
10
  import { MethodLabel } from '../ui/components/method-label.js';
11
11
  import { useQuery } from '../utils/use-query.js';
12
- import ServerSelect from '../ui/server-select.js';
13
12
  import { Collapsible, CollapsibleContent, CollapsibleTrigger, } from 'fumadocs-ui/components/ui/collapsible';
14
13
  import { ChevronDown, LoaderCircle } from '../icons.js';
15
- import { OauthDialog, OauthDialogTrigger, } from '../playground/auth/oauth-dialog.js';
16
14
  import { useRequestData } from '../ui/contexts/code-example.js';
17
15
  import { useEffectEvent } from 'fumadocs-core/utils/use-effect-event';
18
16
  import { buttonVariants } from 'fumadocs-ui/components/ui/button';
19
17
  import { cn } from 'fumadocs-ui/utils/cn';
20
- import { cva } from 'class-variance-authority';
21
- const SchemaContext = createContext(undefined);
22
- export function useSchemaContext() {
23
- const ctx = useContext(SchemaContext);
24
- if (!ctx)
25
- throw new Error('Missing provider');
26
- return ctx;
27
- }
18
+ import { SchemaProvider, useResolvedSchema, } from '../playground/schema.js';
28
19
  function toRequestData(method, mediaType, value) {
29
20
  return {
30
21
  path: value.path,
@@ -36,10 +27,11 @@ function toRequestData(method, mediaType, value) {
36
27
  query: value.query,
37
28
  };
38
29
  }
30
+ const ServerSelect = lazy(() => import('../ui/server-select.js'));
39
31
  export default function Client({ route, method = 'GET', authorization, parameters, body, fields, references, proxyUrl, components: { ResultDisplay = DefaultResultDisplay } = {}, ...rest }) {
40
32
  const { server } = useServerSelectContext();
41
- const dynamicRef = useRef(new Map());
42
33
  const requestData = useRequestData();
34
+ const fieldInfoMap = useMemo(() => new Map(), []);
43
35
  const authInfo = usePersistentAuthInfo(authorization);
44
36
  const defaultValues = useMemo(() => ({
45
37
  authorization: authInfo.info,
@@ -63,6 +55,7 @@ export default function Client({ route, method = 'GET', authorization, parameter
63
55
  });
64
56
  });
65
57
  useEffect(() => {
58
+ fieldInfoMap.clear();
66
59
  form.reset(defaultValues);
67
60
  // eslint-disable-next-line react-hooks/exhaustive-deps -- update default value
68
61
  }, [defaultValues]);
@@ -83,13 +76,11 @@ export default function Client({ route, method = 'GET', authorization, parameter
83
76
  const onSubmit = form.handleSubmit((value) => {
84
77
  testQuery.start(value);
85
78
  });
86
- return (_jsx(FormProvider, { ...form, children: _jsx(SchemaContext.Provider, { value: useMemo(() => ({ references: references, dynamic: dynamicRef }), [references]), children: _jsx(AuthProvider, { authorization: authorization, children: _jsxs("form", { ...rest, className: cn('not-prose flex flex-col rounded-xl border shadow-md overflow-hidden bg-fd-card text-fd-card-foreground', rest.className), onSubmit: onSubmit, children: [_jsxs("div", { className: "flex flex-row items-center gap-2 text-sm p-3 pb-0", children: [_jsx(MethodLabel, { children: method }), _jsx(Route, { route: route, className: "flex-1" }), _jsx("button", { type: "submit", className: cn(buttonVariants({ color: 'primary', size: 'sm' }), 'px-3 py-1.5'), disabled: testQuery.isLoading, children: testQuery.isLoading ? (_jsx(LoaderCircle, { className: "size-4 animate-spin" })) : ('Send') })] }), _jsx(FormBody, { body: body, fields: fields, parameters: parameters, authorization: authorization }), testQuery.data ? _jsx(ResultDisplay, { data: testQuery.data }) : null] }) }) }) }));
79
+ return (_jsx(FormProvider, { ...form, children: _jsx(SchemaProvider, { fieldInfoMap: fieldInfoMap, references: references, children: _jsxs("form", { ...rest, className: cn('not-prose flex flex-col rounded-xl border shadow-md overflow-hidden bg-fd-card text-fd-card-foreground', rest.className), onSubmit: onSubmit, children: [_jsx(ServerSelect, {}), _jsxs("div", { className: "flex flex-row items-center gap-2 text-sm p-3 pb-0", children: [_jsx(MethodLabel, { children: method }), _jsx(Route, { route: route, className: "flex-1" }), _jsx("button", { type: "submit", className: cn(buttonVariants({ color: 'primary', size: 'sm' }), 'px-3 py-1.5'), disabled: testQuery.isLoading, children: testQuery.isLoading ? (_jsx(LoaderCircle, { className: "size-4 animate-spin" })) : ('Send') })] }), _jsx(FormBody, { body: body, fields: fields, parameters: parameters, authorization: authorization }), testQuery.data ? _jsx(ResultDisplay, { data: testQuery.data }) : null, authorization && _jsx(AuthFooter, { authorization: authorization })] }) }) }));
87
80
  }
88
81
  const paramNames = ['Headers', 'Cookies', 'Query', 'Path'];
89
82
  const paramTypes = ['header', 'cookie', 'query', 'path'];
90
- function FormBody({ authorization, parameters = [], body, fields = {}, }) {
91
- const { servers } = useApiContext();
92
- const { server, setServer, setServerVariables } = useServerSelectContext();
83
+ function FormBody({ authorization, parameters = [], fields = {}, body, }) {
93
84
  const params = useMemo(() => {
94
85
  return paramTypes.map((param) => parameters.filter((v) => v.in === param));
95
86
  }, [parameters]);
@@ -99,30 +90,25 @@ function FormBody({ authorization, parameters = [], body, fields = {}, }) {
99
90
  const schema = authorization.type === 'http' && authorization.scheme === 'basic'
100
91
  ? {
101
92
  type: 'object',
102
- isRequired: true,
93
+ required: ['username', 'password'],
103
94
  properties: {
104
95
  username: {
105
96
  type: 'string',
106
- isRequired: true,
107
97
  },
108
98
  password: {
109
99
  type: 'string',
110
- isRequired: true,
111
100
  },
112
101
  },
113
102
  }
114
103
  : {
115
104
  type: 'string',
116
- isRequired: true,
117
105
  description: 'The Authorization access token',
118
106
  };
119
107
  if (fields?.auth)
120
108
  return renderCustomField('authorization', schema, fields.auth);
121
- return (_jsxs(_Fragment, { children: [_jsx(FieldSet, { fieldName: "authorization", name: "Authorization", field: schema }), authorization?.type === 'oauth2' && (_jsx(OauthDialogTrigger, { type: "button", className: cn(buttonVariants({
122
- color: 'secondary',
123
- })), children: "Open" }))] }));
109
+ return (_jsx(FieldSet, { fieldName: "authorization", name: "Authorization", field: schema, isRequired: true }));
124
110
  }
125
- return (_jsxs(_Fragment, { children: [servers.length > 1 ? (_jsx(CollapsiblePanel, { title: "Server URL", children: _jsx(ServerSelect, { server: server, onServerChanged: setServer, onVariablesChanged: setServerVariables }) })) : null, params.map((param, i) => {
111
+ return (_jsxs(_Fragment, { children: [params.map((param, i) => {
126
112
  const name = paramNames[i];
127
113
  const type = paramTypes[i];
128
114
  if (type !== 'header' && param.length === 0)
@@ -131,37 +117,46 @@ function FormBody({ authorization, parameters = [], body, fields = {}, }) {
131
117
  return;
132
118
  return (_jsxs(CollapsiblePanel, { title: name, children: [type === 'header' ? renderAuth() : null, param.map((field) => {
133
119
  const fieldName = `${type}.${field.name}`;
134
- if (!fields?.parameter) {
135
- return (_jsx(FieldSet, { name: field.name, fieldName: fieldName, field: field }, fieldName));
120
+ if (fields?.parameter) {
121
+ return renderCustomField(fieldName, field.schema, fields.parameter, field.name);
136
122
  }
137
- return renderCustomField(fieldName, field, fields.parameter, field.name);
123
+ return (_jsx(FieldSet, { name: field.name, fieldName: fieldName, field: field.schema }, fieldName));
138
124
  })] }, name));
139
- }), body ? (fields.body ? (_jsx(CollapsiblePanel, { title: "Body", children: renderCustomField('body', body, fields.body) })) : (_jsx(BodyInput, { field: body }))) : null] }));
125
+ }), body ? (fields.body ? (_jsx(CollapsiblePanel, { title: "Body", children: renderCustomField('body', body.schema, fields.body) })) : (_jsx(BodyInput, { field: body.schema }))) : null] }));
140
126
  }
141
- const bodyTypeVariants = cva('p-1 rounded-lg font-medium text-xs transition-colors', {
142
- variants: {
143
- active: {
144
- true: 'bg-fd-primary/10 text-fd-primary',
145
- false: 'text-fd-muted-foreground',
146
- },
147
- },
148
- });
149
- function BodyInput({ field }) {
127
+ function BodyInput({ field: _field }) {
128
+ const field = useResolvedSchema(_field);
150
129
  const [isJson, setIsJson] = useState(false);
151
- return (_jsxs(CollapsiblePanel, { title: "Body", children: [_jsxs("div", { className: "grid grid-cols-2 border bg-fd-muted rounded-lg", children: [_jsx("button", { className: cn(bodyTypeVariants({ active: !isJson })), onClick: () => setIsJson(false), type: "button", children: "Simple" }), _jsx("button", { className: cn(bodyTypeVariants({ active: isJson })), onClick: () => setIsJson(true), type: "button", children: "JSON Mode" })] }), isJson ? (_jsx(JsonInput, { fieldName: "body" })) : field.type === 'object' ? (_jsx(ObjectInput, { field: field, fieldName: "body" })) : (_jsx(FieldSet, { field: field, fieldName: "body" }))] }));
130
+ return (_jsx(CollapsiblePanel, { title: "Body", children: isJson ? (_jsx(JsonInput, { fieldName: "body", children: _jsx("button", { className: cn(buttonVariants({
131
+ color: 'ghost',
132
+ size: 'sm',
133
+ className: 'p-2',
134
+ })), onClick: () => setIsJson(false), type: "button", children: "Close JSON Editor" }) })) : (_jsx(FieldSet, { field: field, fieldName: "body", name: _jsx("button", { className: cn(buttonVariants({
135
+ color: 'secondary',
136
+ size: 'sm',
137
+ className: 'p-2',
138
+ })), onClick: () => setIsJson(true), type: "button", children: "Open JSON Editor" }) })) }));
152
139
  }
153
140
  function renderCustomField(fieldName, info, field, key) {
154
141
  return (_jsx(Controller, {
155
142
  // @ts-expect-error we use string here
156
143
  render: (props) => field.render({ ...props, info }), name: fieldName }, key));
157
144
  }
158
- function AuthProvider({ authorization, children, }) {
145
+ const OauthDialog = lazy(() => import('./auth/oauth-dialog.js').then((mod) => ({
146
+ default: mod.OauthDialog,
147
+ })));
148
+ const OauthDialogTrigger = lazy(() => import('./auth/oauth-dialog.js').then((mod) => ({
149
+ default: mod.OauthDialogTrigger,
150
+ })));
151
+ function AuthFooter({ authorization }) {
159
152
  const form = useFormContext();
160
- if (!authorization || authorization.type !== 'oauth2')
161
- return children;
153
+ if (authorization.type !== 'oauth2')
154
+ return;
162
155
  // only the first one, so it looks simpler :)
163
156
  const flow = Object.keys(authorization.flows)[0];
164
- return (_jsx(OauthDialog, { flow: flow, scheme: authorization, setToken: (token) => form.setValue('authorization', `Bearer ${token}`), children: children }));
157
+ return (_jsx(OauthDialog, { flow: flow, scheme: authorization, setToken: (token) => form.setValue('authorization', `Bearer ${token}`), children: _jsx(OauthDialogTrigger, { type: "button", className: cn(buttonVariants({
158
+ color: 'secondary',
159
+ })), children: "Auth Settings" }) }));
165
160
  }
166
161
  function Route({ route, ...props }) {
167
162
  const segments = route.split('/').filter((part) => part.length > 0);
@@ -170,7 +165,7 @@ function Route({ route, ...props }) {
170
165
  function DefaultResultDisplay({ data }) {
171
166
  const statusInfo = useMemo(() => getStatusInfo(data.status), [data.status]);
172
167
  const { shikiOptions } = useApiContext();
173
- return (_jsxs("div", { className: "flex flex-col gap-3 rounded-lg border bg-fd-card p-4", children: [_jsxs("div", { className: "inline-flex items-center gap-1.5 text-sm font-medium text-fd-foreground", children: [_jsx(statusInfo.icon, { className: cn('size-4', statusInfo.color) }), statusInfo.description] }), _jsx("p", { className: "text-sm text-fd-muted-foreground", children: data.status }), data.data ? (_jsx(DynamicCodeBlock, { lang: typeof data.data === 'string' && data.data.length > 50000
168
+ return (_jsxs("div", { className: "flex flex-col gap-3 border-t p-3", children: [_jsxs("div", { className: "inline-flex items-center gap-1.5 text-sm font-medium text-fd-foreground", children: [_jsx(statusInfo.icon, { className: cn('size-4', statusInfo.color) }), statusInfo.description] }), _jsx("p", { className: "text-sm text-fd-muted-foreground", children: data.status }), data.data ? (_jsx(DynamicCodeBlock, { lang: typeof data.data === 'string' && data.data.length > 50000
174
169
  ? 'text'
175
170
  : data.type, code: typeof data.data === 'string'
176
171
  ? data.data
@@ -1,3 +1,3 @@
1
- import type { ReferenceSchema, RequestSchema } from '../playground/index.js';
2
- export declare function getDefaultValue(item: RequestSchema | ReferenceSchema, references: Record<string, RequestSchema>): unknown;
1
+ import type { RequestSchema } from '../playground/index.js';
2
+ export declare function getDefaultValue(schema: RequestSchema): unknown;
3
3
  //# sourceMappingURL=get-default-values.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"get-default-values.d.ts","sourceRoot":"","sources":["../../src/playground/get-default-values.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAGzE,wBAAgB,eAAe,CAC7B,IAAI,EAAE,aAAa,GAAG,eAAe,EACrC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,GACxC,OAAO,CA2BT"}
1
+ {"version":3,"file":"get-default-values.d.ts","sourceRoot":"","sources":["../../src/playground/get-default-values.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAExD,wBAAgB,eAAe,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CA2B9D"}
@@ -1,28 +1,27 @@
1
- import { resolve } from '../playground/resolve.js';
2
- export function getDefaultValue(item, references) {
3
- if (item.type === 'ref')
4
- return getDefaultValue(resolve(item, references), references);
5
- if (item.type === 'object')
6
- return Object.fromEntries(Object.entries(item.properties).map(([key, prop]) => [
7
- key,
8
- getDefaultValue(prop.type === 'ref' ? references[prop.schema] : prop, references),
9
- ]));
10
- if (item.type === 'array')
1
+ export function getDefaultValue(schema) {
2
+ if (typeof schema === 'boolean')
3
+ return null;
4
+ const type = schema.type;
5
+ if (Array.isArray(type))
6
+ return getDefaultValue({
7
+ ...schema,
8
+ type: type[0],
9
+ });
10
+ if (type === 'object' && typeof schema === 'object')
11
+ return Object.fromEntries(Object.entries(schema.properties ?? {}).map(([key, prop]) => {
12
+ return [key, getDefaultValue(prop)];
13
+ }));
14
+ if (type === 'array')
11
15
  return [];
12
- if (item.type === 'null')
16
+ if (type === 'null')
13
17
  return null;
14
- if (item.type === 'switcher') {
15
- const first = Object.values(item.items).at(0);
16
- if (!first)
17
- return '';
18
- return getDefaultValue(resolve(first, references), references);
19
- }
20
- if (item.type === 'file')
21
- return undefined;
22
- if (item.type === 'string')
18
+ if (type === 'string') {
19
+ if (typeof schema === 'object' && schema.format === 'binary')
20
+ return undefined;
23
21
  return '';
24
- if (item.type === 'number')
22
+ }
23
+ if (type === 'number' || type === 'integer')
25
24
  return 0;
26
- if (item.type === 'boolean')
25
+ if (type === 'boolean')
27
26
  return false;
28
27
  }
@@ -1,47 +1,13 @@
1
1
  import type { MethodInformation, RenderContext } from '../types.js';
2
+ import { type ParsedSchema } from '../utils/schema.js';
2
3
  import { type ClientProps } from './client.js';
3
- interface BaseSchema {
4
- description?: string;
5
- isRequired: boolean;
6
- }
7
- export type ParameterField = (PrimitiveSchema | ArraySchema) & {
4
+ export type ParameterField = {
8
5
  name: string;
9
6
  description?: string;
7
+ schema: ParsedSchema;
10
8
  in: 'cookie' | 'header' | 'query' | 'path';
11
9
  };
12
- interface PrimitiveSchema extends BaseSchema {
13
- type: 'boolean' | 'string' | 'number';
14
- }
15
- export interface ReferenceSchema extends BaseSchema {
16
- type: 'ref';
17
- schema: string;
18
- }
19
- interface ArraySchema extends BaseSchema {
20
- type: 'array';
21
- /**
22
- * Reference to item schema or the schema
23
- */
24
- items: string | RequestSchema;
25
- }
26
- interface FileSchema extends BaseSchema {
27
- type: 'file';
28
- }
29
- interface ObjectSchema extends BaseSchema {
30
- type: 'object';
31
- properties: Record<string, RequestSchema | ReferenceSchema>;
32
- /**
33
- * Reference to schema, or true if it's `any`
34
- */
35
- additionalProperties?: boolean | string;
36
- }
37
- interface SwitcherSchema extends BaseSchema {
38
- type: 'switcher';
39
- items: Record<string, ReferenceSchema | RequestSchema>;
40
- }
41
- interface NullSchema extends BaseSchema {
42
- type: 'null';
43
- }
44
- export type RequestSchema = PrimitiveSchema | ArraySchema | ObjectSchema | SwitcherSchema | NullSchema | FileSchema;
10
+ export type RequestSchema = ParsedSchema;
45
11
  export interface APIPlaygroundProps {
46
12
  path: string;
47
13
  method: MethodInformation;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/playground/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,iBAAiB,EAEjB,aAAa,EACd,MAAM,SAAS,CAAC;AAOjB,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,UAAU,CAAC;AAG5C,UAAU,UAAU;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,MAAM,cAAc,GAAG,CAAC,eAAe,GAAG,WAAW,CAAC,GAAG;IAC7D,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,EAAE,EAAE,QAAQ,GAAG,QAAQ,GAAG,OAAO,GAAG,MAAM,CAAC;CAC5C,CAAC;AAEF,UAAU,eAAgB,SAAQ,UAAU;IAC1C,IAAI,EAAE,SAAS,GAAG,QAAQ,GAAG,QAAQ,CAAC;CACvC;AAED,MAAM,WAAW,eAAgB,SAAQ,UAAU;IACjD,IAAI,EAAE,KAAK,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,UAAU,WAAY,SAAQ,UAAU;IACtC,IAAI,EAAE,OAAO,CAAC;IACd;;OAEG;IACH,KAAK,EAAE,MAAM,GAAG,aAAa,CAAC;CAC/B;AAED,UAAU,UAAW,SAAQ,UAAU;IACrC,IAAI,EAAE,MAAM,CAAC;CACd;AAED,UAAU,YAAa,SAAQ,UAAU;IACvC,IAAI,EAAE,QAAQ,CAAC;IACf,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,GAAG,eAAe,CAAC,CAAC;IAE5D;;OAEG;IACH,oBAAoB,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;CACzC;AAED,UAAU,cAAe,SAAQ,UAAU;IACzC,IAAI,EAAE,UAAU,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,GAAG,aAAa,CAAC,CAAC;CACxD;AAED,UAAU,UAAW,SAAQ,UAAU;IACrC,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,MAAM,aAAa,GACrB,eAAe,GACf,WAAW,GACX,YAAY,GACZ,cAAc,GACd,UAAU,GACV,UAAU,CAAC;AAUf,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,iBAAiB,CAAC;IAC1B,GAAG,EAAE,aAAa,CAAC;IAEnB,MAAM,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC;CAC/B;AAED,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAEzD,wBAAsB,aAAa,CAAC,EAClC,IAAI,EACJ,MAAM,EACN,GAAG,EACH,MAAM,GACP,EAAE,kBAAkB,oDAsCpB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/playground/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAChE,OAAO,EAAoB,KAAK,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAErE,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,UAAU,CAAC;AAG5C,MAAM,MAAM,cAAc,GAAG;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,YAAY,CAAC;IACrB,EAAE,EAAE,QAAQ,GAAG,QAAQ,GAAG,OAAO,GAAG,MAAM,CAAC;CAC5C,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG,YAAY,CAAC;AAUzC,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,iBAAiB,CAAC;IAC1B,GAAG,EAAE,aAAa,CAAC;IAEnB,MAAM,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC;CAC/B;AAED,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAEzD,wBAAsB,aAAa,CAAC,EAClC,IAAI,EACJ,MAAM,EACN,GAAG,EACH,MAAM,GACP,EAAE,kBAAkB,oDAyCpB"}