mirror of
https://github.com/GitbookIO/gitbook.git
synced 2026-09-21 01:53:26 +00:00
Adapt OpenAPI to eval adaptive exprs & prefill TryIt config (#3607)
This commit is contained in:
@@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
"@gitbook/react-openapi": minor
|
||||||
|
"gitbook": minor
|
||||||
|
"@gitbook/openapi-parser": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Adapt OpenAPI blocks to eval adaptive exprs & prefill TryIt config
|
||||||
@@ -99,6 +99,7 @@
|
|||||||
"@gitbook/cache-tags": "workspace:*",
|
"@gitbook/cache-tags": "workspace:*",
|
||||||
"@gitbook/colors": "workspace:*",
|
"@gitbook/colors": "workspace:*",
|
||||||
"@gitbook/emoji-codepoints": "workspace:*",
|
"@gitbook/emoji-codepoints": "workspace:*",
|
||||||
|
"@gitbook/expr": "workspace:*",
|
||||||
"@gitbook/fonts": "workspace:*",
|
"@gitbook/fonts": "workspace:*",
|
||||||
"@gitbook/icons": "workspace:*",
|
"@gitbook/icons": "workspace:*",
|
||||||
"@gitbook/openapi-parser": "workspace:*",
|
"@gitbook/openapi-parser": "workspace:*",
|
||||||
@@ -262,9 +263,11 @@
|
|||||||
"name": "@gitbook/react-openapi",
|
"name": "@gitbook/react-openapi",
|
||||||
"version": "1.3.6",
|
"version": "1.3.6",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@gitbook/expr": "workspace:*",
|
||||||
"@gitbook/openapi-parser": "workspace:*",
|
"@gitbook/openapi-parser": "workspace:*",
|
||||||
"@scalar/api-client-react": "^1.3.16",
|
"@scalar/api-client-react": "^1.3.16",
|
||||||
"@scalar/oas-utils": "^0.2.130",
|
"@scalar/oas-utils": "^0.2.130",
|
||||||
|
"@scalar/types": "^0.1.9",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"flatted": "^3.2.9",
|
"flatted": "^3.2.9",
|
||||||
"js-yaml": "^4.1.0",
|
"js-yaml": "^4.1.0",
|
||||||
@@ -1173,7 +1176,7 @@
|
|||||||
|
|
||||||
"@scalar/themes": ["@scalar/themes@0.9.86", "", { "dependencies": { "@scalar/types": "0.1.7" } }, "sha512-QUHo9g5oSWi+0Lm1vJY9TaMZRau8LHg+vte7q5BVTBnu6NuQfigCaN+ouQ73FqIVd96TwMO6Db+dilK1B+9row=="],
|
"@scalar/themes": ["@scalar/themes@0.9.86", "", { "dependencies": { "@scalar/types": "0.1.7" } }, "sha512-QUHo9g5oSWi+0Lm1vJY9TaMZRau8LHg+vte7q5BVTBnu6NuQfigCaN+ouQ73FqIVd96TwMO6Db+dilK1B+9row=="],
|
||||||
|
|
||||||
"@scalar/types": ["@scalar/types@0.2.3", "", { "dependencies": { "@scalar/openapi-types": "0.3.3", "nanoid": "^5.1.5", "zod": "3.24.1" } }, "sha512-K1/Vp5xaQ8TEGDYwHg88OBuQWJRWrE3ToZ0Z2LJwskcY1Eg+uDiRQXKF4QPngZzu5rrWgRErAq4yte4Y7omqgA=="],
|
"@scalar/types": ["@scalar/types@0.1.16", "", { "dependencies": { "@scalar/openapi-types": "0.2.3", "nanoid": "^5.1.5", "zod": "3.24.1" } }, "sha512-v1L96F8Inn27NUw5Xcl0iifw3SOX0R9WBV6GeswR23s8i1SJz7UiLEi8rLOqOB5DiLtC8hDK0kNl4TKn7MNJWQ=="],
|
||||||
|
|
||||||
"@scalar/use-codemirror": ["@scalar/use-codemirror@0.12.13", "", { "dependencies": { "@codemirror/autocomplete": "^6.18.3", "@codemirror/commands": "^6.7.1", "@codemirror/lang-css": "^6.3.1", "@codemirror/lang-html": "^6.4.8", "@codemirror/lang-json": "^6.0.0", "@codemirror/lang-xml": "^6.0.0", "@codemirror/lang-yaml": "^6.1.2", "@codemirror/language": "^6.10.7", "@codemirror/lint": "^6.8.4", "@codemirror/state": "^6.5.0", "@codemirror/view": "^6.35.3", "@lezer/common": "^1.2.3", "@lezer/highlight": "^1.2.1", "@replit/codemirror-css-color-picker": "^6.3.0", "@scalar/components": "0.14.12", "codemirror": "^6.0.0", "vue": "^3.5.12" } }, "sha512-XOXCUT3b1l0gkp4CY51e7xMgR6IP/AMpYIZ97fBOOjnrUIJ8B/J+U/BMS6+lPKiN0hexaSALRWlVBf90txdT8w=="],
|
"@scalar/use-codemirror": ["@scalar/use-codemirror@0.12.13", "", { "dependencies": { "@codemirror/autocomplete": "^6.18.3", "@codemirror/commands": "^6.7.1", "@codemirror/lang-css": "^6.3.1", "@codemirror/lang-html": "^6.4.8", "@codemirror/lang-json": "^6.0.0", "@codemirror/lang-xml": "^6.0.0", "@codemirror/lang-yaml": "^6.1.2", "@codemirror/language": "^6.10.7", "@codemirror/lint": "^6.8.4", "@codemirror/state": "^6.5.0", "@codemirror/view": "^6.35.3", "@lezer/common": "^1.2.3", "@lezer/highlight": "^1.2.1", "@replit/codemirror-css-color-picker": "^6.3.0", "@scalar/components": "0.14.12", "codemirror": "^6.0.0", "vue": "^3.5.12" } }, "sha512-XOXCUT3b1l0gkp4CY51e7xMgR6IP/AMpYIZ97fBOOjnrUIJ8B/J+U/BMS6+lPKiN0hexaSALRWlVBf90txdT8w=="],
|
||||||
|
|
||||||
@@ -3963,10 +3966,14 @@
|
|||||||
|
|
||||||
"@scalar/api-client/@scalar/themes": ["@scalar/themes@0.13.4", "", { "dependencies": { "@scalar/types": "0.2.3", "nanoid": "^5.1.5" } }, "sha512-PMiSqX+MZF29u32ogEjTVA5c/LBd5cE/QPF7lK0EJeemXRy2r/nWbvrXtqD9Y7Sw54g1caVNjK8yJcCYJdB6hw=="],
|
"@scalar/api-client/@scalar/themes": ["@scalar/themes@0.13.4", "", { "dependencies": { "@scalar/types": "0.2.3", "nanoid": "^5.1.5" } }, "sha512-PMiSqX+MZF29u32ogEjTVA5c/LBd5cE/QPF7lK0EJeemXRy2r/nWbvrXtqD9Y7Sw54g1caVNjK8yJcCYJdB6hw=="],
|
||||||
|
|
||||||
|
"@scalar/api-client/@scalar/types": ["@scalar/types@0.2.3", "", { "dependencies": { "@scalar/openapi-types": "0.3.3", "nanoid": "^5.1.5", "zod": "3.24.1" } }, "sha512-K1/Vp5xaQ8TEGDYwHg88OBuQWJRWrE3ToZ0Z2LJwskcY1Eg+uDiRQXKF4QPngZzu5rrWgRErAq4yte4Y7omqgA=="],
|
||||||
|
|
||||||
"@scalar/api-client/pretty-ms": ["pretty-ms@8.0.0", "", { "dependencies": { "parse-ms": "^3.0.0" } }, "sha512-ASJqOugUF1bbzI35STMBUpZqdfYKlJugy6JBziGi2EE+AL5JPJGSzvpeVXojxrr0ViUYoToUjb5kjSEGf7Y83Q=="],
|
"@scalar/api-client/pretty-ms": ["pretty-ms@8.0.0", "", { "dependencies": { "parse-ms": "^3.0.0" } }, "sha512-ASJqOugUF1bbzI35STMBUpZqdfYKlJugy6JBziGi2EE+AL5JPJGSzvpeVXojxrr0ViUYoToUjb5kjSEGf7Y83Q=="],
|
||||||
|
|
||||||
"@scalar/api-client/zod": ["zod@3.24.1", "", {}, "sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A=="],
|
"@scalar/api-client/zod": ["zod@3.24.1", "", {}, "sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A=="],
|
||||||
|
|
||||||
|
"@scalar/api-client-react/@scalar/types": ["@scalar/types@0.2.3", "", { "dependencies": { "@scalar/openapi-types": "0.3.3", "nanoid": "^5.1.5", "zod": "3.24.1" } }, "sha512-K1/Vp5xaQ8TEGDYwHg88OBuQWJRWrE3ToZ0Z2LJwskcY1Eg+uDiRQXKF4QPngZzu5rrWgRErAq4yte4Y7omqgA=="],
|
||||||
|
|
||||||
"@scalar/components/@scalar/oas-utils": ["@scalar/oas-utils@0.4.7", "", { "dependencies": { "@hyperjump/browser": "^1.1.0", "@hyperjump/json-schema": "^1.9.6", "@scalar/helpers": "0.0.4", "@scalar/object-utils": "1.2.1", "@scalar/openapi-types": "0.3.3", "@scalar/themes": "0.13.4", "@scalar/types": "0.2.3", "@types/har-format": "^1.2.15", "flatted": "^3.3.1", "microdiff": "^1.4.0", "nanoid": "^5.1.5", "type-fest": "^4.20.0", "yaml": "^2.4.5", "zod": "3.24.1" } }, "sha512-Vp8iZZCjNKXcPpL0Yr6dmy+VOSN1LZ5CdlGAHtp+pxuQTeahV6FxiVjMc9kdFve77fTNyut4seVAD6d7rDUDcA=="],
|
"@scalar/components/@scalar/oas-utils": ["@scalar/oas-utils@0.4.7", "", { "dependencies": { "@hyperjump/browser": "^1.1.0", "@hyperjump/json-schema": "^1.9.6", "@scalar/helpers": "0.0.4", "@scalar/object-utils": "1.2.1", "@scalar/openapi-types": "0.3.3", "@scalar/themes": "0.13.4", "@scalar/types": "0.2.3", "@types/har-format": "^1.2.15", "flatted": "^3.3.1", "microdiff": "^1.4.0", "nanoid": "^5.1.5", "type-fest": "^4.20.0", "yaml": "^2.4.5", "zod": "3.24.1" } }, "sha512-Vp8iZZCjNKXcPpL0Yr6dmy+VOSN1LZ5CdlGAHtp+pxuQTeahV6FxiVjMc9kdFve77fTNyut4seVAD6d7rDUDcA=="],
|
||||||
|
|
||||||
"@scalar/components/@scalar/themes": ["@scalar/themes@0.13.4", "", { "dependencies": { "@scalar/types": "0.2.3", "nanoid": "^5.1.5" } }, "sha512-PMiSqX+MZF29u32ogEjTVA5c/LBd5cE/QPF7lK0EJeemXRy2r/nWbvrXtqD9Y7Sw54g1caVNjK8yJcCYJdB6hw=="],
|
"@scalar/components/@scalar/themes": ["@scalar/themes@0.13.4", "", { "dependencies": { "@scalar/types": "0.2.3", "nanoid": "^5.1.5" } }, "sha512-PMiSqX+MZF29u32ogEjTVA5c/LBd5cE/QPF7lK0EJeemXRy2r/nWbvrXtqD9Y7Sw54g1caVNjK8yJcCYJdB6hw=="],
|
||||||
@@ -3983,7 +3990,7 @@
|
|||||||
|
|
||||||
"@scalar/themes/@scalar/types": ["@scalar/types@0.1.7", "", { "dependencies": { "@scalar/openapi-types": "0.2.0", "@unhead/schema": "^1.11.11", "nanoid": "^5.1.5", "type-fest": "^4.20.0", "zod": "^3.23.8" } }, "sha512-irIDYzTQG2KLvFbuTI8k2Pz/R4JR+zUUSykVTbEMatkzMmVFnn1VzNSMlODbadycwZunbnL2tA27AXed9URVjw=="],
|
"@scalar/themes/@scalar/types": ["@scalar/types@0.1.7", "", { "dependencies": { "@scalar/openapi-types": "0.2.0", "@unhead/schema": "^1.11.11", "nanoid": "^5.1.5", "type-fest": "^4.20.0", "zod": "^3.23.8" } }, "sha512-irIDYzTQG2KLvFbuTI8k2Pz/R4JR+zUUSykVTbEMatkzMmVFnn1VzNSMlODbadycwZunbnL2tA27AXed9URVjw=="],
|
||||||
|
|
||||||
"@scalar/types/@scalar/openapi-types": ["@scalar/openapi-types@0.3.3", "", { "dependencies": { "zod": "3.24.1" } }, "sha512-mr3OvbCyvuzSDgv9gR9D3pJAsl82BRNBp1P8ldgRgKF4Wiswfa7nQeKibpX0kHSGXLgiyvxWJULUFwgdWMXNNA=="],
|
"@scalar/types/@scalar/openapi-types": ["@scalar/openapi-types@0.2.3", "", { "dependencies": { "zod": "3.24.1" } }, "sha512-O1GwqLpcRc3GKXTbeBZ5E12fXR2ltpqGWk4RfhoN4ebKZsPVknV5at5425G97E1SwMy12BporRvn90k1Z+MruQ=="],
|
||||||
|
|
||||||
"@scalar/types/zod": ["zod@3.24.1", "", {}, "sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A=="],
|
"@scalar/types/zod": ["zod@3.24.1", "", {}, "sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A=="],
|
||||||
|
|
||||||
@@ -5081,18 +5088,28 @@
|
|||||||
|
|
||||||
"@radix-ui/react-visually-hidden/@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.1.1", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-RApLLOcINYJA+dMVbOju7MYv1Mb2EBp2nH4HdDzXTSyaR5optlm6Otrz1euW3HbdOR8UmmFK06TD+A9frYWv+g=="],
|
"@radix-ui/react-visually-hidden/@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.1.1", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-RApLLOcINYJA+dMVbOju7MYv1Mb2EBp2nH4HdDzXTSyaR5optlm6Otrz1euW3HbdOR8UmmFK06TD+A9frYWv+g=="],
|
||||||
|
|
||||||
|
"@scalar/api-client-react/@scalar/types/@scalar/openapi-types": ["@scalar/openapi-types@0.3.3", "", { "dependencies": { "zod": "3.24.1" } }, "sha512-mr3OvbCyvuzSDgv9gR9D3pJAsl82BRNBp1P8ldgRgKF4Wiswfa7nQeKibpX0kHSGXLgiyvxWJULUFwgdWMXNNA=="],
|
||||||
|
|
||||||
|
"@scalar/api-client-react/@scalar/types/zod": ["zod@3.24.1", "", {}, "sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A=="],
|
||||||
|
|
||||||
"@scalar/api-client/pretty-ms/parse-ms": ["parse-ms@3.0.0", "", {}, "sha512-Tpb8Z7r7XbbtBTrM9UhpkzzaMrqA2VXMT3YChzYltwV3P3pM6t8wl7TvpMnSTosz1aQAdVib7kdoys7vYOPerw=="],
|
"@scalar/api-client/pretty-ms/parse-ms": ["parse-ms@3.0.0", "", {}, "sha512-Tpb8Z7r7XbbtBTrM9UhpkzzaMrqA2VXMT3YChzYltwV3P3pM6t8wl7TvpMnSTosz1aQAdVib7kdoys7vYOPerw=="],
|
||||||
|
|
||||||
"@scalar/components/@scalar/oas-utils/@scalar/object-utils": ["@scalar/object-utils@1.2.1", "", { "dependencies": { "flatted": "^3.3.1", "just-clone": "^6.2.0", "ts-deepmerge": "^7.0.1", "type-fest": "^4.20.0" } }, "sha512-2P/0In6XSrV1Ye8yU3LyOWJKWkzXpxf0thHmTfJriqGBZz41s06td2KKqoqHSEEi+FAsl3O1ngmOOzLM3QUkkw=="],
|
"@scalar/components/@scalar/oas-utils/@scalar/object-utils": ["@scalar/object-utils@1.2.1", "", { "dependencies": { "flatted": "^3.3.1", "just-clone": "^6.2.0", "ts-deepmerge": "^7.0.1", "type-fest": "^4.20.0" } }, "sha512-2P/0In6XSrV1Ye8yU3LyOWJKWkzXpxf0thHmTfJriqGBZz41s06td2KKqoqHSEEi+FAsl3O1ngmOOzLM3QUkkw=="],
|
||||||
|
|
||||||
"@scalar/components/@scalar/oas-utils/@scalar/openapi-types": ["@scalar/openapi-types@0.3.3", "", { "dependencies": { "zod": "3.24.1" } }, "sha512-mr3OvbCyvuzSDgv9gR9D3pJAsl82BRNBp1P8ldgRgKF4Wiswfa7nQeKibpX0kHSGXLgiyvxWJULUFwgdWMXNNA=="],
|
"@scalar/components/@scalar/oas-utils/@scalar/openapi-types": ["@scalar/openapi-types@0.3.3", "", { "dependencies": { "zod": "3.24.1" } }, "sha512-mr3OvbCyvuzSDgv9gR9D3pJAsl82BRNBp1P8ldgRgKF4Wiswfa7nQeKibpX0kHSGXLgiyvxWJULUFwgdWMXNNA=="],
|
||||||
|
|
||||||
|
"@scalar/components/@scalar/oas-utils/@scalar/types": ["@scalar/types@0.2.3", "", { "dependencies": { "@scalar/openapi-types": "0.3.3", "nanoid": "^5.1.5", "zod": "3.24.1" } }, "sha512-K1/Vp5xaQ8TEGDYwHg88OBuQWJRWrE3ToZ0Z2LJwskcY1Eg+uDiRQXKF4QPngZzu5rrWgRErAq4yte4Y7omqgA=="],
|
||||||
|
|
||||||
"@scalar/components/@scalar/oas-utils/zod": ["zod@3.24.1", "", {}, "sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A=="],
|
"@scalar/components/@scalar/oas-utils/zod": ["zod@3.24.1", "", {}, "sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A=="],
|
||||||
|
|
||||||
|
"@scalar/components/@scalar/themes/@scalar/types": ["@scalar/types@0.2.3", "", { "dependencies": { "@scalar/openapi-types": "0.3.3", "nanoid": "^5.1.5", "zod": "3.24.1" } }, "sha512-K1/Vp5xaQ8TEGDYwHg88OBuQWJRWrE3ToZ0Z2LJwskcY1Eg+uDiRQXKF4QPngZzu5rrWgRErAq4yte4Y7omqgA=="],
|
||||||
|
|
||||||
"@scalar/postman-to-openapi/@scalar/oas-utils/@scalar/object-utils": ["@scalar/object-utils@1.2.1", "", { "dependencies": { "flatted": "^3.3.1", "just-clone": "^6.2.0", "ts-deepmerge": "^7.0.1", "type-fest": "^4.20.0" } }, "sha512-2P/0In6XSrV1Ye8yU3LyOWJKWkzXpxf0thHmTfJriqGBZz41s06td2KKqoqHSEEi+FAsl3O1ngmOOzLM3QUkkw=="],
|
"@scalar/postman-to-openapi/@scalar/oas-utils/@scalar/object-utils": ["@scalar/object-utils@1.2.1", "", { "dependencies": { "flatted": "^3.3.1", "just-clone": "^6.2.0", "ts-deepmerge": "^7.0.1", "type-fest": "^4.20.0" } }, "sha512-2P/0In6XSrV1Ye8yU3LyOWJKWkzXpxf0thHmTfJriqGBZz41s06td2KKqoqHSEEi+FAsl3O1ngmOOzLM3QUkkw=="],
|
||||||
|
|
||||||
"@scalar/postman-to-openapi/@scalar/oas-utils/@scalar/themes": ["@scalar/themes@0.13.4", "", { "dependencies": { "@scalar/types": "0.2.3", "nanoid": "^5.1.5" } }, "sha512-PMiSqX+MZF29u32ogEjTVA5c/LBd5cE/QPF7lK0EJeemXRy2r/nWbvrXtqD9Y7Sw54g1caVNjK8yJcCYJdB6hw=="],
|
"@scalar/postman-to-openapi/@scalar/oas-utils/@scalar/themes": ["@scalar/themes@0.13.4", "", { "dependencies": { "@scalar/types": "0.2.3", "nanoid": "^5.1.5" } }, "sha512-PMiSqX+MZF29u32ogEjTVA5c/LBd5cE/QPF7lK0EJeemXRy2r/nWbvrXtqD9Y7Sw54g1caVNjK8yJcCYJdB6hw=="],
|
||||||
|
|
||||||
|
"@scalar/postman-to-openapi/@scalar/oas-utils/@scalar/types": ["@scalar/types@0.2.3", "", { "dependencies": { "@scalar/openapi-types": "0.3.3", "nanoid": "^5.1.5", "zod": "3.24.1" } }, "sha512-K1/Vp5xaQ8TEGDYwHg88OBuQWJRWrE3ToZ0Z2LJwskcY1Eg+uDiRQXKF4QPngZzu5rrWgRErAq4yte4Y7omqgA=="],
|
||||||
|
|
||||||
"@scalar/postman-to-openapi/@scalar/oas-utils/zod": ["zod@3.24.1", "", {}, "sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A=="],
|
"@scalar/postman-to-openapi/@scalar/oas-utils/zod": ["zod@3.24.1", "", {}, "sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A=="],
|
||||||
|
|
||||||
"@scalar/postman-to-openapi/@scalar/openapi-types/zod": ["zod@3.24.1", "", {}, "sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A=="],
|
"@scalar/postman-to-openapi/@scalar/openapi-types/zod": ["zod@3.24.1", "", {}, "sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A=="],
|
||||||
@@ -5439,6 +5456,10 @@
|
|||||||
|
|
||||||
"@radix-ui/react-visually-hidden/@radix-ui/react-primitive/@radix-ui/react-slot/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw=="],
|
"@radix-ui/react-visually-hidden/@radix-ui/react-primitive/@radix-ui/react-slot/@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw=="],
|
||||||
|
|
||||||
|
"@scalar/components/@scalar/themes/@scalar/types/@scalar/openapi-types": ["@scalar/openapi-types@0.3.3", "", { "dependencies": { "zod": "3.24.1" } }, "sha512-mr3OvbCyvuzSDgv9gR9D3pJAsl82BRNBp1P8ldgRgKF4Wiswfa7nQeKibpX0kHSGXLgiyvxWJULUFwgdWMXNNA=="],
|
||||||
|
|
||||||
|
"@scalar/components/@scalar/themes/@scalar/types/zod": ["zod@3.24.1", "", {}, "sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A=="],
|
||||||
|
|
||||||
"@smithy/core/@smithy/util-stream/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "@smithy/util-uri-escape": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-wU87iWZoCbcqrwszsOewEIuq+SU2mSoBE2CcsLwE0I19m0B2gOJr1MVjxWcDQYOzHbR1xCk7AcOBbGFUYOKvdg=="],
|
"@smithy/core/@smithy/util-stream/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "@smithy/util-uri-escape": "^4.0.0", "tslib": "^2.6.2" } }, "sha512-wU87iWZoCbcqrwszsOewEIuq+SU2mSoBE2CcsLwE0I19m0B2gOJr1MVjxWcDQYOzHbR1xCk7AcOBbGFUYOKvdg=="],
|
||||||
|
|
||||||
"@smithy/core/@smithy/util-stream/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-fiUIYgIgRjMWznk6iLJz35K2YxSLHzLBA/RC6lBrKfQ8fHbPfvk7Pk9UvpKoHgJjI18MnbPuEju53zcVy6KF1g=="],
|
"@smithy/core/@smithy/util-stream/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.0.1", "", { "dependencies": { "@smithy/types": "^4.1.0", "tslib": "^2.6.2" } }, "sha512-fiUIYgIgRjMWznk6iLJz35K2YxSLHzLBA/RC6lBrKfQ8fHbPfvk7Pk9UvpKoHgJjI18MnbPuEju53zcVy6KF1g=="],
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
"@gitbook/browser-types": "workspace:*",
|
"@gitbook/browser-types": "workspace:*",
|
||||||
"@gitbook/cache-tags": "workspace:*",
|
"@gitbook/cache-tags": "workspace:*",
|
||||||
"@gitbook/colors": "workspace:*",
|
"@gitbook/colors": "workspace:*",
|
||||||
|
"@gitbook/expr": "workspace:*",
|
||||||
"@gitbook/emoji-codepoints": "workspace:*",
|
"@gitbook/emoji-codepoints": "workspace:*",
|
||||||
"@gitbook/fonts": "workspace:*",
|
"@gitbook/fonts": "workspace:*",
|
||||||
"@gitbook/icons": "workspace:*",
|
"@gitbook/icons": "workspace:*",
|
||||||
|
|||||||
@@ -0,0 +1,103 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import type { GitBookSiteContext } from '@/lib/context';
|
||||||
|
import { OpenAPIPrefillContextProvider } from '@gitbook/react-openapi';
|
||||||
|
import * as React from 'react';
|
||||||
|
import { createContext, useContext } from 'react';
|
||||||
|
|
||||||
|
export type AdaptiveVisitorClaimsData = {
|
||||||
|
visitor: {
|
||||||
|
claims: Record<string, unknown> & { unsigned: Record<string, unknown> };
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* In-memory cache of visitor claim readers keyed by contextId.
|
||||||
|
*/
|
||||||
|
const adaptiveVisitorReaderCache = new Map<
|
||||||
|
string,
|
||||||
|
ReturnType<typeof createResourceReader<AdaptiveVisitorClaimsData | null>>
|
||||||
|
>();
|
||||||
|
|
||||||
|
function createResourceReader<T>(promise: Promise<T>) {
|
||||||
|
let result: T | null | undefined;
|
||||||
|
|
||||||
|
const suspender = (async () => {
|
||||||
|
try {
|
||||||
|
result = await promise;
|
||||||
|
} catch {
|
||||||
|
result = null;
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
|
||||||
|
return {
|
||||||
|
read() {
|
||||||
|
if (result === undefined) {
|
||||||
|
throw suspender;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return an adaptive visitor claims cached reader for a given endpoint URL and contextId.
|
||||||
|
*/
|
||||||
|
function getAdaptiveVisitorClaimsReader(url: string, contextId: string) {
|
||||||
|
let reader = adaptiveVisitorReaderCache.get(contextId);
|
||||||
|
if (!reader) {
|
||||||
|
const promise = (async () => {
|
||||||
|
try {
|
||||||
|
const res = await fetch(url);
|
||||||
|
if (!res.ok) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return await res.json<AdaptiveVisitorClaimsData>();
|
||||||
|
} catch {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
|
||||||
|
reader = createResourceReader(promise);
|
||||||
|
adaptiveVisitorReaderCache.set(contextId, reader);
|
||||||
|
}
|
||||||
|
return reader;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type AdaptiveVisitorContextValue = () => AdaptiveVisitorClaimsData | null;
|
||||||
|
|
||||||
|
const AdaptiveVisitorContext = createContext<AdaptiveVisitorContextValue>(() => null);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provide context to adapt site based on visitor claims.
|
||||||
|
*/
|
||||||
|
export function AdaptiveVisitorContextProvider(
|
||||||
|
props: React.PropsWithChildren<{
|
||||||
|
visitorClaimsURL: string;
|
||||||
|
contextId: GitBookSiteContext['contextId'] | undefined;
|
||||||
|
}>
|
||||||
|
) {
|
||||||
|
const { visitorClaimsURL, contextId, children } = props;
|
||||||
|
|
||||||
|
const getAdaptiveVisitorClaims = React.useCallback(() => {
|
||||||
|
if (!contextId) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return getAdaptiveVisitorClaimsReader(visitorClaimsURL, contextId).read();
|
||||||
|
}, [visitorClaimsURL, contextId]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AdaptiveVisitorContext.Provider value={getAdaptiveVisitorClaims}>
|
||||||
|
<OpenAPIPrefillContextProvider getPrefillInputContextData={getAdaptiveVisitorClaims}>
|
||||||
|
{children}
|
||||||
|
</OpenAPIPrefillContextProvider>
|
||||||
|
</AdaptiveVisitorContext.Provider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hook that returns a suspensable getter for adaptive visitor claims data.
|
||||||
|
*/
|
||||||
|
export function useAdaptiveVisitor(): AdaptiveVisitorContextValue {
|
||||||
|
return useContext(AdaptiveVisitorContext);
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export * from './AdaptiveVisitorContextProvider';
|
||||||
@@ -17,6 +17,7 @@ import { GITBOOK_APP_URL } from '@/lib/env';
|
|||||||
import { AIChatProvider } from '../AI';
|
import { AIChatProvider } from '../AI';
|
||||||
import type { RenderAIMessageOptions } from '../AI';
|
import type { RenderAIMessageOptions } from '../AI';
|
||||||
import { AIChat } from '../AIChat';
|
import { AIChat } from '../AIChat';
|
||||||
|
import { AdaptiveVisitorContextProvider } from '../Adaptive';
|
||||||
import { Announcement } from '../Announcement';
|
import { Announcement } from '../Announcement';
|
||||||
import { SpacesDropdown } from '../Header/SpacesDropdown';
|
import { SpacesDropdown } from '../Header/SpacesDropdown';
|
||||||
import { InsightsProvider } from '../Insights';
|
import { InsightsProvider } from '../Insights';
|
||||||
@@ -56,29 +57,38 @@ export function SpaceLayoutServerContext(props: SpaceLayoutProps) {
|
|||||||
eventUrl.searchParams.set('o', context.organizationId);
|
eventUrl.searchParams.set('o', context.organizationId);
|
||||||
eventUrl.searchParams.set('s', context.site.id);
|
eventUrl.searchParams.set('s', context.site.id);
|
||||||
|
|
||||||
|
const getVisitorClaimsUrl = context.linker.toAbsoluteURL(
|
||||||
|
context.linker.toPathInSite('/~gitbook/visitor')
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SpaceLayoutContextProvider basePath={context.linker.toPathInSpace('')}>
|
<SpaceLayoutContextProvider basePath={context.linker.toPathInSpace('')}>
|
||||||
<CurrentContentProvider
|
<AdaptiveVisitorContextProvider
|
||||||
organizationId={context.organizationId}
|
contextId={context.contextId}
|
||||||
siteId={context.site.id}
|
visitorClaimsURL={getVisitorClaimsUrl}
|
||||||
siteSectionId={context.sections?.current?.id ?? null}
|
|
||||||
siteSpaceId={context.siteSpace.id}
|
|
||||||
siteShareKey={context.shareKey ?? null}
|
|
||||||
spaceId={context.space.id}
|
|
||||||
revisionId={context.revisionId}
|
|
||||||
visitorAuthClaims={visitorAuthClaims}
|
|
||||||
>
|
>
|
||||||
<InsightsProvider
|
<CurrentContentProvider
|
||||||
enabled={withTracking}
|
organizationId={context.organizationId}
|
||||||
appURL={GITBOOK_APP_URL}
|
siteId={context.site.id}
|
||||||
eventUrl={eventUrl.toString()}
|
siteSectionId={context.sections?.current?.id ?? null}
|
||||||
visitorCookieTrackingEnabled={customization.insights?.trackingCookie}
|
siteSpaceId={context.siteSpace.id}
|
||||||
|
siteShareKey={context.shareKey ?? null}
|
||||||
|
spaceId={context.space.id}
|
||||||
|
revisionId={context.revisionId}
|
||||||
|
visitorAuthClaims={visitorAuthClaims}
|
||||||
>
|
>
|
||||||
<AIChatProvider renderMessageOptions={aiChatRenderMessageOptions}>
|
<InsightsProvider
|
||||||
{children}
|
enabled={withTracking}
|
||||||
</AIChatProvider>
|
appURL={GITBOOK_APP_URL}
|
||||||
</InsightsProvider>
|
eventUrl={eventUrl.toString()}
|
||||||
</CurrentContentProvider>
|
visitorCookieTrackingEnabled={customization.insights?.trackingCookie}
|
||||||
|
>
|
||||||
|
<AIChatProvider renderMessageOptions={aiChatRenderMessageOptions}>
|
||||||
|
{children}
|
||||||
|
</AIChatProvider>
|
||||||
|
</InsightsProvider>
|
||||||
|
</CurrentContentProvider>
|
||||||
|
</AdaptiveVisitorContextProvider>
|
||||||
</SpaceLayoutContextProvider>
|
</SpaceLayoutContextProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { type JwtPayload, jwtDecode } from 'jwt-decode';
|
import { type JwtPayload, jwtDecode } from 'jwt-decode';
|
||||||
import type { NextRequest } from 'next/server';
|
import { type NextRequest, NextResponse } from 'next/server';
|
||||||
import hash from 'object-hash';
|
import hash from 'object-hash';
|
||||||
|
|
||||||
const VISITOR_AUTH_PARAM = 'jwt_token';
|
const VISITOR_AUTH_PARAM = 'jwt_token';
|
||||||
@@ -443,3 +443,45 @@ export function getVisitorAuthCookieMaxAge(decoded: JwtPayload): number {
|
|||||||
|
|
||||||
return defaultMaxAge;
|
return defaultMaxAge;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler for the /~gitbook/visitor middleware route to expose visitor data.
|
||||||
|
*/
|
||||||
|
export function serveVisitorClaimsDataRequest(request: NextRequest, siteRequestURL: URL) {
|
||||||
|
const { visitorToken, unsignedClaims } = getVisitorData({
|
||||||
|
cookies: request.cookies.getAll(),
|
||||||
|
url: siteRequestURL,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!visitorToken && !Object.keys(unsignedClaims).length) {
|
||||||
|
return NextResponse.json({});
|
||||||
|
}
|
||||||
|
|
||||||
|
const visitorClaims = {
|
||||||
|
visitor: {
|
||||||
|
claims: {
|
||||||
|
unsigned: unsignedClaims,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!visitorToken) {
|
||||||
|
return NextResponse.json(visitorClaims);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const decodedJwtPayload = jwtDecode(visitorToken.token);
|
||||||
|
return NextResponse.json({
|
||||||
|
visitor: {
|
||||||
|
claims: {
|
||||||
|
...visitorClaims.visitor.claims,
|
||||||
|
...decodedJwtPayload,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.warn('Error decoding visitor token', error);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NextResponse.json(visitorClaims);
|
||||||
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import {
|
|||||||
getResponseCookiesForVisitorAuth,
|
getResponseCookiesForVisitorAuth,
|
||||||
getVisitorData,
|
getVisitorData,
|
||||||
normalizeVisitorURL,
|
normalizeVisitorURL,
|
||||||
|
serveVisitorClaimsDataRequest,
|
||||||
} from '@/lib/visitors';
|
} from '@/lib/visitors';
|
||||||
import { serveResizedImage } from '@/routes/image';
|
import { serveResizedImage } from '@/routes/image';
|
||||||
import { cookies } from 'next/headers';
|
import { cookies } from 'next/headers';
|
||||||
@@ -126,7 +127,6 @@ async function serveSiteRoutes(requestURL: URL, request: NextRequest) {
|
|||||||
|
|
||||||
const { url: siteRequestURL, mode } = match;
|
const { url: siteRequestURL, mode } = match;
|
||||||
const imagesContextId = getImageResizingContextId(siteRequestURL);
|
const imagesContextId = getImageResizingContextId(siteRequestURL);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Serve image resizing requests (all requests containing `/~gitbook/image`).
|
* Serve image resizing requests (all requests containing `/~gitbook/image`).
|
||||||
* All URLs containing `/~gitbook/image` are rewritten to `/~gitbook/image`
|
* All URLs containing `/~gitbook/image` are rewritten to `/~gitbook/image`
|
||||||
@@ -154,6 +154,11 @@ async function serveSiteRoutes(requestURL: URL, request: NextRequest) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handler that returns visitor data for the app to consume.
|
||||||
|
if (siteRequestURL.pathname.endsWith('/~gitbook/visitor')) {
|
||||||
|
return serveVisitorClaimsDataRequest(request, siteRequestURL);
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Detect and extract the visitor authentication token from the request
|
// Detect and extract the visitor authentication token from the request
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -70,6 +70,13 @@ export interface OpenAPICustomOperationProperties {
|
|||||||
'x-stability'?: OpenAPIStability;
|
'x-stability'?: OpenAPIStability;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom properties that can be defined to enable prefilling for OpenAPI blocks (e.g TryIt functionality).
|
||||||
|
*/
|
||||||
|
export interface OpenAPICustomPrefillProperties {
|
||||||
|
'x-gitbook-prefill'?: string;
|
||||||
|
}
|
||||||
|
|
||||||
export type OpenAPIStability = 'experimental' | 'alpha' | 'beta';
|
export type OpenAPIStability = 'experimental' | 'alpha' | 'beta';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -11,9 +11,11 @@
|
|||||||
"version": "1.3.6",
|
"version": "1.3.6",
|
||||||
"sideEffects": false,
|
"sideEffects": false,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@gitbook/expr": "workspace:*",
|
||||||
"@gitbook/openapi-parser": "workspace:*",
|
"@gitbook/openapi-parser": "workspace:*",
|
||||||
"@scalar/api-client-react": "^1.3.16",
|
"@scalar/api-client-react": "^1.3.16",
|
||||||
"@scalar/oas-utils": "^0.2.130",
|
"@scalar/oas-utils": "^0.2.130",
|
||||||
|
"@scalar/types": "^0.1.9",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"flatted": "^3.2.9",
|
"flatted": "^3.2.9",
|
||||||
"json-xml-parse": "^1.3.0",
|
"json-xml-parse": "^1.3.0",
|
||||||
|
|||||||
@@ -194,7 +194,7 @@ function OpenAPICodeSampleFooter(props: {
|
|||||||
context: OpenAPIContext;
|
context: OpenAPIContext;
|
||||||
}) {
|
}) {
|
||||||
const { data, context, renderers } = props;
|
const { data, context, renderers } = props;
|
||||||
const { method, path } = data;
|
const { method, path, securities, servers } = data;
|
||||||
const { specUrl } = context;
|
const { specUrl } = context;
|
||||||
const hideTryItPanel = data['x-hideTryItPanel'] || data.operation['x-hideTryItPanel'];
|
const hideTryItPanel = data['x-hideTryItPanel'] || data.operation['x-hideTryItPanel'];
|
||||||
const hasMultipleMediaTypes =
|
const hasMultipleMediaTypes =
|
||||||
@@ -226,6 +226,8 @@ function OpenAPICodeSampleFooter(props: {
|
|||||||
context={getOpenAPIClientContext(context)}
|
context={getOpenAPIClientContext(context)}
|
||||||
method={method}
|
method={method}
|
||||||
path={path}
|
path={path}
|
||||||
|
securities={securities}
|
||||||
|
servers={servers}
|
||||||
specUrl={specUrl}
|
specUrl={specUrl}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import * as React from 'react';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prefill data that can be used to dynamically inject info into OpenAPI operation blocks.
|
||||||
|
*
|
||||||
|
* This is typically dynamic input context, such as visitor data or environment info.
|
||||||
|
*/
|
||||||
|
export type PrefillInputContextData = Record<string, unknown>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Context value is function that returns prefill data.
|
||||||
|
*/
|
||||||
|
type PrefillContextValue = () => PrefillInputContextData | null;
|
||||||
|
|
||||||
|
const OpenAPIPrefillContext = React.createContext<PrefillContextValue | null>(null);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provide context to help prefill dynamic info like visitor data in OpenAPI blocks.
|
||||||
|
*/
|
||||||
|
export function OpenAPIPrefillContextProvider(
|
||||||
|
props: React.PropsWithChildren<{
|
||||||
|
getPrefillInputContextData: () => PrefillInputContextData | null;
|
||||||
|
}>
|
||||||
|
) {
|
||||||
|
const { getPrefillInputContextData, children } = props;
|
||||||
|
return (
|
||||||
|
<OpenAPIPrefillContext.Provider value={getPrefillInputContextData}>
|
||||||
|
{children}
|
||||||
|
</OpenAPIPrefillContext.Provider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hook to access the prefill context function.
|
||||||
|
*/
|
||||||
|
export function useOpenAPIPrefillContext(): PrefillContextValue {
|
||||||
|
return React.useContext(OpenAPIPrefillContext) ?? (() => null);
|
||||||
|
}
|
||||||
@@ -1,13 +1,16 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { ApiClientModalProvider, useApiClientModal } from '@scalar/api-client-react';
|
import { ApiClientModalProvider, useApiClientModal } from '@scalar/api-client-react';
|
||||||
import { useEffect, useImperativeHandle, useMemo, useRef, useState } from 'react';
|
import { Suspense, useEffect, useImperativeHandle, useMemo, useRef, useState } from 'react';
|
||||||
import { createPortal } from 'react-dom';
|
import { createPortal } from 'react-dom';
|
||||||
|
|
||||||
import type { OpenAPIV3_1 } from '@gitbook/openapi-parser';
|
import type { OpenAPIV3_1 } from '@gitbook/openapi-parser';
|
||||||
import { useOpenAPIOperationContext } from './OpenAPIOperationContext';
|
import { useOpenAPIOperationContext } from './OpenAPIOperationContext';
|
||||||
|
import { useOpenAPIPrefillContext } from './OpenAPIPrefillContextProvider';
|
||||||
import type { OpenAPIClientContext } from './context';
|
import type { OpenAPIClientContext } from './context';
|
||||||
import { t } from './translate';
|
import { t } from './translate';
|
||||||
|
import type { OpenAPIOperationData } from './types';
|
||||||
|
import { resolveTryItPrefillForOperation } from './util/tryit-prefill';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Button which launches the Scalar API Client
|
* Button which launches the Scalar API Client
|
||||||
@@ -15,12 +18,15 @@ import { t } from './translate';
|
|||||||
export function ScalarApiButton(props: {
|
export function ScalarApiButton(props: {
|
||||||
method: OpenAPIV3_1.HttpMethods;
|
method: OpenAPIV3_1.HttpMethods;
|
||||||
path: string;
|
path: string;
|
||||||
|
securities: OpenAPIOperationData['securities'];
|
||||||
|
servers: OpenAPIOperationData['servers'];
|
||||||
specUrl: string;
|
specUrl: string;
|
||||||
context: OpenAPIClientContext;
|
context: OpenAPIClientContext;
|
||||||
}) {
|
}) {
|
||||||
const { method, path, specUrl, context } = props;
|
const { method, path, securities, servers, specUrl, context } = props;
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
const controllerRef = useRef<ScalarModalControllerRef>(null);
|
const controllerRef = useRef<ScalarModalControllerRef>(null);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="scalar scalar-activate">
|
<div className="scalar scalar-activate">
|
||||||
<button
|
<button
|
||||||
@@ -42,12 +48,16 @@ export function ScalarApiButton(props: {
|
|||||||
|
|
||||||
{isOpen &&
|
{isOpen &&
|
||||||
createPortal(
|
createPortal(
|
||||||
<ScalarModal
|
<Suspense fallback={null}>
|
||||||
controllerRef={controllerRef}
|
<ScalarModal
|
||||||
method={method}
|
controllerRef={controllerRef}
|
||||||
path={path}
|
method={method}
|
||||||
specUrl={specUrl}
|
path={path}
|
||||||
/>,
|
securities={securities}
|
||||||
|
servers={servers}
|
||||||
|
specUrl={specUrl}
|
||||||
|
/>
|
||||||
|
</Suspense>,
|
||||||
document.body
|
document.body
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@@ -57,12 +67,26 @@ export function ScalarApiButton(props: {
|
|||||||
function ScalarModal(props: {
|
function ScalarModal(props: {
|
||||||
method: OpenAPIV3_1.HttpMethods;
|
method: OpenAPIV3_1.HttpMethods;
|
||||||
path: string;
|
path: string;
|
||||||
|
securities: OpenAPIOperationData['securities'];
|
||||||
|
servers: OpenAPIOperationData['servers'];
|
||||||
specUrl: string;
|
specUrl: string;
|
||||||
controllerRef: React.Ref<ScalarModalControllerRef>;
|
controllerRef: React.Ref<ScalarModalControllerRef>;
|
||||||
}) {
|
}) {
|
||||||
const { method, path, specUrl, controllerRef } = props;
|
const { method, path, securities, servers, specUrl, controllerRef } = props;
|
||||||
|
|
||||||
|
const getPrefillInputContextData = useOpenAPIPrefillContext();
|
||||||
|
const prefillInputContext = getPrefillInputContextData();
|
||||||
|
|
||||||
|
const prefillConfig = resolveTryItPrefillForOperation({
|
||||||
|
operation: { securities, servers },
|
||||||
|
prefillInputContext,
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ApiClientModalProvider configuration={{ url: specUrl }} initialRequest={{ method, path }}>
|
<ApiClientModalProvider
|
||||||
|
configuration={{ url: specUrl, ...prefillConfig }}
|
||||||
|
initialRequest={{ method, path }}
|
||||||
|
>
|
||||||
<ScalarModalController method={method} path={path} controllerRef={controllerRef} />
|
<ScalarModalController method={method} path={path} controllerRef={controllerRef} />
|
||||||
</ApiClientModalProvider>
|
</ApiClientModalProvider>
|
||||||
);
|
);
|
||||||
@@ -84,7 +108,11 @@ function ScalarModalController(props: {
|
|||||||
const openClient = useMemo(() => {
|
const openClient = useMemo(() => {
|
||||||
if (openScalarClient) {
|
if (openScalarClient) {
|
||||||
return () => {
|
return () => {
|
||||||
openScalarClient({ method, path, _source: 'gitbook' });
|
openScalarClient({
|
||||||
|
method,
|
||||||
|
path,
|
||||||
|
_source: 'gitbook',
|
||||||
|
});
|
||||||
trackClientOpening({ method, path });
|
trackClientOpening({ method, path });
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ export * from './schemas';
|
|||||||
export * from './OpenAPIOperation';
|
export * from './OpenAPIOperation';
|
||||||
export * from './OpenAPIWebhook';
|
export * from './OpenAPIWebhook';
|
||||||
export * from './OpenAPIOperationContext';
|
export * from './OpenAPIOperationContext';
|
||||||
|
export * from './OpenAPIPrefillContextProvider';
|
||||||
export * from './resolveOpenAPIOperation';
|
export * from './resolveOpenAPIOperation';
|
||||||
export * from './resolveOpenAPIWebhook';
|
export * from './resolveOpenAPIWebhook';
|
||||||
export type { OpenAPIOperationData, OpenAPIWebhookData } from './types';
|
export type { OpenAPIOperationData, OpenAPIWebhookData } from './types';
|
||||||
|
|||||||
@@ -1,17 +1,31 @@
|
|||||||
import type {
|
import type {
|
||||||
OpenAPICustomOperationProperties,
|
OpenAPICustomOperationProperties,
|
||||||
|
OpenAPICustomPrefillProperties,
|
||||||
OpenAPICustomSpecProperties,
|
OpenAPICustomSpecProperties,
|
||||||
OpenAPIV3,
|
OpenAPIV3,
|
||||||
} from '@gitbook/openapi-parser';
|
} from '@gitbook/openapi-parser';
|
||||||
|
|
||||||
export type OpenAPISecurityWithRequired = OpenAPIV3.SecuritySchemeObject & { required?: boolean };
|
export type OpenAPIServerVariableWithCustomProperties = OpenAPIV3.ServerVariableObject &
|
||||||
|
OpenAPICustomPrefillProperties;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* OpenAPI ServerObject type extended to provide x-gitbook prefill custom properties at the variable level.
|
||||||
|
*/
|
||||||
|
export type OpenAPIServerWithCustomProperties = Omit<OpenAPIV3.ServerObject, 'variables'> & {
|
||||||
|
variables?: {
|
||||||
|
[variable: string]: OpenAPIServerVariableWithCustomProperties;
|
||||||
|
};
|
||||||
|
} & OpenAPICustomPrefillProperties;
|
||||||
|
|
||||||
|
export type OpenAPISecurityWithRequired = OpenAPIV3.SecuritySchemeObject &
|
||||||
|
OpenAPICustomPrefillProperties & { required?: boolean };
|
||||||
|
|
||||||
export interface OpenAPIOperationData extends OpenAPICustomSpecProperties {
|
export interface OpenAPIOperationData extends OpenAPICustomSpecProperties {
|
||||||
path: string;
|
path: string;
|
||||||
method: string;
|
method: string;
|
||||||
|
|
||||||
/** Servers to be used for this operation */
|
/** Servers to be used for this operation */
|
||||||
servers: OpenAPIV3.ServerObject[];
|
servers: OpenAPIServerWithCustomProperties[];
|
||||||
|
|
||||||
/** Spec of the operation */
|
/** Spec of the operation */
|
||||||
operation: OpenAPIV3.OperationObject<OpenAPICustomOperationProperties>;
|
operation: OpenAPIV3.OperationObject<OpenAPICustomOperationProperties>;
|
||||||
|
|||||||
@@ -0,0 +1,311 @@
|
|||||||
|
import { describe, expect, it } from 'bun:test';
|
||||||
|
import type { PrefillInputContextData } from '../OpenAPIPrefillContextProvider';
|
||||||
|
import type { OpenAPIOperationData } from '../types';
|
||||||
|
import { resolveTryItPrefillForOperation } from './tryit-prefill';
|
||||||
|
|
||||||
|
describe('resolveTryItPrefillForOperation', () => {
|
||||||
|
describe('prefill authentication info', () => {
|
||||||
|
it('should resolve prefill for bearer token scheme', () => {
|
||||||
|
const operation: OpenAPIOperationData = {
|
||||||
|
path: '/orgs/<orgId>/spaces/<spaceId>',
|
||||||
|
method: 'GET',
|
||||||
|
operation: { summary: 'Get space by ID' },
|
||||||
|
servers: [{ url: 'https://api.gitbook.com/v1/' }],
|
||||||
|
securities: [
|
||||||
|
[
|
||||||
|
'apiTokenScheme',
|
||||||
|
{
|
||||||
|
type: 'http',
|
||||||
|
scheme: 'bearer',
|
||||||
|
'x-gitbook-prefill': '{{ visitor.claims.apiToken }}',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
const prefillInputContext: PrefillInputContextData = {
|
||||||
|
visitor: { claims: { apiToken: 'gb_api_testToken' } },
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = resolveTryItPrefillForOperation({
|
||||||
|
operation,
|
||||||
|
prefillInputContext,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(result).toEqual({
|
||||||
|
authentication: {
|
||||||
|
securitySchemes: {
|
||||||
|
apiTokenScheme: { token: 'gb_api_testToken' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should resolve prefill for basic auth scheme', () => {
|
||||||
|
const operation: OpenAPIOperationData = {
|
||||||
|
path: '/orgs/<orgId>/spaces',
|
||||||
|
method: 'PUT',
|
||||||
|
operation: { summary: 'Create space in an org' },
|
||||||
|
servers: [{ url: 'https://api.gitbook.com/v1/' }],
|
||||||
|
securities: [
|
||||||
|
[
|
||||||
|
'basicAuthScheme',
|
||||||
|
{
|
||||||
|
type: 'http',
|
||||||
|
scheme: 'basic',
|
||||||
|
'x-gitbook-prefill': '{{ visitor.claims.basicAuth }}',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
const prefillInputContext: PrefillInputContextData = {
|
||||||
|
visitor: { claims: { basicAuth: 'testuser:testpassword' } },
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = resolveTryItPrefillForOperation({
|
||||||
|
operation,
|
||||||
|
prefillInputContext,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(result).toEqual({
|
||||||
|
authentication: {
|
||||||
|
securitySchemes: {
|
||||||
|
basicAuthScheme: { username: 'testuser', password: 'testpassword' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should resolve prefill for apiKey scheme', () => {
|
||||||
|
const operation: OpenAPIOperationData = {
|
||||||
|
path: '/orgs/<orgId>/spaces/<spaceId>',
|
||||||
|
method: 'POST',
|
||||||
|
operation: { summary: 'Update space by ID' },
|
||||||
|
servers: [{ url: 'https://api.gitbook.com/v1/' }],
|
||||||
|
securities: [
|
||||||
|
[
|
||||||
|
'apiKeyHeader',
|
||||||
|
{
|
||||||
|
type: 'apiKey',
|
||||||
|
in: 'header',
|
||||||
|
name: 'X-API-KEY',
|
||||||
|
'x-gitbook-prefill': '{{ visitor.claims.apiKey }}',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
const prefillInputContext: PrefillInputContextData = {
|
||||||
|
visitor: { claims: { apiKey: 'key-123' } },
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = resolveTryItPrefillForOperation({
|
||||||
|
operation,
|
||||||
|
prefillInputContext,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(result).toEqual({
|
||||||
|
authentication: {
|
||||||
|
securitySchemes: {
|
||||||
|
apiKeyHeader: { name: 'X-API-KEY', in: 'header', value: 'key-123' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return empty object if no visitor data matches prefill expression', () => {
|
||||||
|
const operation: OpenAPIOperationData = {
|
||||||
|
path: '/orgs/<orgId>/spaces',
|
||||||
|
method: 'GET',
|
||||||
|
operation: { summary: 'List all spaces in an org' },
|
||||||
|
servers: [{ url: 'https://api.gitbook.com/v1/' }],
|
||||||
|
securities: [
|
||||||
|
[
|
||||||
|
'bearer',
|
||||||
|
{
|
||||||
|
type: 'http',
|
||||||
|
scheme: 'bearer',
|
||||||
|
'x-gitbook-prefill': '{{ visitor.claims.missing }}',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
const prefillInputContext: PrefillInputContextData = {
|
||||||
|
visitor: { claims: {} },
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = resolveTryItPrefillForOperation({
|
||||||
|
operation,
|
||||||
|
prefillInputContext,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(result).toEqual({});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('prefill server info', () => {
|
||||||
|
it('should prefill server at url level', () => {
|
||||||
|
const operation: OpenAPIOperationData = {
|
||||||
|
path: '/orgs/<orgId>/spaces',
|
||||||
|
method: 'GET',
|
||||||
|
operation: { summary: 'List spaces in an org' },
|
||||||
|
servers: [
|
||||||
|
{
|
||||||
|
url: 'https://api.gitbook.com/v1/',
|
||||||
|
description: 'GitBook API endpoint',
|
||||||
|
'x-gitbook-prefill': '{{ visitor.claims.api.endpointUrl }}',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
securities: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
const prefillInputContext: PrefillInputContextData = {
|
||||||
|
visitor: {
|
||||||
|
claims: { api: { endpointUrl: 'https://api.gitbook-staging.com/v1/' } },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = resolveTryItPrefillForOperation({
|
||||||
|
operation,
|
||||||
|
prefillInputContext,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(result).toEqual({
|
||||||
|
servers: [
|
||||||
|
{
|
||||||
|
url: 'https://api.gitbook-staging.com/v1/',
|
||||||
|
description: 'GitBook API endpoint',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should prefill server at variables level', () => {
|
||||||
|
const operation: OpenAPIOperationData = {
|
||||||
|
path: '/orgs/<orgId>/spaces',
|
||||||
|
method: 'GET',
|
||||||
|
operation: { summary: 'List spaces in an org' },
|
||||||
|
servers: [
|
||||||
|
{
|
||||||
|
url: 'https://api.{domain}/{version}/',
|
||||||
|
description: 'Versioned API endpoint by environment',
|
||||||
|
variables: {
|
||||||
|
domain: {
|
||||||
|
default: 'gitbook.com',
|
||||||
|
'x-gitbook-prefill':
|
||||||
|
'{{ visitor.claims.api.env === "staging" ? "gitbook-staging.com" : "gitbook.com" }}',
|
||||||
|
},
|
||||||
|
version: {
|
||||||
|
default: 'v1',
|
||||||
|
'x-gitbook-prefill': '{{ visitor.claims.api.version }}',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
securities: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
// Override env
|
||||||
|
const overrideEnvResult = resolveTryItPrefillForOperation({
|
||||||
|
operation,
|
||||||
|
prefillInputContext: { visitor: { claims: { api: { env: 'staging' } } } },
|
||||||
|
});
|
||||||
|
expect(overrideEnvResult).toEqual({
|
||||||
|
servers: [
|
||||||
|
{
|
||||||
|
url: 'https://api.{domain}/{version}/',
|
||||||
|
description: 'Versioned API endpoint by environment',
|
||||||
|
variables: {
|
||||||
|
domain: { default: 'gitbook-staging.com' },
|
||||||
|
version: { default: 'v1' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
// Override version
|
||||||
|
const overrideVersionResult = resolveTryItPrefillForOperation({
|
||||||
|
operation,
|
||||||
|
prefillInputContext: { visitor: { claims: { api: { version: 'v2' } } } },
|
||||||
|
});
|
||||||
|
expect(overrideVersionResult).toEqual({
|
||||||
|
servers: [
|
||||||
|
{
|
||||||
|
url: 'https://api.{domain}/{version}/',
|
||||||
|
description: 'Versioned API endpoint by environment',
|
||||||
|
variables: {
|
||||||
|
domain: { default: 'gitbook.com' },
|
||||||
|
version: { default: 'v2' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
// Override both
|
||||||
|
const overrideBoth = resolveTryItPrefillForOperation({
|
||||||
|
operation,
|
||||||
|
prefillInputContext: {
|
||||||
|
visitor: { claims: { api: { env: 'staging', version: 'v2' } } },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
expect(overrideBoth).toEqual({
|
||||||
|
servers: [
|
||||||
|
{
|
||||||
|
url: 'https://api.{domain}/{version}/',
|
||||||
|
description: 'Versioned API endpoint by environment',
|
||||||
|
variables: {
|
||||||
|
domain: { default: 'gitbook-staging.com' },
|
||||||
|
version: { default: 'v2' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should ignore server prefill when no matching visitor data', () => {
|
||||||
|
const operation: OpenAPIOperationData = {
|
||||||
|
path: '/orgs/<orgId>/spaces',
|
||||||
|
method: 'GET',
|
||||||
|
operation: { summary: 'List spaces in an org' },
|
||||||
|
servers: [
|
||||||
|
{
|
||||||
|
url: 'https://api.{domain}/{version}/',
|
||||||
|
description: 'Versioned API endpoint by environment',
|
||||||
|
variables: {
|
||||||
|
domain: {
|
||||||
|
default: 'gitbook.com',
|
||||||
|
'x-gitbook-prefill':
|
||||||
|
'{{ visitor.claims.api.env === "staging" ? "gitbook-staging.com" : "gitbook.com" }}',
|
||||||
|
},
|
||||||
|
version: {
|
||||||
|
default: 'v1',
|
||||||
|
'x-gitbook-prefill': '{{ visitor.claims.api.version }}',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
securities: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = resolveTryItPrefillForOperation({
|
||||||
|
operation,
|
||||||
|
prefillInputContext: { visitor: { claims: { isBetaUser: true } } },
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(result).toEqual({
|
||||||
|
servers: [
|
||||||
|
{
|
||||||
|
url: 'https://api.{domain}/{version}/',
|
||||||
|
description: 'Versioned API endpoint by environment',
|
||||||
|
variables: {
|
||||||
|
domain: { default: 'gitbook.com' },
|
||||||
|
version: { default: 'v1' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,156 @@
|
|||||||
|
import { ExpressionRuntime, parseTemplate } from '@gitbook/expr';
|
||||||
|
import type { OpenAPIV3 } from '@gitbook/openapi-parser';
|
||||||
|
import type { ApiClientConfiguration } from '@scalar/types';
|
||||||
|
import type { PrefillInputContextData } from '../OpenAPIPrefillContextProvider';
|
||||||
|
import type { OpenAPIOperationData } from '../types';
|
||||||
|
|
||||||
|
export interface TryItPrefillConfiguration {
|
||||||
|
authentication?: ApiClientConfiguration['authentication'];
|
||||||
|
servers?: ApiClientConfiguration['servers'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve the Scalar API client prefill configuration for a given OpenAPI operation.
|
||||||
|
*/
|
||||||
|
export function resolveTryItPrefillForOperation(args: {
|
||||||
|
/**
|
||||||
|
* The parsed OpenAPI operation.
|
||||||
|
*/
|
||||||
|
operation: Pick<OpenAPIOperationData, 'securities' | 'servers'>;
|
||||||
|
/**
|
||||||
|
* Prefill input context data.
|
||||||
|
*/
|
||||||
|
prefillInputContext: PrefillInputContextData | null;
|
||||||
|
}): TryItPrefillConfiguration {
|
||||||
|
const {
|
||||||
|
operation: { securities, servers },
|
||||||
|
prefillInputContext,
|
||||||
|
} = args;
|
||||||
|
|
||||||
|
// Fixed ExpressionRuntime and resolveTryItPrefillExpression function
|
||||||
|
const runtime = new ExpressionRuntime();
|
||||||
|
const resolveTryItPrefillExpression = (expr: string) => {
|
||||||
|
if (!prefillInputContext) return undefined;
|
||||||
|
const parts = parseTemplate(expr);
|
||||||
|
if (!parts.length) return undefined;
|
||||||
|
return runtime.evaluateTemplate(expr, prefillInputContext);
|
||||||
|
};
|
||||||
|
|
||||||
|
const prefillAuth = securities
|
||||||
|
? resolveTryItPrefillAuthForOperationSecurities({
|
||||||
|
securities,
|
||||||
|
resolveTryItPrefillExpression,
|
||||||
|
})
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
const prefillServers = servers
|
||||||
|
? resolveTryItPrefillServersForOperationServers({ servers, resolveTryItPrefillExpression })
|
||||||
|
: [];
|
||||||
|
|
||||||
|
return {
|
||||||
|
...(prefillAuth ? { authentication: prefillAuth } : {}),
|
||||||
|
...(prefillServers ? { servers: prefillServers } : {}),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve prefill authentication configuration for the security schemes defined for an operation.
|
||||||
|
*/
|
||||||
|
function resolveTryItPrefillAuthForOperationSecurities(args: {
|
||||||
|
securities: OpenAPIOperationData['securities'];
|
||||||
|
resolveTryItPrefillExpression: (expr: string) => string | undefined;
|
||||||
|
}): ApiClientConfiguration['authentication'] | undefined {
|
||||||
|
const { securities, resolveTryItPrefillExpression } = args;
|
||||||
|
const prefillAuthConfig: ApiClientConfiguration['authentication']['securitySchemes'] = {};
|
||||||
|
|
||||||
|
for (const [schemeName, security] of Object.values(securities)) {
|
||||||
|
const tryitPrefillAuthValue = security['x-gitbook-prefill']
|
||||||
|
? resolveTryItPrefillExpression(security['x-gitbook-prefill'])
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
if (!tryitPrefillAuthValue) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (security.type) {
|
||||||
|
case 'http': {
|
||||||
|
if (security.scheme?.includes('bearer')) {
|
||||||
|
prefillAuthConfig[schemeName] = { token: tryitPrefillAuthValue };
|
||||||
|
} else if (
|
||||||
|
security.scheme?.includes('basic') &&
|
||||||
|
tryitPrefillAuthValue.includes(':')
|
||||||
|
) {
|
||||||
|
const [username, password] = tryitPrefillAuthValue.split(':', 2);
|
||||||
|
prefillAuthConfig[schemeName] = { username, password };
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'apiKey': {
|
||||||
|
prefillAuthConfig[schemeName] = {
|
||||||
|
name: security.name,
|
||||||
|
in: security.in,
|
||||||
|
value: tryitPrefillAuthValue,
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'oauth2':
|
||||||
|
case 'openIdConnect': {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Object.keys(prefillAuthConfig).length > 0
|
||||||
|
? { securitySchemes: prefillAuthConfig }
|
||||||
|
: undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve prefill server configuration for the servers defined for an operation.
|
||||||
|
*/
|
||||||
|
function resolveTryItPrefillServersForOperationServers(args: {
|
||||||
|
servers: OpenAPIOperationData['servers'];
|
||||||
|
resolveTryItPrefillExpression: (expr: string) => string | undefined;
|
||||||
|
}): ApiClientConfiguration['servers'] | undefined {
|
||||||
|
const { servers, resolveTryItPrefillExpression } = args;
|
||||||
|
const resolvedServers: ApiClientConfiguration['servers'] = [];
|
||||||
|
|
||||||
|
for (const server of servers) {
|
||||||
|
// Url-level prefill
|
||||||
|
const tryItPrefillServerUrlExpr = server['x-gitbook-prefill'];
|
||||||
|
const tryItPrefillServerUrlValue = tryItPrefillServerUrlExpr
|
||||||
|
? resolveTryItPrefillExpression(tryItPrefillServerUrlExpr)
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
const variables: { [variable: string]: OpenAPIV3.ServerVariableObject } = server.variables
|
||||||
|
? { ...server.variables }
|
||||||
|
: {};
|
||||||
|
|
||||||
|
// Variable-level prefill
|
||||||
|
if (server.variables) {
|
||||||
|
for (const [varName, variable] of Object.entries(server.variables)) {
|
||||||
|
const { 'x-gitbook-prefill': tryItPrefillVarExpr, ...variableProps } = variable;
|
||||||
|
|
||||||
|
const tryItPrefillVarValue = tryItPrefillVarExpr
|
||||||
|
? resolveTryItPrefillExpression(tryItPrefillVarExpr)
|
||||||
|
: undefined;
|
||||||
|
variables[varName] = {
|
||||||
|
...variableProps,
|
||||||
|
...(tryItPrefillVarValue ? { default: String(tryItPrefillVarValue) } : {}),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const hasServerVariables = Object.keys(variables).length > 0;
|
||||||
|
if (server.url && (tryItPrefillServerUrlValue || hasServerVariables)) {
|
||||||
|
const resolvedServer: OpenAPIV3.ServerObject = {
|
||||||
|
url: tryItPrefillServerUrlValue ?? server.url,
|
||||||
|
...(server.description ? { description: server.description } : {}),
|
||||||
|
...(hasServerVariables ? { variables } : {}),
|
||||||
|
};
|
||||||
|
resolvedServers.push(resolvedServer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return resolvedServers.length > 0 ? resolvedServers : undefined;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user