fumadocs-openapi 10.5.0 → 10.6.1
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 +33 -21
- package/dist/generate-file.d.ts +10 -2
- package/dist/generate-file.d.ts.map +1 -1
- package/dist/generate-file.js +15 -3
- package/dist/generate-file.js.map +1 -1
- package/dist/playground/client.d.ts +32 -10
- package/dist/playground/client.d.ts.map +1 -1
- package/dist/playground/client.js +70 -60
- package/dist/playground/client.js.map +1 -1
- package/dist/playground/components/inputs.js +1 -1
- package/dist/playground/components/inputs.js.map +1 -1
- package/dist/playground/components/server-select.js +3 -4
- package/dist/playground/components/server-select.js.map +1 -1
- package/dist/playground/fetcher.d.ts +20 -1
- package/dist/playground/fetcher.d.ts.map +1 -1
- package/dist/playground/fetcher.js +28 -24
- package/dist/playground/fetcher.js.map +1 -1
- package/dist/playground/index.d.ts +3 -3
- package/dist/playground/index.d.ts.map +1 -1
- package/dist/playground/index.js +2 -2
- package/dist/playground/index.js.map +1 -1
- package/dist/playground/schema.d.ts +1 -0
- package/dist/playground/schema.d.ts.map +1 -1
- package/dist/playground/schema.js +10 -12
- package/dist/playground/schema.js.map +1 -1
- package/dist/requests/generators/python.d.ts +2 -1
- package/dist/requests/generators/python.d.ts.map +1 -1
- package/dist/requests/generators/python.js +13 -2
- package/dist/requests/generators/python.js.map +1 -1
- package/dist/scalar/index.d.ts +2 -1
- package/dist/scalar/index.d.ts.map +1 -1
- package/dist/server/create.d.ts +2 -0
- package/dist/server/create.d.ts.map +1 -1
- package/dist/server/create.js +11 -8
- package/dist/server/create.js.map +1 -1
- package/dist/server/proxy.d.ts +5 -2
- package/dist/server/proxy.d.ts.map +1 -1
- package/dist/server/proxy.js +41 -31
- package/dist/server/proxy.js.map +1 -1
- package/dist/server/source-api.d.ts +2 -0
- package/dist/server/source-api.d.ts.map +1 -1
- package/dist/server/source-api.js +10 -1
- package/dist/server/source-api.js.map +1 -1
- package/dist/types.d.ts +2 -4
- package/dist/types.d.ts.map +1 -1
- package/dist/ui/api-page.d.ts +1 -3
- package/dist/ui/api-page.d.ts.map +1 -1
- package/dist/ui/api-page.js +4 -6
- package/dist/ui/api-page.js.map +1 -1
- package/dist/ui/base.d.ts +20 -16
- package/dist/ui/base.d.ts.map +1 -1
- package/dist/ui/base.js +18 -9
- package/dist/ui/base.js.map +1 -1
- package/dist/ui/{full.client.js → client/full.js} +3 -3
- package/dist/ui/client/full.js.map +1 -0
- package/dist/ui/client/index.d.ts +1 -1
- package/dist/ui/client/index.js.map +1 -1
- package/dist/ui/client/storage-key.js.map +1 -1
- package/dist/ui/components/codeblock.d.ts +2 -2
- package/dist/ui/components/codeblock.d.ts.map +1 -1
- package/dist/ui/components/server-tab.js +43 -0
- package/dist/ui/components/server-tab.js.map +1 -0
- package/dist/ui/contexts/api.js +18 -35
- package/dist/ui/contexts/api.js.map +1 -1
- package/dist/ui/create-client.d.ts +26 -0
- package/dist/ui/create-client.d.ts.map +1 -0
- package/dist/ui/create-client.js +132 -0
- package/dist/ui/create-client.js.map +1 -0
- package/dist/ui/index.d.ts +10 -2
- package/dist/ui/index.d.ts.map +1 -0
- package/dist/ui/index.js +21 -1
- package/dist/ui/index.js.map +1 -0
- package/dist/ui/operation/client.js +44 -36
- package/dist/ui/operation/client.js.map +1 -1
- package/dist/ui/operation/{request-tabs.d.ts → get-example-requests.d.ts} +2 -4
- package/dist/ui/operation/get-example-requests.d.ts.map +1 -0
- package/dist/ui/operation/get-example-requests.js +83 -0
- package/dist/ui/operation/get-example-requests.js.map +1 -0
- package/dist/ui/operation/index.js +101 -63
- package/dist/ui/operation/index.js.map +1 -1
- package/dist/ui/operation/request-tabs.js +3 -81
- package/dist/ui/operation/request-tabs.js.map +1 -1
- package/dist/ui/operation/response-tabs.d.ts +1 -1
- package/dist/ui/operation/response-tabs.js +57 -54
- package/dist/ui/operation/response-tabs.js.map +1 -1
- package/dist/ui/operation/usage-tabs/client.js +7 -48
- package/dist/ui/operation/usage-tabs/client.js.map +1 -1
- package/dist/ui/operation/usage-tabs/index.js +14 -10
- package/dist/ui/operation/usage-tabs/index.js.map +1 -1
- package/dist/ui/operation/usage-tabs/lazy.js +1 -2
- package/dist/ui/operation/usage-tabs/lazy.js.map +1 -1
- package/dist/ui/schema/client.d.ts +0 -1
- package/dist/ui/schema/client.d.ts.map +1 -1
- package/dist/ui/schema/index.d.ts +1 -2
- package/dist/ui/schema/index.d.ts.map +1 -1
- package/dist/ui/schema/index.js +4 -2
- package/dist/ui/schema/index.js.map +1 -1
- package/dist/utils/pages/builder.d.ts +1 -1
- package/dist/utils/pages/builder.js +1 -1
- package/dist/utils/process-document.d.ts +1 -1
- package/dist/utils/process-document.js +1 -32
- package/dist/utils/process-document.js.map +1 -1
- package/dist/utils/schema/dereference.js +37 -0
- package/dist/utils/schema/dereference.js.map +1 -0
- package/dist/utils/{schema.d.ts → schema/index.d.ts} +3 -3
- package/dist/utils/schema/index.d.ts.map +1 -0
- package/dist/utils/{schema.js → schema/index.js} +3 -3
- package/dist/utils/schema/index.js.map +1 -0
- package/dist/utils/schema/resolve-ref.js +21 -0
- package/dist/utils/schema/resolve-ref.js.map +1 -0
- package/dist/utils/{schema-to-string.js → schema/to-string.js} +2 -2
- package/dist/utils/schema/to-string.js.map +1 -0
- package/package.json +10 -10
- package/dist/requests/to-python-object.js +0 -17
- package/dist/requests/to-python-object.js.map +0 -1
- package/dist/ui/full.client.js.map +0 -1
- package/dist/ui/full.d.ts +0 -11
- package/dist/ui/full.d.ts.map +0 -1
- package/dist/ui/full.js +0 -36
- package/dist/ui/full.js.map +0 -1
- package/dist/ui/operation/request-tabs.d.ts.map +0 -1
- package/dist/utils/schema-to-string.js.map +0 -1
- package/dist/utils/schema.d.ts.map +0 -1
- package/dist/utils/schema.js.map +0 -1
- /package/dist/utils/{schema-to-string.d.ts → schema/to-string.d.ts} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fetcher.d.ts","names":[],"sources":["../../src/playground/fetcher.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"fetcher.d.ts","names":[],"sources":["../../src/playground/fetcher.ts"],"mappings":";;;UAKiB,WAAA;EACf,MAAA;EACA,IAAA;EACA,IAAA;AAAA;AAAA,UAYe,qBAAA;EAiByC;;;EAbxD,cAAA;EAEA,QAAA;EAAA;;;;;EAMA,kBAAA;EAKwD;;;EAAxD,aAAA,IAAiB,WAAA,EAAa,WAAA,KAAgB,SAAA,CAAU,WAAA;AAAA"}
|
|
@@ -1,42 +1,46 @@
|
|
|
1
1
|
import { resolveMediaAdapter } from "../requests/media/resolve-adapter.js";
|
|
2
2
|
import "../requests/media/adapter.js";
|
|
3
3
|
//#region src/playground/fetcher.ts
|
|
4
|
-
function createBrowserFetcher(adapters, requestTimeout) {
|
|
5
|
-
return { async fetch(url,
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
4
|
+
function createBrowserFetcher(adapters, { proxyUrl, proxyForwardCookie = true, requestTimeout = 10, onRequestInit } = {}) {
|
|
5
|
+
return { async fetch(url, data) {
|
|
6
|
+
let requestUrl = new URL(url, document.baseURI);
|
|
7
|
+
let requestInit = {
|
|
8
|
+
method: data.method,
|
|
9
|
+
cache: "no-cache",
|
|
10
|
+
signal: typeof requestTimeout === "number" ? AbortSignal.timeout(requestTimeout * 1e3) : void 0
|
|
11
|
+
};
|
|
12
|
+
const headers = requestInit.headers = new Headers();
|
|
13
|
+
for (const key in data.header) {
|
|
14
|
+
const param = data.header[key];
|
|
10
15
|
headers.append(key, param.value);
|
|
11
16
|
}
|
|
12
|
-
const proxyUrl = options.proxyUrl ? new URL(options.proxyUrl, document.baseURI) : null;
|
|
13
17
|
if (proxyUrl) {
|
|
14
|
-
proxyUrl
|
|
15
|
-
url
|
|
18
|
+
requestUrl = new URL(proxyUrl, document.baseURI);
|
|
19
|
+
requestUrl.searchParams.append("url", url);
|
|
16
20
|
}
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
const adapter = resolveMediaAdapter(options.bodyMediaType, adapters);
|
|
21
|
+
if (data.bodyMediaType && data.body) {
|
|
22
|
+
const adapter = resolveMediaAdapter(data.bodyMediaType, adapters);
|
|
20
23
|
if (!adapter) return {
|
|
21
24
|
status: 400,
|
|
22
25
|
type: "text",
|
|
23
|
-
data: `[Fumadocs] No adapter for ${
|
|
26
|
+
data: `[Fumadocs] No adapter for ${data.bodyMediaType}, you need to specify one from 'createOpenAPI()'.`
|
|
24
27
|
};
|
|
25
|
-
|
|
28
|
+
if (data.bodyMediaType !== "multipart/form-data") headers.append("Content-Type", data.bodyMediaType);
|
|
29
|
+
requestInit.body = adapter.encode(data);
|
|
26
30
|
}
|
|
27
|
-
|
|
28
|
-
const
|
|
29
|
-
|
|
31
|
+
if (proxyUrl && proxyForwardCookie) {
|
|
32
|
+
const encoded = Object.entries(data.cookie).map(([k, v]) => `${k}=${encodeURIComponent(v.value)}`).join("; ");
|
|
33
|
+
requestUrl.searchParams.set("cookie", encoded);
|
|
34
|
+
requestInit.credentials = "omit";
|
|
35
|
+
} else for (const key in data.cookie) {
|
|
36
|
+
const param = data.cookie[key];
|
|
37
|
+
const segs = [`${key}=${encodeURIComponent(param.value)}`];
|
|
38
|
+
if (proxyUrl && requestUrl.origin !== window.location.origin) segs.push(`domain=${requestUrl.host}`);
|
|
30
39
|
segs.push("path=/", "max-age=30");
|
|
31
40
|
document.cookie = segs.join("; ");
|
|
32
41
|
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
cache: "no-cache",
|
|
36
|
-
headers,
|
|
37
|
-
body,
|
|
38
|
-
signal: AbortSignal.timeout(requestTimeout * 1e3)
|
|
39
|
-
}).then(async (res) => {
|
|
42
|
+
if (onRequestInit) requestInit = await onRequestInit(requestInit);
|
|
43
|
+
return fetch(requestUrl, requestInit).then(async (res) => {
|
|
40
44
|
const contentType = res.headers.get("Content-Type") ?? "";
|
|
41
45
|
let type;
|
|
42
46
|
let data;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fetcher.js","names":[],"sources":["../../src/playground/fetcher.ts"],"sourcesContent":["import type { RequestData } from '@/requests/types';\nimport type { MediaAdapter } from '@/requests/media/adapter';\nimport { resolveMediaAdapter } from '@/requests/media/adapter';\
|
|
1
|
+
{"version":3,"file":"fetcher.js","names":[],"sources":["../../src/playground/fetcher.ts"],"sourcesContent":["import type { RequestData } from '@/requests/types';\nimport type { MediaAdapter } from '@/requests/media/adapter';\nimport { resolveMediaAdapter } from '@/requests/media/adapter';\nimport type { Awaitable } from '@/types';\n\nexport interface FetchResult {\n status: number;\n type: 'json' | 'html' | 'text';\n data: unknown;\n}\n\nexport interface Fetcher {\n /**\n * This method will not apply the path & search parameters from `options` to given `url`.\n *\n * @param url - The full URL of request.\n */\n fetch: (url: string, data: RequestData) => Promise<FetchResult>;\n}\n\nexport interface BrowserFetcherOptions {\n /**\n * Request timeout in seconds (default: 10s)\n */\n requestTimeout?: number | false;\n\n proxyUrl?: string;\n /**\n * Forward cookies via search parameters when API proxy is configured.\n *\n * @default true\n */\n proxyForwardCookie?: boolean;\n\n /**\n * transform the request options before sending.\n */\n onRequestInit?: (requestInit: RequestInit) => Awaitable<RequestInit>;\n}\n\nexport function createBrowserFetcher(\n adapters: Record<string, MediaAdapter>,\n {\n proxyUrl,\n proxyForwardCookie = true,\n requestTimeout = 10,\n onRequestInit,\n }: BrowserFetcherOptions = {},\n): Fetcher {\n return {\n async fetch(url, data) {\n let requestUrl = new URL(url, document.baseURI);\n let requestInit: RequestInit = {\n method: data.method,\n cache: 'no-cache',\n signal:\n typeof requestTimeout === 'number'\n ? AbortSignal.timeout(requestTimeout * 1000)\n : undefined,\n };\n\n const headers = (requestInit.headers = new Headers());\n\n for (const key in data.header) {\n const param = data.header[key];\n headers.append(key, param.value);\n }\n\n if (proxyUrl) {\n requestUrl = new URL(proxyUrl, document.baseURI);\n requestUrl.searchParams.append('url', url);\n }\n\n if (data.bodyMediaType && data.body) {\n const adapter = resolveMediaAdapter(data.bodyMediaType, adapters);\n if (!adapter)\n return {\n status: 400,\n type: 'text',\n data: `[Fumadocs] No adapter for ${data.bodyMediaType}, you need to specify one from 'createOpenAPI()'.`,\n };\n\n if (data.bodyMediaType !== 'multipart/form-data') {\n headers.append('Content-Type', data.bodyMediaType);\n }\n\n requestInit.body = adapter.encode(data as { body: unknown });\n }\n\n // cookies\n if (proxyUrl && proxyForwardCookie) {\n const encoded = Object.entries(data.cookie)\n .map(([k, v]) => `${k}=${encodeURIComponent(v.value)}`)\n .join('; ');\n requestUrl.searchParams.set('cookie', encoded);\n requestInit.credentials = 'omit';\n } else {\n for (const key in data.cookie) {\n const param = data.cookie[key];\n const segs: string[] = [`${key}=${encodeURIComponent(param.value)}`];\n\n if (proxyUrl && requestUrl.origin !== window.location.origin)\n segs.push(`domain=${requestUrl.host}`);\n segs.push('path=/', 'max-age=30');\n\n document.cookie = segs.join('; ');\n }\n }\n\n if (onRequestInit) requestInit = await onRequestInit(requestInit);\n\n return fetch(requestUrl, requestInit)\n .then(async (res) => {\n const contentType = res.headers.get('Content-Type') ?? '';\n let type: FetchResult['type'];\n let data: unknown;\n\n if (contentType.startsWith('application/json')) {\n type = 'json';\n data = await res.json();\n } else {\n type = contentType.startsWith('text/html') ? 'html' : 'text';\n data = await res.text();\n }\n\n return { status: res.status, type, data };\n })\n .catch((e) => {\n const message = e instanceof Error ? `[${e.name}] ${e.message}` : e.toString();\n\n return {\n status: 400,\n type: 'text',\n data: `Client side error: ${message}`,\n };\n });\n },\n };\n}\n"],"mappings":";;;AAwCA,SAAgB,qBACd,UACA,EACE,UACA,qBAAqB,MACrB,iBAAiB,IACjB,kBACyB,EAAE,EACpB;AACT,QAAO,EACL,MAAM,MAAM,KAAK,MAAM;EACrB,IAAI,aAAa,IAAI,IAAI,KAAK,SAAS,QAAQ;EAC/C,IAAI,cAA2B;GAC7B,QAAQ,KAAK;GACb,OAAO;GACP,QACE,OAAO,mBAAmB,WACtB,YAAY,QAAQ,iBAAiB,IAAK,GAC1C,KAAA;GACP;EAED,MAAM,UAAW,YAAY,UAAU,IAAI,SAAS;AAEpD,OAAK,MAAM,OAAO,KAAK,QAAQ;GAC7B,MAAM,QAAQ,KAAK,OAAO;AAC1B,WAAQ,OAAO,KAAK,MAAM,MAAM;;AAGlC,MAAI,UAAU;AACZ,gBAAa,IAAI,IAAI,UAAU,SAAS,QAAQ;AAChD,cAAW,aAAa,OAAO,OAAO,IAAI;;AAG5C,MAAI,KAAK,iBAAiB,KAAK,MAAM;GACnC,MAAM,UAAU,oBAAoB,KAAK,eAAe,SAAS;AACjE,OAAI,CAAC,QACH,QAAO;IACL,QAAQ;IACR,MAAM;IACN,MAAM,6BAA6B,KAAK,cAAc;IACvD;AAEH,OAAI,KAAK,kBAAkB,sBACzB,SAAQ,OAAO,gBAAgB,KAAK,cAAc;AAGpD,eAAY,OAAO,QAAQ,OAAO,KAA0B;;AAI9D,MAAI,YAAY,oBAAoB;GAClC,MAAM,UAAU,OAAO,QAAQ,KAAK,OAAO,CACxC,KAAK,CAAC,GAAG,OAAO,GAAG,EAAE,GAAG,mBAAmB,EAAE,MAAM,GAAG,CACtD,KAAK,KAAK;AACb,cAAW,aAAa,IAAI,UAAU,QAAQ;AAC9C,eAAY,cAAc;QAE1B,MAAK,MAAM,OAAO,KAAK,QAAQ;GAC7B,MAAM,QAAQ,KAAK,OAAO;GAC1B,MAAM,OAAiB,CAAC,GAAG,IAAI,GAAG,mBAAmB,MAAM,MAAM,GAAG;AAEpE,OAAI,YAAY,WAAW,WAAW,OAAO,SAAS,OACpD,MAAK,KAAK,UAAU,WAAW,OAAO;AACxC,QAAK,KAAK,UAAU,aAAa;AAEjC,YAAS,SAAS,KAAK,KAAK,KAAK;;AAIrC,MAAI,cAAe,eAAc,MAAM,cAAc,YAAY;AAEjE,SAAO,MAAM,YAAY,YAAY,CAClC,KAAK,OAAO,QAAQ;GACnB,MAAM,cAAc,IAAI,QAAQ,IAAI,eAAe,IAAI;GACvD,IAAI;GACJ,IAAI;AAEJ,OAAI,YAAY,WAAW,mBAAmB,EAAE;AAC9C,WAAO;AACP,WAAO,MAAM,IAAI,MAAM;UAClB;AACL,WAAO,YAAY,WAAW,YAAY,GAAG,SAAS;AACtD,WAAO,MAAM,IAAI,MAAM;;AAGzB,UAAO;IAAE,QAAQ,IAAI;IAAQ;IAAM;IAAM;IACzC,CACD,OAAO,MAAM;AAGZ,UAAO;IACL,QAAQ;IACR,MAAM;IACN,MAAM,sBALQ,aAAa,QAAQ,IAAI,EAAE,KAAK,IAAI,EAAE,YAAY,EAAE,UAAU;IAM7E;IACD;IAEP"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { MethodInformation, RenderContext, SecuritySchemeObject } from "../types.js";
|
|
2
|
-
import * as react from "react";
|
|
3
|
-
import * as react_jsx_runtime0 from "react/jsx-runtime";
|
|
2
|
+
import * as _$react from "react";
|
|
3
|
+
import * as _$react_jsx_runtime0 from "react/jsx-runtime";
|
|
4
4
|
|
|
5
5
|
//#region src/playground/index.d.ts
|
|
6
6
|
interface APIPlaygroundProps {
|
|
@@ -16,7 +16,7 @@ declare function APIPlayground({
|
|
|
16
16
|
path,
|
|
17
17
|
method,
|
|
18
18
|
ctx
|
|
19
|
-
}: APIPlaygroundProps):
|
|
19
|
+
}: APIPlaygroundProps): string | number | bigint | boolean | _$react_jsx_runtime0.JSX.Element | Iterable<_$react.ReactNode> | Promise<_$react.ReactNode> | null | undefined;
|
|
20
20
|
//#endregion
|
|
21
21
|
export { APIPlayground, APIPlaygroundProps, SecurityEntry };
|
|
22
22
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../../src/playground/index.tsx"],"mappings":";;;;;UAiBiB,kBAAA;EACf,IAAA;EACA,MAAA,EAAQ,iBAAA;EACR,GAAA,EAAK,aAAA;AAAA;AAAA,KAGK,aAAA,GAAgB,oBAAA;EAC1B,MAAA;EACA,EAAA;AAAA;AAAA,
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../../src/playground/index.tsx"],"mappings":";;;;;UAiBiB,kBAAA;EACf,IAAA;EACA,MAAA,EAAQ,iBAAA;EACR,GAAA,EAAK,aAAA;AAAA;AAAA,KAGK,aAAA,GAAgB,oBAAA;EAC1B,MAAA;EACA,EAAA;AAAA;AAAA,iBAGc,aAAA,CAAA;EAAgB,IAAA;EAAM,MAAA;EAAQ;AAAA,GAAO,kBAAA,wCAAkB,oBAAA,CAAA,GAAA,CAAA,OAAA,GAAA,QAAA,CAAA,OAAA,CAAA,SAAA,IAAA,OAAA,CAAA,OAAA,CAAA,SAAA"}
|
package/dist/playground/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { getPreferredType } from "../utils/schema.js";
|
|
1
|
+
import { getPreferredType } from "../utils/schema/index.js";
|
|
2
2
|
import { ClientLazy } from "./lazy.js";
|
|
3
3
|
import { jsx } from "react/jsx-runtime";
|
|
4
4
|
//#region src/playground/index.tsx
|
|
5
|
-
|
|
5
|
+
function APIPlayground({ path, method, ctx }) {
|
|
6
6
|
if (ctx.playground?.render) return ctx.playground.render({
|
|
7
7
|
path,
|
|
8
8
|
method,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../src/playground/index.tsx"],"sourcesContent":["import type {\n MediaTypeObject,\n MethodInformation,\n ParameterObject,\n RenderContext,\n SecuritySchemeObject,\n} from '@/types';\nimport { getPreferredType, NoReference, type ParsedSchema } from '@/utils/schema';\nimport { type PlaygroundClientProps } from './client';\nimport { ClientLazy } from './lazy';\n\ninterface Context {\n references: Record<string, ParsedSchema>;\n registered: WeakMap<Exclude<ParsedSchema, boolean>, string>;\n id: (schema?: object) => string;\n}\n\nexport interface APIPlaygroundProps {\n path: string;\n method: MethodInformation;\n ctx: RenderContext;\n}\n\nexport type SecurityEntry = SecuritySchemeObject & {\n scopes: string[];\n id: string;\n};\n\nexport
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/playground/index.tsx"],"sourcesContent":["import type {\n MediaTypeObject,\n MethodInformation,\n ParameterObject,\n RenderContext,\n SecuritySchemeObject,\n} from '@/types';\nimport { getPreferredType, NoReference, type ParsedSchema } from '@/utils/schema';\nimport { type PlaygroundClientProps } from './client';\nimport { ClientLazy } from './lazy';\n\ninterface Context {\n references: Record<string, ParsedSchema>;\n registered: WeakMap<Exclude<ParsedSchema, boolean>, string>;\n id: (schema?: object) => string;\n}\n\nexport interface APIPlaygroundProps {\n path: string;\n method: MethodInformation;\n ctx: RenderContext;\n}\n\nexport type SecurityEntry = SecuritySchemeObject & {\n scopes: string[];\n id: string;\n};\n\nexport function APIPlayground({ path, method, ctx }: APIPlaygroundProps) {\n if (ctx.playground?.render) {\n return ctx.playground.render({ path, method, ctx });\n }\n\n const bodyContent = method.requestBody?.content;\n const mediaType = bodyContent ? getPreferredType(bodyContent) : undefined;\n const takenIds = new Map<string, number>();\n\n const context: Context = {\n references: {},\n id(schema) {\n let name = 'r';\n if (schema) {\n const ref = ctx.schema.getRawRef(schema)?.split('/');\n if (ref && ref.length > 0) name = ref[ref.length - 1];\n }\n\n const count = takenIds.get(name) ?? 0;\n takenIds.set(name, count + 1);\n return count === 0 ? name : `${name}${count}`;\n },\n registered: new WeakMap(),\n };\n\n const props: PlaygroundClientProps = {\n securities: parseSecurities(method, ctx),\n method: method.method,\n route: path,\n parameters: method.parameters?.map((param: NoReference<ParameterObject>): ParameterObject => {\n if (param.schema !== undefined) {\n return {\n ...param,\n schema: writeReferences(param.schema, context),\n } as ParameterObject;\n }\n\n if (param.content !== undefined) {\n const content: Record<string, MediaTypeObject> = {};\n\n for (const k in param.content) {\n const original = param.content[k] as NoReference<MediaTypeObject>;\n if (!original || original.schema === undefined) continue;\n\n content[k] = {\n ...original,\n schema: writeReferences(original.schema, context),\n } as MediaTypeObject;\n }\n\n return {\n ...param,\n content,\n } as ParameterObject;\n }\n\n return param;\n }),\n body:\n bodyContent && mediaType\n ? ({\n schema: writeReferences(bodyContent[mediaType].schema as ParsedSchema, context),\n mediaType,\n } as PlaygroundClientProps['body'])\n : undefined,\n references: context.references,\n proxyUrl: ctx.proxyUrl,\n writeOnly: true,\n readOnly: false,\n };\n\n return <ClientLazy {...props} />;\n}\n\nfunction writeReferences(\n schema: ParsedSchema,\n ctx: Context,\n stack: WeakMap<object, object> = new WeakMap(),\n): ParsedSchema {\n if (typeof schema !== 'object' || !schema) return schema;\n if (stack.has(schema)) {\n const out = stack.get(schema)!;\n const id = ctx.id(schema);\n ctx.references[id] = out;\n\n return {\n $ref: `#/${id}`,\n };\n }\n\n const output = { ...schema };\n stack.set(schema, output);\n for (const _n in output) {\n const name = _n as keyof typeof output;\n if (!output[name]) continue;\n\n switch (name) {\n case 'oneOf':\n case 'allOf':\n case 'anyOf':\n output[name] = output[name].map((item) => writeReferences(item, ctx, stack));\n continue;\n case 'items':\n case 'additionalProperties':\n case 'not':\n output[name] = writeReferences(output[name], ctx, stack);\n continue;\n case 'properties':\n case 'patternProperties':\n output[name] = { ...output[name] };\n\n for (const key in output[name]) {\n output[name][key] = writeReferences(output[name][key], ctx, stack);\n }\n }\n }\n\n return output;\n}\n\nfunction parseSecurities(\n method: MethodInformation,\n { schema: { dereferenced } }: RenderContext,\n): PlaygroundClientProps['securities'] {\n const result: PlaygroundClientProps['securities'] = [];\n const security = method.security ?? dereferenced.security ?? [];\n if (security.length === 0) return result;\n\n for (const map of security) {\n const list: PlaygroundClientProps['securities'][number] = [];\n\n for (const [key, scopes] of Object.entries(map)) {\n const scheme = dereferenced.components?.securitySchemes?.[key];\n if (!scheme) continue;\n\n list.push({\n ...scheme,\n scopes,\n id: key,\n });\n }\n\n if (list.length > 0) result.push(list);\n }\n\n return result;\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.d.ts","names":[],"sources":["../../src/playground/schema.tsx"],"mappings":"
|
|
1
|
+
{"version":3,"file":"schema.d.ts","names":[],"sources":["../../src/playground/schema.tsx"],"mappings":";;;;;UAeiB,WAAA;;;;EAIf,SAAA;;;;EAKA,QAAA;AAAA"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { mergeAllOf } from "../utils/merge-schema.js";
|
|
2
|
-
import { schemaToString } from "../utils/schema
|
|
2
|
+
import { schemaToString } from "../utils/schema/to-string.js";
|
|
3
|
+
import { resolveRefSync } from "../utils/schema/resolve-ref.js";
|
|
3
4
|
import { createContext, use, useMemo } from "react";
|
|
4
5
|
import { jsx } from "react/jsx-runtime";
|
|
5
6
|
import { Ajv2020 } from "ajv/dist/2020.js";
|
|
@@ -129,24 +130,21 @@ function useResolvedSchema(raw) {
|
|
|
129
130
|
return useMemo(() => {
|
|
130
131
|
const schema = dereference(raw, references);
|
|
131
132
|
if (typeof schema === "boolean") return anyFields;
|
|
132
|
-
if (schema.allOf)
|
|
133
|
-
|
|
134
|
-
|
|
133
|
+
if (schema.allOf) {
|
|
134
|
+
const merged = mergeAllOf(schema, { dereference(schema) {
|
|
135
|
+
return dereference(schema, references);
|
|
136
|
+
} });
|
|
137
|
+
if (typeof merged === "boolean") return anyFields;
|
|
138
|
+
return merged;
|
|
139
|
+
}
|
|
135
140
|
return schema;
|
|
136
141
|
}, [raw, references]);
|
|
137
142
|
}
|
|
138
143
|
function dereference(schema, references) {
|
|
139
144
|
if (typeof schema === "boolean") return schema;
|
|
140
|
-
|
|
141
|
-
if (ref) {
|
|
142
|
-
if (ref.startsWith("#/")) ref = ref.slice(2);
|
|
143
|
-
if (ref in references) return references[ref];
|
|
144
|
-
}
|
|
145
|
+
if (schema.$ref) return resolveRefSync(schema.$ref, references);
|
|
145
146
|
return schema;
|
|
146
147
|
}
|
|
147
|
-
function fallbackAny(schema) {
|
|
148
|
-
return typeof schema === "boolean" ? anyFields : schema;
|
|
149
|
-
}
|
|
150
148
|
function getUnion(schema) {
|
|
151
149
|
if (schema.anyOf) return [schema.anyOf, "anyOf"];
|
|
152
150
|
if (schema.oneOf) return [schema.oneOf, "oneOf"];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.js","names":[],"sources":["../../src/playground/schema.tsx"],"sourcesContent":["import { Ajv2020 } from 'ajv/dist/2020';\nimport { createContext, ReactNode, use, useMemo } from 'react';\nimport type { ParsedSchema, ResolvedSchema } from '@/utils/schema';\nimport { mergeAllOf } from '@/utils/merge-schema';\nimport { FieldKey, useDataEngine, useFieldValue, useNamespace } from '@fumari/stf';\nimport { stringifyFieldKey } from '@fumari/stf/lib/utils';\nimport { sample } from 'openapi-sampler';\nimport { FormatFlags, schemaToString } from '@/utils/schema
|
|
1
|
+
{"version":3,"file":"schema.js","names":[],"sources":["../../src/playground/schema.tsx"],"sourcesContent":["import { Ajv2020 } from 'ajv/dist/2020';\nimport { createContext, ReactNode, use, useMemo } from 'react';\nimport type { ParsedSchema, ResolvedSchema } from '@/utils/schema';\nimport { mergeAllOf } from '@/utils/merge-schema';\nimport { FieldKey, useDataEngine, useFieldValue, useNamespace } from '@fumari/stf';\nimport { stringifyFieldKey } from '@fumari/stf/lib/utils';\nimport { sample } from 'openapi-sampler';\nimport { FormatFlags, schemaToString } from '@/utils/schema/to-string';\nimport { resolveRefSync } from '@/utils/schema/resolve-ref';\n\ninterface SchemaContextType extends SchemaScope {\n references: Record<string, ParsedSchema>;\n ajv: Ajv2020;\n}\n\nexport interface SchemaScope {\n /**\n * show write only fields\n */\n writeOnly: boolean;\n\n /**\n * show read only fields\n */\n readOnly: boolean;\n}\n\ntype UnionField = 'anyOf' | 'oneOf';\n\nexport interface FieldInfo {\n selectedType?: string;\n oneOf: number;\n\n /**\n * The actual field that represents union members.\n */\n unionField?: UnionField;\n}\n\nconst SchemaContext = createContext<SchemaContextType | undefined>(undefined);\nexport const anyFields = {\n type: ['string', 'number', 'boolean', 'array', 'object'],\n items: true,\n additionalProperties: true,\n} satisfies ParsedSchema;\n\nexport function SchemaProvider({\n references,\n readOnly,\n writeOnly,\n children,\n}: Omit<SchemaContextType, 'ajv'> & { children: ReactNode }) {\n const ajv = useMemo(\n () =>\n new Ajv2020({\n strict: false,\n validateSchema: false,\n validateFormats: false,\n }),\n [],\n );\n\n return (\n <SchemaContext.Provider\n value={useMemo(\n () => ({ references, ajv, readOnly, writeOnly }),\n [references, ajv, readOnly, writeOnly],\n )}\n >\n {children}\n </SchemaContext.Provider>\n );\n}\n\nexport function useSchemaScope(): SchemaScope {\n return use(SchemaContext)!;\n}\n\n/**\n * A hook to store dynamic info of a field, such as selected schema of `oneOf`.\n *\n * @param fieldName - field name of form.\n * @param schema - The **resolved** JSON Schema to generate initial values.\n * @param depth - The depth to avoid duplicated field name with same schema (e.g. nested `oneOf`).\n */\nexport function useFieldInfo(\n fieldName: FieldKey,\n schema: Exclude<ParsedSchema, boolean>,\n depth = 0,\n): {\n info: FieldInfo;\n schema: Exclude<ParsedSchema, boolean>;\n updateInfo: (value: Partial<FieldInfo>) => void;\n} {\n const { ajv, references } = use(SchemaContext)!;\n const engine = useDataEngine();\n const { generateDefault } = useSchemaUtils();\n const fieldData = useNamespace({\n namespace: `field-info:${depth}:${stringifyFieldKey(fieldName)}`,\n initial(): FieldInfo {\n const value = engine.get(fieldName);\n const out: FieldInfo = {\n oneOf: -1,\n };\n const union = getUnion(schema);\n if (union) {\n const [members, field] = union;\n\n out.oneOf = members.findIndex((item) =>\n ajv.validate(typeof item === 'object' ? { ...item, ...references } : item, value),\n );\n if (out.oneOf === -1) out.oneOf = 0;\n out.unionField = field;\n }\n\n if (Array.isArray(schema.type)) {\n const types = schema.type;\n\n out.selectedType =\n types.find((type) => {\n return ajv.validate({ ...schema, ...references, type }, value);\n }) ?? types[0];\n }\n\n return out;\n },\n });\n const [info, setInfo] = useFieldValue<FieldInfo>([], {\n stf: fieldData,\n });\n\n return {\n info,\n schema,\n updateInfo(value) {\n const updated = {\n ...info,\n ...value,\n };\n\n if (updated.oneOf === info.oneOf && updated.selectedType === info.selectedType) return;\n\n setInfo(updated);\n\n let valueSchema: ParsedSchema = schema;\n if (updated.unionField) {\n valueSchema = schema[updated.unionField]![updated.oneOf];\n } else if (updated.selectedType) {\n // must remove to `examples` to avoid invalid default values\n valueSchema = { ...schema, type: updated.selectedType, examples: undefined };\n }\n\n engine.update(fieldName, generateDefault(valueSchema));\n },\n };\n}\n\nexport function useSchemaUtils() {\n const { references } = use(SchemaContext)!;\n\n return {\n generateDefault(schema: ParsedSchema): unknown {\n return sample(\n schema as never,\n { skipNonRequired: true, skipReadOnly: true, quiet: true },\n references,\n );\n },\n schemaToString(value: ResolvedSchema, flags?: FormatFlags) {\n return schemaToString(\n value,\n (s) => ({ dereferenced: dereference(s, references), raw: s }),\n flags,\n );\n },\n };\n}\n\n/**\n * resolve $ref & merge `allOf`.\n */\nexport function useResolvedSchema(raw: ParsedSchema): Exclude<ParsedSchema, boolean> {\n const { references } = use(SchemaContext)!;\n\n return useMemo(() => {\n const schema = dereference(raw, references);\n if (typeof schema === 'boolean') return anyFields;\n\n if (schema.allOf) {\n const merged = mergeAllOf(schema, {\n dereference(schema) {\n return dereference(schema, references);\n },\n });\n if (typeof merged === 'boolean') return anyFields;\n return merged;\n }\n\n return schema;\n }, [raw, references]);\n}\n\nfunction dereference(schema: ParsedSchema, references: Record<string, ParsedSchema>): ParsedSchema {\n if (typeof schema === 'boolean') return schema;\n if (schema.$ref) {\n return resolveRefSync(schema.$ref, references) as ParsedSchema;\n }\n\n return schema;\n}\n\nfunction getUnion(\n schema: Exclude<ParsedSchema, boolean>,\n): [readonly ParsedSchema[], UnionField] | undefined {\n if (schema.anyOf) {\n return [schema.anyOf, 'anyOf'];\n }\n\n if (schema.oneOf) return [schema.oneOf, 'oneOf'];\n}\n"],"mappings":"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"}
|
|
@@ -2,6 +2,7 @@ import { CodeUsageGenerator } from "./index.js";
|
|
|
2
2
|
|
|
3
3
|
//#region src/requests/generators/python.d.ts
|
|
4
4
|
declare const python: CodeUsageGenerator;
|
|
5
|
+
declare function generatePythonObject(v: unknown, imports: Set<string>): string;
|
|
5
6
|
//#endregion
|
|
6
|
-
export { python };
|
|
7
|
+
export { generatePythonObject, python };
|
|
7
8
|
//# sourceMappingURL=python.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"python.d.ts","names":[],"sources":["../../../src/requests/generators/python.ts"],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"python.d.ts","names":[],"sources":["../../../src/requests/generators/python.ts"],"mappings":";;;cAGa,MAAA,EAAQ,kBAAA;AAAA,iBAuDL,oBAAA,CAAqB,CAAA,WAAY,OAAA,EAAS,GAAA"}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { resolveMediaAdapter } from "../media/resolve-adapter.js";
|
|
2
2
|
import "../media/adapter.js";
|
|
3
|
-
import { generatePythonObject } from "../to-python-object.js";
|
|
4
3
|
//#region src/requests/generators/python.ts
|
|
5
4
|
const python = {
|
|
6
5
|
label: "Python",
|
|
@@ -34,7 +33,19 @@ response = requests.request(${params.join(", ")})
|
|
|
34
33
|
print(response.text)`;
|
|
35
34
|
}
|
|
36
35
|
};
|
|
36
|
+
function generatePythonObject(v, imports) {
|
|
37
|
+
if (v === null) return "None";
|
|
38
|
+
else if (typeof v === "boolean") return v ? "True" : "False";
|
|
39
|
+
else if (typeof v === "string") return JSON.stringify(v);
|
|
40
|
+
else if (typeof v === "number") return v.toString();
|
|
41
|
+
else if (Array.isArray(v)) return `[${v.map((item) => generatePythonObject(item, imports)).join(", ")}]`;
|
|
42
|
+
else if (v instanceof Date) {
|
|
43
|
+
imports.add("datetime");
|
|
44
|
+
return `datetime.datetime(${v.getFullYear()}, ${v.getMonth() + 1}, ${v.getDate()}, ${v.getHours()}, ${v.getMinutes()}, ${v.getSeconds()}, ${v.getMilliseconds()})`;
|
|
45
|
+
} else if (typeof v === "object") return `{\n${Object.entries(v).map(([key, value]) => ` ${JSON.stringify(key)}: ${generatePythonObject(value, imports)}`).join(", \n")}\n}`;
|
|
46
|
+
else throw new Error(`Unsupported type: ${typeof v}`);
|
|
47
|
+
}
|
|
37
48
|
//#endregion
|
|
38
|
-
export { python };
|
|
49
|
+
export { generatePythonObject, python };
|
|
39
50
|
|
|
40
51
|
//# sourceMappingURL=python.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"python.js","names":[],"sources":["../../../src/requests/generators/python.ts"],"sourcesContent":["import type { CodeUsageGenerator } from '@/requests/generators';\nimport {
|
|
1
|
+
{"version":3,"file":"python.js","names":[],"sources":["../../../src/requests/generators/python.ts"],"sourcesContent":["import type { CodeUsageGenerator } from '@/requests/generators';\nimport { resolveMediaAdapter } from '@/requests/media/adapter';\n\nexport const python: CodeUsageGenerator = {\n label: 'Python',\n lang: 'python',\n generate(url, data, { mediaAdapters }) {\n const headers: Record<string, string> = {};\n const imports = new Set<string>();\n const params = [`\"${data.method}\"`, 'url'];\n let body: string | undefined;\n\n imports.add('requests');\n\n if (data.body && data.bodyMediaType) {\n const adapter = resolveMediaAdapter(data.bodyMediaType, mediaAdapters);\n headers['Content-Type'] = data.bodyMediaType;\n\n body = adapter?.generateExample(data as { body: unknown }, {\n lang: 'python',\n });\n\n if (body) {\n params.push('data = body');\n }\n }\n\n for (const [k, v] of Object.entries(data.header)) {\n headers[k] = v.value;\n }\n\n if (Object.keys(headers).length > 0) {\n params.push(`headers = ${generatePythonObject(headers, imports)}`);\n }\n\n const inputCookies = Object.entries(data.cookie);\n if (inputCookies.length > 0) {\n const cookies: Record<string, string> = {};\n\n for (const [k, v] of inputCookies) {\n cookies[k] = v.value;\n }\n\n params.push(`cookies = ${generatePythonObject(cookies, imports)}`);\n }\n\n return `${Array.from(imports)\n .map((name) => 'import ' + name)\n .join('\\n')}\n\nurl = ${JSON.stringify(url)}\n${body ?? ''}\nresponse = requests.request(${params.join(', ')})\n\nprint(response.text)`;\n },\n};\n\nexport function generatePythonObject(v: unknown, imports: Set<string>): string {\n if (v === null) {\n return 'None';\n } else if (typeof v === 'boolean') {\n return v ? 'True' : 'False';\n } else if (typeof v === 'string') {\n return JSON.stringify(v);\n } else if (typeof v === 'number') {\n return v.toString();\n } else if (Array.isArray(v)) {\n const items = v.map((item) => generatePythonObject(item, imports));\n return `[${items.join(', ')}]`;\n } else if (v instanceof Date) {\n imports.add('datetime');\n return `datetime.datetime(${v.getFullYear()}, ${v.getMonth() + 1}, ${v.getDate()}, ${v.getHours()}, ${v.getMinutes()}, ${v.getSeconds()}, ${v.getMilliseconds()})`;\n } else if (typeof v === 'object') {\n const entries = Object.entries(v).map(\n ([key, value]) => ` ${JSON.stringify(key)}: ${generatePythonObject(value, imports)}`,\n );\n return `{\\n${entries.join(', \\n')}\\n}`;\n } else {\n throw new Error(`Unsupported type: ${typeof v}`);\n }\n}\n"],"mappings":";;;AAGA,MAAa,SAA6B;CACxC,OAAO;CACP,MAAM;CACN,SAAS,KAAK,MAAM,EAAE,iBAAiB;EACrC,MAAM,UAAkC,EAAE;EAC1C,MAAM,0BAAU,IAAI,KAAa;EACjC,MAAM,SAAS,CAAC,IAAI,KAAK,OAAO,IAAI,MAAM;EAC1C,IAAI;AAEJ,UAAQ,IAAI,WAAW;AAEvB,MAAI,KAAK,QAAQ,KAAK,eAAe;GACnC,MAAM,UAAU,oBAAoB,KAAK,eAAe,cAAc;AACtE,WAAQ,kBAAkB,KAAK;AAE/B,UAAO,SAAS,gBAAgB,MAA2B,EACzD,MAAM,UACP,CAAC;AAEF,OAAI,KACF,QAAO,KAAK,cAAc;;AAI9B,OAAK,MAAM,CAAC,GAAG,MAAM,OAAO,QAAQ,KAAK,OAAO,CAC9C,SAAQ,KAAK,EAAE;AAGjB,MAAI,OAAO,KAAK,QAAQ,CAAC,SAAS,EAChC,QAAO,KAAK,aAAa,qBAAqB,SAAS,QAAQ,GAAG;EAGpE,MAAM,eAAe,OAAO,QAAQ,KAAK,OAAO;AAChD,MAAI,aAAa,SAAS,GAAG;GAC3B,MAAM,UAAkC,EAAE;AAE1C,QAAK,MAAM,CAAC,GAAG,MAAM,aACnB,SAAQ,KAAK,EAAE;AAGjB,UAAO,KAAK,aAAa,qBAAqB,SAAS,QAAQ,GAAG;;AAGpE,SAAO,GAAG,MAAM,KAAK,QAAQ,CAC1B,KAAK,SAAS,YAAY,KAAK,CAC/B,KAAK,KAAK,CAAC;;QAEV,KAAK,UAAU,IAAI,CAAC;EAC1B,QAAQ,GAAG;8BACiB,OAAO,KAAK,KAAK,CAAC;;;;CAI/C;AAED,SAAgB,qBAAqB,GAAY,SAA8B;AAC7E,KAAI,MAAM,KACR,QAAO;UACE,OAAO,MAAM,UACtB,QAAO,IAAI,SAAS;UACX,OAAO,MAAM,SACtB,QAAO,KAAK,UAAU,EAAE;UACf,OAAO,MAAM,SACtB,QAAO,EAAE,UAAU;UACV,MAAM,QAAQ,EAAE,CAEzB,QAAO,IADO,EAAE,KAAK,SAAS,qBAAqB,MAAM,QAAQ,CAAC,CACjD,KAAK,KAAK,CAAC;UACnB,aAAa,MAAM;AAC5B,UAAQ,IAAI,WAAW;AACvB,SAAO,qBAAqB,EAAE,aAAa,CAAC,IAAI,EAAE,UAAU,GAAG,EAAE,IAAI,EAAE,SAAS,CAAC,IAAI,EAAE,UAAU,CAAC,IAAI,EAAE,YAAY,CAAC,IAAI,EAAE,YAAY,CAAC,IAAI,EAAE,iBAAiB,CAAC;YACvJ,OAAO,MAAM,SAItB,QAAO,MAHS,OAAO,QAAQ,EAAE,CAAC,KAC/B,CAAC,KAAK,WAAW,KAAK,KAAK,UAAU,IAAI,CAAC,IAAI,qBAAqB,OAAO,QAAQ,GACpF,CACoB,KAAK,OAAO,CAAC;KAElC,OAAM,IAAI,MAAM,qBAAqB,OAAO,IAAI"}
|
package/dist/scalar/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../../src/scalar/index.tsx"],"mappings":";;;;;AAuBA
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../../src/scalar/index.tsx"],"mappings":";;;;;AAuBA;;;iBAAgB,UAAA,CAAW,OAAA,GAAS,oBAAA,GAA4B,oBAAA"}
|
package/dist/server/create.d.ts
CHANGED
|
@@ -27,6 +27,8 @@ interface OpenAPIServer {
|
|
|
27
27
|
createProxy: typeof createProxy;
|
|
28
28
|
getSchemas: () => Promise<ProcessedSchemaMap>;
|
|
29
29
|
getSchema: (document: string) => Promise<ProcessedDocument>;
|
|
30
|
+
/** @private internal API */
|
|
31
|
+
_getWatchPaths: () => string[];
|
|
30
32
|
readonly options: OpenAPIOptions;
|
|
31
33
|
}
|
|
32
34
|
declare function createOpenAPI(options?: OpenAPIOptions): OpenAPIServer;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create.d.ts","names":[],"sources":["../../src/server/create.ts"],"mappings":";;;;;;;;AAGsE;
|
|
1
|
+
{"version":3,"file":"create.d.ts","names":[],"sources":["../../src/server/create.ts"],"mappings":";;;;;;;;AAGsE;KAMjE,SAAA,GAAY,MAAA,kBAAwB,QAAA;AAAA,KACpC,kBAAA,GAAqB,MAAA,SAAe,iBAAA;AAAA,UAExB,cAAA;EAHgC;AAAA;;;;;EAU/C,KAAA,qBAA0B,SAAA,GAAY,OAAA,CAAQ,SAAA;EAE9C,YAAA;;;;EAKA,QAAA;AAAA;AAAA,UAGe,aAAA;EACf,WAAA,SAAoB,WAAA;EACpB,UAAA,QAAkB,OAAA,CAAQ,kBAAA;EAC1B,SAAA,GAAY,QAAA,aAAqB,OAAA,CAAQ,iBAAA;EAbK;EAe9C,cAAA;EAAA,SACS,OAAA,EAAS,cAAA;AAAA;AAAA,iBAGJ,aAAA,CAAc,OAAA,GAAS,cAAA,GAAsB,aAAA;AAT7D;;;AAAA,iBAuDgB,gBAAA,GAAA,CACd,OAAA,EAAS,wBAAA,CAAyB,CAAA,IACjC,wBAAA,CAAyB,CAAA"}
|
package/dist/server/create.js
CHANGED
|
@@ -1,22 +1,25 @@
|
|
|
1
1
|
import { createProxy } from "./proxy.js";
|
|
2
2
|
import { processDocument } from "../utils/process-document.js";
|
|
3
|
+
import fs from "node:fs";
|
|
3
4
|
//#region src/server/create.ts
|
|
4
5
|
function createOpenAPI(options = {}) {
|
|
5
6
|
const { input = [], disableCache = false } = options;
|
|
6
7
|
let schemas;
|
|
7
8
|
async function getSchemas() {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
}
|
|
15
|
-
return out;
|
|
9
|
+
if (Array.isArray(input)) {
|
|
10
|
+
const entries = await Promise.all(input.map(async (item) => [item, await processDocument(item)]));
|
|
11
|
+
return Object.fromEntries(entries);
|
|
12
|
+
} else {
|
|
13
|
+
const entries = await Promise.all(Object.entries(await input()).map(async ([k, v]) => [k, await processDocument(v)]));
|
|
14
|
+
return Object.fromEntries(entries);
|
|
15
|
+
}
|
|
16
16
|
}
|
|
17
17
|
return {
|
|
18
18
|
options,
|
|
19
19
|
createProxy,
|
|
20
|
+
_getWatchPaths() {
|
|
21
|
+
return (Array.isArray(input) ? input : Object.keys(input)).filter((key) => !URL.canParse(key) && fs.existsSync(key));
|
|
22
|
+
},
|
|
20
23
|
async getSchema(document) {
|
|
21
24
|
const schemas = await this.getSchemas();
|
|
22
25
|
if (document in schemas) return schemas[document];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create.js","names":[],"sources":["../../src/server/create.ts"],"sourcesContent":["import { createProxy } from '@/server/proxy';\nimport { processDocument, type ProcessedDocument } from '@/utils/process-document';\nimport type { Document } from '@/types';\nimport type { InlineCodeUsageGenerator } from '@/requests/generators';\n\n/**\n * schema id -> file path, URL, or downloaded schema object\n */\ntype SchemaMap = Record<string, string | Document>;\ntype ProcessedSchemaMap = Record<string, ProcessedDocument>;\n\nexport interface OpenAPIOptions {\n /**\n * Schema files, can be:\n * - URL\n * - file path\n * - a function returning records of downloaded schemas.\n */\n input?: string[] | (() => SchemaMap | Promise<SchemaMap>);\n\n disableCache?: boolean;\n\n /**\n * The url of proxy to avoid CORS issues\n */\n proxyUrl?: string;\n}\n\nexport interface OpenAPIServer {\n createProxy: typeof createProxy;\n getSchemas: () => Promise<ProcessedSchemaMap>;\n getSchema: (document: string) => Promise<ProcessedDocument>;\n readonly options: OpenAPIOptions;\n}\n\nexport function createOpenAPI(options: OpenAPIOptions = {}): OpenAPIServer {\n const { input = [], disableCache = false } = options;\n let schemas: Promise<ProcessedSchemaMap> | undefined;\n\n async function getSchemas()
|
|
1
|
+
{"version":3,"file":"create.js","names":[],"sources":["../../src/server/create.ts"],"sourcesContent":["import { createProxy } from '@/server/proxy';\nimport { processDocument, type ProcessedDocument } from '@/utils/process-document';\nimport type { Document } from '@/types';\nimport type { InlineCodeUsageGenerator } from '@/requests/generators';\nimport fs from 'node:fs';\n\n/**\n * schema id -> file path, URL, or downloaded schema object\n */\ntype SchemaMap = Record<string, string | Document>;\ntype ProcessedSchemaMap = Record<string, ProcessedDocument>;\n\nexport interface OpenAPIOptions {\n /**\n * Schema files, can be:\n * - URL\n * - file path\n * - a function returning records of downloaded schemas.\n */\n input?: string[] | (() => SchemaMap | Promise<SchemaMap>);\n\n disableCache?: boolean;\n\n /**\n * The url of proxy to avoid CORS issues\n */\n proxyUrl?: string;\n}\n\nexport interface OpenAPIServer {\n createProxy: typeof createProxy;\n getSchemas: () => Promise<ProcessedSchemaMap>;\n getSchema: (document: string) => Promise<ProcessedDocument>;\n /** @private internal API */\n _getWatchPaths: () => string[];\n readonly options: OpenAPIOptions;\n}\n\nexport function createOpenAPI(options: OpenAPIOptions = {}): OpenAPIServer {\n const { input = [], disableCache = false } = options;\n let schemas: Promise<ProcessedSchemaMap> | undefined;\n\n async function getSchemas(): Promise<ProcessedSchemaMap> {\n if (Array.isArray(input)) {\n const entries = await Promise.all(\n input.map(async (item) => [item, await processDocument(item)]),\n );\n return Object.fromEntries(entries);\n } else {\n const entries = await Promise.all(\n Object.entries(await input()).map(async ([k, v]) => [k, await processDocument(v)]),\n );\n return Object.fromEntries(entries);\n }\n }\n\n return {\n options,\n createProxy,\n _getWatchPaths() {\n const keys = Array.isArray(input) ? input : Object.keys(input);\n return keys.filter((key) => !URL.canParse(key) && fs.existsSync(key));\n },\n async getSchema(document) {\n const schemas = await this.getSchemas();\n if (document in schemas) return schemas[document];\n\n console.warn(\n `[Fumadocs OpenAPI] the document \"${document}\" is not listed in the input array, this may not be expected.`,\n );\n // do not cache unlisted documents\n return processDocument(document);\n },\n async getSchemas() {\n if (disableCache) return getSchemas();\n\n return (schemas ??= getSchemas());\n },\n };\n}\n\n/**\n * @deprecated\n */\nexport function createCodeSample<T>(\n options: InlineCodeUsageGenerator<T>,\n): InlineCodeUsageGenerator<T> {\n return options;\n}\n"],"mappings":";;;;AAsCA,SAAgB,cAAc,UAA0B,EAAE,EAAiB;CACzE,MAAM,EAAE,QAAQ,EAAE,EAAE,eAAe,UAAU;CAC7C,IAAI;CAEJ,eAAe,aAA0C;AACvD,MAAI,MAAM,QAAQ,MAAM,EAAE;GACxB,MAAM,UAAU,MAAM,QAAQ,IAC5B,MAAM,IAAI,OAAO,SAAS,CAAC,MAAM,MAAM,gBAAgB,KAAK,CAAC,CAAC,CAC/D;AACD,UAAO,OAAO,YAAY,QAAQ;SAC7B;GACL,MAAM,UAAU,MAAM,QAAQ,IAC5B,OAAO,QAAQ,MAAM,OAAO,CAAC,CAAC,IAAI,OAAO,CAAC,GAAG,OAAO,CAAC,GAAG,MAAM,gBAAgB,EAAE,CAAC,CAAC,CACnF;AACD,UAAO,OAAO,YAAY,QAAQ;;;AAItC,QAAO;EACL;EACA;EACA,iBAAiB;AAEf,WADa,MAAM,QAAQ,MAAM,GAAG,QAAQ,OAAO,KAAK,MAAM,EAClD,QAAQ,QAAQ,CAAC,IAAI,SAAS,IAAI,IAAI,GAAG,WAAW,IAAI,CAAC;;EAEvE,MAAM,UAAU,UAAU;GACxB,MAAM,UAAU,MAAM,KAAK,YAAY;AACvC,OAAI,YAAY,QAAS,QAAO,QAAQ;AAExC,WAAQ,KACN,oCAAoC,SAAS,+DAC9C;AAED,UAAO,gBAAgB,SAAS;;EAElC,MAAM,aAAa;AACjB,OAAI,aAAc,QAAO,YAAY;AAErC,UAAQ,YAAY,YAAY;;EAEnC;;;;;AAMH,SAAgB,iBACd,SAC6B;AAC7B,QAAO"}
|
package/dist/server/proxy.d.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
//#region src/server/proxy.d.ts
|
|
2
|
-
declare const
|
|
3
|
-
type
|
|
2
|
+
declare const methods: readonly ["GET", "POST", "PUT", "DELETE", "PATCH", "HEAD"];
|
|
3
|
+
type Handler = (req: Request) => Promise<Response>;
|
|
4
|
+
interface Proxy extends Record<(typeof methods)[number], Handler> {
|
|
5
|
+
handle: Handler;
|
|
6
|
+
}
|
|
4
7
|
interface CreateProxyOptions {
|
|
5
8
|
/**
|
|
6
9
|
* Filter by prefixes of request url
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"proxy.d.ts","names":[],"sources":["../../src/server/proxy.ts"],"mappings":";cAAM,
|
|
1
|
+
{"version":3,"file":"proxy.d.ts","names":[],"sources":["../../src/server/proxy.ts"],"mappings":";cAAM,OAAA;AAAA,KAGD,OAAA,IAAW,GAAA,EAAK,OAAA,KAAY,OAAA,CAAQ,QAAA;AAAA,UAExB,KAAA,SAAc,MAAA,SAAe,OAAA,WAAkB,OAAA;EAC9D,MAAA,EAAQ,OAAA;AAAA;AAAA,UAGO,kBAAA;EANZ;;;;;EAYH,WAAA;EAZsC;;;EAiBtC,cAAA;EAjB+B;;;;AAEjC;EAsBE,aAAA,IAAiB,OAAA,EAAS,OAAA;;;;EAK1B,SAAA;IACE,OAAA,IAAW,OAAA,EAAS,OAAA,KAAY,OAAA;IAChC,QAAA,IAAY,QAAA,EAAU,QAAA,KAAa,QAAA;EAAA;AAAA;AAAA,iBAIvB,WAAA,CAAY,OAAA,GAAS,kBAAA,GAA0B,KAAA"}
|
package/dist/server/proxy.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
//#region src/server/proxy.ts
|
|
2
|
-
const
|
|
2
|
+
const methods = [
|
|
3
3
|
"GET",
|
|
4
4
|
"POST",
|
|
5
5
|
"PUT",
|
|
@@ -7,50 +7,60 @@ const keys = [
|
|
|
7
7
|
"PATCH",
|
|
8
8
|
"HEAD"
|
|
9
9
|
];
|
|
10
|
+
const methodsWithBody = new Set([
|
|
11
|
+
"POST",
|
|
12
|
+
"PUT",
|
|
13
|
+
"PATCH",
|
|
14
|
+
"DELETE"
|
|
15
|
+
]);
|
|
10
16
|
function createProxy(options = {}) {
|
|
11
17
|
const { allowedOrigins, allowedUrls, filterRequest = (req) => {
|
|
12
18
|
return !allowedUrls || allowedUrls.some((item) => req.url.startsWith(item));
|
|
13
19
|
}, overrides } = options;
|
|
14
|
-
const handlers = {};
|
|
20
|
+
const handlers = { handle: handler };
|
|
15
21
|
async function handler(req) {
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
if (
|
|
21
|
-
|
|
22
|
+
const searchParams = new URL(req.url).searchParams;
|
|
23
|
+
const rawUrl = searchParams.get("url");
|
|
24
|
+
if (!rawUrl) return Response.json("[Proxy] A `url` query parameter is required for proxy url", { status: 400 });
|
|
25
|
+
const targetUrl = URL.parse(rawUrl);
|
|
26
|
+
if (!targetUrl) return Response.json("[Proxy] Invalid `url` parameter value.", { status: 400 });
|
|
27
|
+
if (allowedOrigins && !allowedOrigins.includes(targetUrl.origin)) return Response.json(`[Proxy] The origin "${targetUrl.origin}" is not allowed.`, { status: 400 });
|
|
28
|
+
const proxied = await rewriteRequest(req, targetUrl, searchParams.get("cookie"));
|
|
29
|
+
if (!filterRequest(proxied)) return Response.json("[Proxy] The proxied request is not allowed", { status: 403 });
|
|
30
|
+
try {
|
|
31
|
+
return rewriteResponse(await fetch(proxied));
|
|
32
|
+
} catch (err) {
|
|
33
|
+
return Response.json(`[Proxy] Failed to proxy request: ${err instanceof Error ? err.message : "unknown reason"}`, { status: 500 });
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
async function rewriteRequest(request, url, cookie) {
|
|
37
|
+
const headers = new Headers(request.headers);
|
|
38
|
+
headers.delete("origin");
|
|
39
|
+
if (cookie) headers.set("Cookie", cookie);
|
|
40
|
+
const contentLength = headers.get("content-length");
|
|
22
41
|
const hasBody = contentLength && parseInt(contentLength) > 0;
|
|
23
|
-
|
|
24
|
-
method:
|
|
42
|
+
const proxied = new Request(url, {
|
|
43
|
+
method: request.method,
|
|
25
44
|
cache: "no-cache",
|
|
26
|
-
headers
|
|
27
|
-
body: hasBody &&
|
|
28
|
-
"POST",
|
|
29
|
-
"PUT",
|
|
30
|
-
"PATCH",
|
|
31
|
-
"DELETE"
|
|
32
|
-
].includes(req.method.toUpperCase()) ? await req.arrayBuffer() : void 0
|
|
33
|
-
});
|
|
34
|
-
if (overrides?.request) proxied = overrides.request(proxied);
|
|
35
|
-
if (!filterRequest(proxied)) return Response.json("[Proxy] The proxied request is not allowed", { status: 403 });
|
|
36
|
-
proxied.headers.forEach((_value, originalKey) => {
|
|
37
|
-
if (originalKey.toLowerCase() === "origin") proxied.headers.delete(originalKey);
|
|
45
|
+
headers,
|
|
46
|
+
body: hasBody && methodsWithBody.has(request.method.toUpperCase()) ? await request.arrayBuffer() : void 0
|
|
38
47
|
});
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
48
|
+
return overrides?.request ? overrides.request(proxied) : proxied;
|
|
49
|
+
}
|
|
50
|
+
async function rewriteResponse(response) {
|
|
51
|
+
if (overrides?.response) response = overrides.response(response);
|
|
52
|
+
const headers = new Headers(response.headers);
|
|
43
53
|
headers.forEach((_value, originalKey) => {
|
|
44
54
|
if (originalKey.toLowerCase().startsWith("access-control-")) headers.delete(originalKey);
|
|
45
55
|
});
|
|
46
|
-
headers.set("X-Forwarded-Host",
|
|
47
|
-
return new Response(
|
|
48
|
-
status:
|
|
49
|
-
statusText:
|
|
56
|
+
headers.set("X-Forwarded-Host", response.url);
|
|
57
|
+
return new Response(response.body, {
|
|
58
|
+
status: response.status,
|
|
59
|
+
statusText: response.statusText,
|
|
50
60
|
headers
|
|
51
61
|
});
|
|
52
62
|
}
|
|
53
|
-
for (const key of
|
|
63
|
+
for (const key of methods) handlers[key] = handler;
|
|
54
64
|
return handlers;
|
|
55
65
|
}
|
|
56
66
|
//#endregion
|
package/dist/server/proxy.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"proxy.js","names":[],"sources":["../../src/server/proxy.ts"],"sourcesContent":["const
|
|
1
|
+
{"version":3,"file":"proxy.js","names":[],"sources":["../../src/server/proxy.ts"],"sourcesContent":["const methods = ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD'] as const;\nconst methodsWithBody = new Set(['POST', 'PUT', 'PATCH', 'DELETE']);\n\ntype Handler = (req: Request) => Promise<Response>;\n\nexport interface Proxy extends Record<(typeof methods)[number], Handler> {\n handle: Handler;\n}\n\nexport interface CreateProxyOptions {\n /**\n * Filter by prefixes of request url\n *\n * @deprecated Use `allowedOrigins` for filtering origins, or `filterRequest` for more detailed rules.\n */\n allowedUrls?: string[];\n\n /**\n * List of allowed origins to proxy to.\n */\n allowedOrigins?: string[];\n\n /**\n * Determine if the proxied request is allowed.\n *\n * @returns true if allowed, otherwise forbidden.\n */\n filterRequest?: (request: Request) => boolean;\n\n /**\n * Override proxied request/response with yours\n */\n overrides?: {\n request?: (request: Request) => Request;\n response?: (response: Response) => Response;\n };\n}\n\nexport function createProxy(options: CreateProxyOptions = {}): Proxy {\n const {\n allowedOrigins,\n allowedUrls,\n filterRequest = (req) => {\n return !allowedUrls || allowedUrls.some((item) => req.url.startsWith(item));\n },\n overrides,\n } = options;\n const handlers: Partial<Proxy> = {\n handle: handler,\n };\n\n async function handler(req: Request): Promise<Response> {\n const searchParams = new URL(req.url).searchParams;\n const rawUrl = searchParams.get('url');\n\n if (!rawUrl)\n return Response.json('[Proxy] A `url` query parameter is required for proxy url', {\n status: 400,\n });\n\n const targetUrl = URL.parse(rawUrl);\n if (!targetUrl)\n return Response.json('[Proxy] Invalid `url` parameter value.', {\n status: 400,\n });\n\n if (allowedOrigins && !allowedOrigins.includes(targetUrl.origin)) {\n return Response.json(`[Proxy] The origin \"${targetUrl.origin}\" is not allowed.`, {\n status: 400,\n });\n }\n\n const proxied = await rewriteRequest(req, targetUrl, searchParams.get('cookie'));\n\n if (!filterRequest(proxied)) {\n return Response.json('[Proxy] The proxied request is not allowed', {\n status: 403,\n });\n }\n\n try {\n return rewriteResponse(await fetch(proxied));\n } catch (err) {\n return Response.json(\n `[Proxy] Failed to proxy request: ${err instanceof Error ? err.message : 'unknown reason'}`,\n {\n status: 500,\n },\n );\n }\n }\n\n async function rewriteRequest(\n request: Request,\n url: URL,\n cookie: string | null,\n ): Promise<Request> {\n const headers = new Headers(request.headers);\n headers.delete('origin');\n if (cookie) {\n headers.set('Cookie', cookie);\n }\n\n const contentLength = headers.get('content-length');\n const hasBody = contentLength && parseInt(contentLength) > 0;\n\n const proxied = new Request(url, {\n method: request.method,\n cache: 'no-cache',\n headers,\n body:\n hasBody && methodsWithBody.has(request.method.toUpperCase())\n ? await request.arrayBuffer()\n : undefined,\n });\n\n return overrides?.request ? overrides.request(proxied) : proxied;\n }\n\n async function rewriteResponse(response: Response): Promise<Response> {\n if (overrides?.response) {\n response = overrides.response(response);\n }\n\n const headers = new Headers(response.headers);\n headers.forEach((_value, originalKey) => {\n const key = originalKey.toLowerCase();\n\n if (key.startsWith('access-control-')) {\n headers.delete(originalKey);\n }\n });\n headers.set('X-Forwarded-Host', response.url);\n\n return new Response(response.body, {\n status: response.status,\n statusText: response.statusText,\n headers,\n });\n }\n\n for (const key of methods) {\n handlers[key] = handler;\n }\n\n return handlers as Proxy;\n}\n"],"mappings":";AAAA,MAAM,UAAU;CAAC;CAAO;CAAQ;CAAO;CAAU;CAAS;CAAO;AACjE,MAAM,kBAAkB,IAAI,IAAI;CAAC;CAAQ;CAAO;CAAS;CAAS,CAAC;AAqCnE,SAAgB,YAAY,UAA8B,EAAE,EAAS;CACnE,MAAM,EACJ,gBACA,aACA,iBAAiB,QAAQ;AACvB,SAAO,CAAC,eAAe,YAAY,MAAM,SAAS,IAAI,IAAI,WAAW,KAAK,CAAC;IAE7E,cACE;CACJ,MAAM,WAA2B,EAC/B,QAAQ,SACT;CAED,eAAe,QAAQ,KAAiC;EACtD,MAAM,eAAe,IAAI,IAAI,IAAI,IAAI,CAAC;EACtC,MAAM,SAAS,aAAa,IAAI,MAAM;AAEtC,MAAI,CAAC,OACH,QAAO,SAAS,KAAK,6DAA6D,EAChF,QAAQ,KACT,CAAC;EAEJ,MAAM,YAAY,IAAI,MAAM,OAAO;AACnC,MAAI,CAAC,UACH,QAAO,SAAS,KAAK,0CAA0C,EAC7D,QAAQ,KACT,CAAC;AAEJ,MAAI,kBAAkB,CAAC,eAAe,SAAS,UAAU,OAAO,CAC9D,QAAO,SAAS,KAAK,uBAAuB,UAAU,OAAO,oBAAoB,EAC/E,QAAQ,KACT,CAAC;EAGJ,MAAM,UAAU,MAAM,eAAe,KAAK,WAAW,aAAa,IAAI,SAAS,CAAC;AAEhF,MAAI,CAAC,cAAc,QAAQ,CACzB,QAAO,SAAS,KAAK,8CAA8C,EACjE,QAAQ,KACT,CAAC;AAGJ,MAAI;AACF,UAAO,gBAAgB,MAAM,MAAM,QAAQ,CAAC;WACrC,KAAK;AACZ,UAAO,SAAS,KACd,oCAAoC,eAAe,QAAQ,IAAI,UAAU,oBACzE,EACE,QAAQ,KACT,CACF;;;CAIL,eAAe,eACb,SACA,KACA,QACkB;EAClB,MAAM,UAAU,IAAI,QAAQ,QAAQ,QAAQ;AAC5C,UAAQ,OAAO,SAAS;AACxB,MAAI,OACF,SAAQ,IAAI,UAAU,OAAO;EAG/B,MAAM,gBAAgB,QAAQ,IAAI,iBAAiB;EACnD,MAAM,UAAU,iBAAiB,SAAS,cAAc,GAAG;EAE3D,MAAM,UAAU,IAAI,QAAQ,KAAK;GAC/B,QAAQ,QAAQ;GAChB,OAAO;GACP;GACA,MACE,WAAW,gBAAgB,IAAI,QAAQ,OAAO,aAAa,CAAC,GACxD,MAAM,QAAQ,aAAa,GAC3B,KAAA;GACP,CAAC;AAEF,SAAO,WAAW,UAAU,UAAU,QAAQ,QAAQ,GAAG;;CAG3D,eAAe,gBAAgB,UAAuC;AACpE,MAAI,WAAW,SACb,YAAW,UAAU,SAAS,SAAS;EAGzC,MAAM,UAAU,IAAI,QAAQ,SAAS,QAAQ;AAC7C,UAAQ,SAAS,QAAQ,gBAAgB;AAGvC,OAFY,YAAY,aAAa,CAE7B,WAAW,kBAAkB,CACnC,SAAQ,OAAO,YAAY;IAE7B;AACF,UAAQ,IAAI,oBAAoB,SAAS,IAAI;AAE7C,SAAO,IAAI,SAAS,SAAS,MAAM;GACjC,QAAQ,SAAS;GACjB,YAAY,SAAS;GACrB;GACD,CAAC;;AAGJ,MAAK,MAAM,OAAO,QAChB,UAAS,OAAO;AAGlB,QAAO"}
|